]> git.pld-linux.org Git - packages/lighttpd.git/blob - lighttpd-branch.diff
- svn 1199
[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-16 00:26:05.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,7 +437,7 @@
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 +                 strdup strerror strstr strtol sendfile  getopt socket lstat \
110                   gethostbyname poll sigtimedwait epoll_ctl getrlimit chroot \
111                   getuid select signal pathconf madvise posix_fadvise posix_madvise \
112                   writev sigaction sendfile64 send_file kqueue port_create localtime_r])
113 @@ -538,7 +535,7 @@
114  AC_OUTPUT
115  
116  
117 -do_build="mod_cgi mod_fastcgi mod_proxy mod_evhost mod_simple_vhost mod_access mod_alias mod_setenv mod_usertrack mod_auth mod_status mod_accesslog mod_rrdtool mod_secdownload mod_expire mod_compress mod_dirlisting mod_indexfiles mod_userdir mod_webdav mod_staticfile mod_scgi" 
118 +do_build="mod_cgi mod_fastcgi mod_proxy mod_evhost mod_simple_vhost mod_access mod_alias mod_setenv mod_usertrack mod_auth mod_status mod_accesslog mod_rrdtool mod_secdownload mod_expire mod_compress mod_dirlisting mod_indexfiles mod_userdir mod_webdav mod_staticfile mod_scgi mod_flv_streaming" 
119  
120  plugins="mod_rewrite mod_redirect mod_ssi mod_trigger_b4_dl"
121  features="regex-conditionals"
122 @@ -642,6 +639,14 @@
123         disable_feature="$disable_feature $features"
124  fi
125  
126 +features="webdav-locks"
127 +if test "x$UUID_LIB" \!= x; then
128 +       enable_feature="$enable_feature $features"
129 +else
130 +       disable_feature="$disable_feature $features"
131 +fi
132 +
133 +
134  ## output
135  
136  $ECHO
137 --- ../lighttpd-1.4.11/cygwin/lighttpd.README   2006-03-07 14:22:19.000000000 +0200
138 +++ lighttpd-1.4.12/cygwin/lighttpd.README      2006-07-17 22:02:18.000000000 +0300
139 @@ -1,114 +1,114 @@
140 -lighttpd\r
141 -------------------------------------------\r
142 -A fast, secure and flexible webserver\r
143 -\r
144 -Runtime requirements:\r
145 -  cygwin-1.5.10 or newer\r
146 -  crypt-1.1 or newer\r
147 -  libbz2_1-1.0.2 or newer\r
148 -  libpcre0-4.5 or newer\r
149 -  openssl-0.9.7d or newer\r
150 -  zlib-1.2.1 or newer\r
151 -\r
152 -Build requirements:\r
153 -  cygwin-1.5.10 or newer\r
154 -  gcc-3.3.1-3 or newer\r
155 -  binutils-20030901-1 or newer\r
156 -  crypt\r
157 -  openssl-devel\r
158 -  openssl\r
159 -  openldap\r
160 -  openldap-devel\r
161 -  zlib\r
162 -  bzip2\r
163 -\r
164 -Canonical homepage:\r
165 -  http://jan.kneschke.de/projects/lighttpd/\r
166 -\r
167 -Canonical download:\r
168 -  http://jan.kneschke.de/projects/lighttpd/download\r
169 -\r
170 -------------------------------------\r
171 -\r
172 -Build instructions:\r
173 -  unpack lighttpd-1.4.11-<REL>-src.tar.bz2\r
174 -    if you use setup to install this src package, it will be\r
175 -        unpacked under /usr/src automatically\r
176 -  cd /usr/src\r
177 -  ./lighttpd-1.4.11-<REL>.sh all\r
178 -\r
179 -This will create:\r
180 -  /usr/src/lighttpd-1.4.11-<REL>.tar.bz2\r
181 -  /usr/src/lighttpd-1.4.11-<REL>-src.tar.bz2\r
182 -\r
183 -Or use './lighttpd-1.4.11-<REL>.sh prep' to get a patched source directory\r
184 -\r
185 --------------------------------------------\r
186 -\r
187 -Files included in the binary distribution:\r
188 -\r
189 -  /etc/lighttpd/lighttpd.conf.default\r
190 -  /usr/lib/cyglightcomp.dll\r
191 -  /usr/lib/lighttpd/mod_access.dll\r
192 -  /usr/lib/lighttpd/mod_accesslog.dll\r
193 -  /usr/lib/lighttpd/mod_auth.dll\r
194 -  /usr/lib/lighttpd/mod_cgi.dll\r
195 -  /usr/lib/lighttpd/mod_compress.dll\r
196 -  /usr/lib/lighttpd/mod_evhost.dll\r
197 -  /usr/lib/lighttpd/mod_expire.dll\r
198 -  /usr/lib/lighttpd/mod_fastcgi.dll\r
199 -  /usr/lib/lighttpd/mod_httptls.dll\r
200 -  /usr/lib/lighttpd/mod_maps.dll\r
201 -  /usr/lib/lighttpd/mod_proxy.dll\r
202 -  /usr/lib/lighttpd/mod_redirect.dll\r
203 -  /usr/lib/lighttpd/mod_rewrite.dll\r
204 -  /usr/lib/lighttpd/mod_rrdtool.dll\r
205 -  /usr/lib/lighttpd/mod_secdownload.dll\r
206 -  /usr/lib/lighttpd/mod_simple_vhost.dll\r
207 -  /usr/lib/lighttpd/mod_ssi.dll\r
208 -  /usr/lib/lighttpd/mod_status.dll\r
209 -  /usr/lib/lighttpd/mod_usertrack.dll\r
210 -  /usr/sbin/lighttpd.exe\r
211 -  /usr/share/doc/Cygwin/lighttpd-1.3.0.README\r
212 -  /usr/share/doc/lighttpd-1.3.0/accesslog.txt\r
213 -  /usr/share/doc/lighttpd-1.3.0/authentification.txt\r
214 -  /usr/share/doc/lighttpd-1.3.0/AUTHORS\r
215 -  /usr/share/doc/lighttpd-1.3.0/cgi.txt\r
216 -  /usr/share/doc/lighttpd-1.3.0/ChangeLog\r
217 -  /usr/share/doc/lighttpd-1.3.0/compress.txt\r
218 -  /usr/share/doc/lighttpd-1.3.0/configuration.txt\r
219 -  /usr/share/doc/lighttpd-1.3.0/COPYING\r
220 -  /usr/share/doc/lighttpd-1.3.0/fastcgi-state.txt\r
221 -  /usr/share/doc/lighttpd-1.3.0/fastcgi.txt\r
222 -  /usr/share/doc/lighttpd-1.3.0/features.txt\r
223 -  /usr/share/doc/lighttpd-1.3.0/INSTALL\r
224 -  /usr/share/doc/lighttpd-1.3.0/NEWS\r
225 -  /usr/share/doc/lighttpd-1.3.0/performance.txt\r
226 -  /usr/share/doc/lighttpd-1.3.0/plugins.txt\r
227 -  /usr/share/doc/lighttpd-1.3.0/proxy.txt\r
228 -  /usr/share/doc/lighttpd-1.3.0/README\r
229 -  /usr/share/doc/lighttpd-1.3.0/redirect.txt\r
230 -  /usr/share/doc/lighttpd-1.3.0/rewrite.txt\r
231 -  /usr/share/doc/lighttpd-1.3.0/rrdtool.txt\r
232 -  /usr/share/doc/lighttpd-1.3.0/secdownload.txt\r
233 -  /usr/share/doc/lighttpd-1.3.0/security.txt\r
234 -  /usr/share/doc/lighttpd-1.3.0/simple-vhost.txt\r
235 -  /usr/share/doc/lighttpd-1.3.0/skeleton.txt\r
236 -  /usr/share/doc/lighttpd-1.3.0/ssi.txt\r
237 -  /usr/share/doc/lighttpd-1.3.0/state.txt\r
238 -  /usr/share/man/man1/lighttpd.1.gz\r
239 -\r
240 -------------------\r
241 -\r
242 -Port Notes:\r
243 -\r
244 -----------  lighttpd-1.3.1-1 -----------\r
245 -\r
246 -Updated to 1.3.1\r
247 -\r
248 -----------  lighttpd-1.3.0-1 -----------\r
249 -Initial release\r
250 -\r
251 -Cygwin port maintained by: Jan Kneschke <jan@kneschke.de>\r
252 -Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com>\r
253 -\r
254 +lighttpd
255 +------------------------------------------
256 +A fast, secure and flexible webserver
257 +
258 +Runtime requirements:
259 +  cygwin-1.5.10 or newer
260 +  crypt-1.1 or newer
261 +  libbz2_1-1.0.2 or newer
262 +  libpcre0-4.5 or newer
263 +  openssl-0.9.7d or newer
264 +  zlib-1.2.1 or newer
265 +
266 +Build requirements:
267 +  cygwin-1.5.10 or newer
268 +  gcc-3.3.1-3 or newer
269 +  binutils-20030901-1 or newer
270 +  crypt
271 +  openssl-devel
272 +  openssl
273 +  openldap
274 +  openldap-devel
275 +  zlib
276 +  bzip2
277 +
278 +Canonical homepage:
279 +  http://jan.kneschke.de/projects/lighttpd/
280 +
281 +Canonical download:
282 +  http://jan.kneschke.de/projects/lighttpd/download
283 +
284 +------------------------------------
285 +
286 +Build instructions:
287 +  unpack lighttpd-1.4.12-<REL>-src.tar.bz2
288 +    if you use setup to install this src package, it will be
289 +        unpacked under /usr/src automatically
290 +  cd /usr/src
291 +  ./lighttpd-1.4.12-<REL>.sh all
292 +
293 +This will create:
294 +  /usr/src/lighttpd-1.4.12-<REL>.tar.bz2
295 +  /usr/src/lighttpd-1.4.12-<REL>-src.tar.bz2
296 +
297 +Or use './lighttpd-1.4.12-<REL>.sh prep' to get a patched source directory
298 +
299 +-------------------------------------------
300 +
301 +Files included in the binary distribution:
302 +
303 +  /etc/lighttpd/lighttpd.conf.default
304 +  /usr/lib/cyglightcomp.dll
305 +  /usr/lib/lighttpd/mod_access.dll
306 +  /usr/lib/lighttpd/mod_accesslog.dll
307 +  /usr/lib/lighttpd/mod_auth.dll
308 +  /usr/lib/lighttpd/mod_cgi.dll
309 +  /usr/lib/lighttpd/mod_compress.dll
310 +  /usr/lib/lighttpd/mod_evhost.dll
311 +  /usr/lib/lighttpd/mod_expire.dll
312 +  /usr/lib/lighttpd/mod_fastcgi.dll
313 +  /usr/lib/lighttpd/mod_httptls.dll
314 +  /usr/lib/lighttpd/mod_maps.dll
315 +  /usr/lib/lighttpd/mod_proxy.dll
316 +  /usr/lib/lighttpd/mod_redirect.dll
317 +  /usr/lib/lighttpd/mod_rewrite.dll
318 +  /usr/lib/lighttpd/mod_rrdtool.dll
319 +  /usr/lib/lighttpd/mod_secdownload.dll
320 +  /usr/lib/lighttpd/mod_simple_vhost.dll
321 +  /usr/lib/lighttpd/mod_ssi.dll
322 +  /usr/lib/lighttpd/mod_status.dll
323 +  /usr/lib/lighttpd/mod_usertrack.dll
324 +  /usr/sbin/lighttpd.exe
325 +  /usr/share/doc/Cygwin/lighttpd-1.3.0.README
326 +  /usr/share/doc/lighttpd-1.3.0/accesslog.txt
327 +  /usr/share/doc/lighttpd-1.3.0/authentification.txt
328 +  /usr/share/doc/lighttpd-1.3.0/AUTHORS
329 +  /usr/share/doc/lighttpd-1.3.0/cgi.txt
330 +  /usr/share/doc/lighttpd-1.3.0/ChangeLog
331 +  /usr/share/doc/lighttpd-1.3.0/compress.txt
332 +  /usr/share/doc/lighttpd-1.3.0/configuration.txt
333 +  /usr/share/doc/lighttpd-1.3.0/COPYING
334 +  /usr/share/doc/lighttpd-1.3.0/fastcgi-state.txt
335 +  /usr/share/doc/lighttpd-1.3.0/fastcgi.txt
336 +  /usr/share/doc/lighttpd-1.3.0/features.txt
337 +  /usr/share/doc/lighttpd-1.3.0/INSTALL
338 +  /usr/share/doc/lighttpd-1.3.0/NEWS
339 +  /usr/share/doc/lighttpd-1.3.0/performance.txt
340 +  /usr/share/doc/lighttpd-1.3.0/plugins.txt
341 +  /usr/share/doc/lighttpd-1.3.0/proxy.txt
342 +  /usr/share/doc/lighttpd-1.3.0/README
343 +  /usr/share/doc/lighttpd-1.3.0/redirect.txt
344 +  /usr/share/doc/lighttpd-1.3.0/rewrite.txt
345 +  /usr/share/doc/lighttpd-1.3.0/rrdtool.txt
346 +  /usr/share/doc/lighttpd-1.3.0/secdownload.txt
347 +  /usr/share/doc/lighttpd-1.3.0/security.txt
348 +  /usr/share/doc/lighttpd-1.3.0/simple-vhost.txt
349 +  /usr/share/doc/lighttpd-1.3.0/skeleton.txt
350 +  /usr/share/doc/lighttpd-1.3.0/ssi.txt
351 +  /usr/share/doc/lighttpd-1.3.0/state.txt
352 +  /usr/share/man/man1/lighttpd.1.gz
353 +
354 +------------------
355 +
356 +Port Notes:
357 +
358 +----------  lighttpd-1.3.1-1 -----------
359 +
360 +Updated to 1.3.1
361 +
362 +----------  lighttpd-1.3.0-1 -----------
363 +Initial release
364 +
365 +Cygwin port maintained by: Jan Kneschke <jan@kneschke.de>
366 +Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com>
367 +
368 --- ../lighttpd-1.4.11/cygwin/lighttpd.README.in        2005-08-11 01:26:59.000000000 +0300
369 +++ lighttpd-1.4.12/cygwin/lighttpd.README.in   2006-07-16 00:26:04.000000000 +0300
370 @@ -1,114 +1,114 @@
371 -lighttpd\r
372 -------------------------------------------\r
373 -A fast, secure and flexible webserver\r
374 -\r
375 -Runtime requirements:\r
376 -  cygwin-1.5.10 or newer\r
377 -  crypt-1.1 or newer\r
378 -  libbz2_1-1.0.2 or newer\r
379 -  libpcre0-4.5 or newer\r
380 -  openssl-0.9.7d or newer\r
381 -  zlib-1.2.1 or newer\r
382 -\r
383 -Build requirements:\r
384 -  cygwin-1.5.10 or newer\r
385 -  gcc-3.3.1-3 or newer\r
386 -  binutils-20030901-1 or newer\r
387 -  crypt\r
388 -  openssl-devel\r
389 -  openssl\r
390 -  openldap\r
391 -  openldap-devel\r
392 -  zlib\r
393 -  bzip2\r
394 -\r
395 -Canonical homepage:\r
396 -  http://jan.kneschke.de/projects/lighttpd/\r
397 -\r
398 -Canonical download:\r
399 -  http://jan.kneschke.de/projects/lighttpd/download\r
400 -\r
401 -------------------------------------\r
402 -\r
403 -Build instructions:\r
404 -  unpack lighttpd-@VERSION@-<REL>-src.tar.bz2\r
405 -    if you use setup to install this src package, it will be\r
406 -        unpacked under /usr/src automatically\r
407 -  cd /usr/src\r
408 -  ./lighttpd-@VERSION@-<REL>.sh all\r
409 -\r
410 -This will create:\r
411 -  /usr/src/lighttpd-@VERSION@-<REL>.tar.bz2\r
412 -  /usr/src/lighttpd-@VERSION@-<REL>-src.tar.bz2\r
413 -\r
414 -Or use './lighttpd-@VERSION@-<REL>.sh prep' to get a patched source directory\r
415 -\r
416 --------------------------------------------\r
417 -\r
418 -Files included in the binary distribution:\r
419 -\r
420 -  /etc/lighttpd/lighttpd.conf.default\r
421 -  /usr/lib/cyglightcomp.dll\r
422 -  /usr/lib/lighttpd/mod_access.dll\r
423 -  /usr/lib/lighttpd/mod_accesslog.dll\r
424 -  /usr/lib/lighttpd/mod_auth.dll\r
425 -  /usr/lib/lighttpd/mod_cgi.dll\r
426 -  /usr/lib/lighttpd/mod_compress.dll\r
427 -  /usr/lib/lighttpd/mod_evhost.dll\r
428 -  /usr/lib/lighttpd/mod_expire.dll\r
429 -  /usr/lib/lighttpd/mod_fastcgi.dll\r
430 -  /usr/lib/lighttpd/mod_httptls.dll\r
431 -  /usr/lib/lighttpd/mod_maps.dll\r
432 -  /usr/lib/lighttpd/mod_proxy.dll\r
433 -  /usr/lib/lighttpd/mod_redirect.dll\r
434 -  /usr/lib/lighttpd/mod_rewrite.dll\r
435 -  /usr/lib/lighttpd/mod_rrdtool.dll\r
436 -  /usr/lib/lighttpd/mod_secdownload.dll\r
437 -  /usr/lib/lighttpd/mod_simple_vhost.dll\r
438 -  /usr/lib/lighttpd/mod_ssi.dll\r
439 -  /usr/lib/lighttpd/mod_status.dll\r
440 -  /usr/lib/lighttpd/mod_usertrack.dll\r
441 -  /usr/sbin/lighttpd.exe\r
442 -  /usr/share/doc/Cygwin/lighttpd-1.3.0.README\r
443 -  /usr/share/doc/lighttpd-1.3.0/accesslog.txt\r
444 -  /usr/share/doc/lighttpd-1.3.0/authentification.txt\r
445 -  /usr/share/doc/lighttpd-1.3.0/AUTHORS\r
446 -  /usr/share/doc/lighttpd-1.3.0/cgi.txt\r
447 -  /usr/share/doc/lighttpd-1.3.0/ChangeLog\r
448 -  /usr/share/doc/lighttpd-1.3.0/compress.txt\r
449 -  /usr/share/doc/lighttpd-1.3.0/configuration.txt\r
450 -  /usr/share/doc/lighttpd-1.3.0/COPYING\r
451 -  /usr/share/doc/lighttpd-1.3.0/fastcgi-state.txt\r
452 -  /usr/share/doc/lighttpd-1.3.0/fastcgi.txt\r
453 -  /usr/share/doc/lighttpd-1.3.0/features.txt\r
454 -  /usr/share/doc/lighttpd-1.3.0/INSTALL\r
455 -  /usr/share/doc/lighttpd-1.3.0/NEWS\r
456 -  /usr/share/doc/lighttpd-1.3.0/performance.txt\r
457 -  /usr/share/doc/lighttpd-1.3.0/plugins.txt\r
458 -  /usr/share/doc/lighttpd-1.3.0/proxy.txt\r
459 -  /usr/share/doc/lighttpd-1.3.0/README\r
460 -  /usr/share/doc/lighttpd-1.3.0/redirect.txt\r
461 -  /usr/share/doc/lighttpd-1.3.0/rewrite.txt\r
462 -  /usr/share/doc/lighttpd-1.3.0/rrdtool.txt\r
463 -  /usr/share/doc/lighttpd-1.3.0/secdownload.txt\r
464 -  /usr/share/doc/lighttpd-1.3.0/security.txt\r
465 -  /usr/share/doc/lighttpd-1.3.0/simple-vhost.txt\r
466 -  /usr/share/doc/lighttpd-1.3.0/skeleton.txt\r
467 -  /usr/share/doc/lighttpd-1.3.0/ssi.txt\r
468 -  /usr/share/doc/lighttpd-1.3.0/state.txt\r
469 -  /usr/share/man/man1/lighttpd.1.gz\r
470 -\r
471 -------------------\r
472 -\r
473 -Port Notes:\r
474 -\r
475 -----------  lighttpd-1.3.1-1 -----------\r
476 -\r
477 -Updated to 1.3.1\r
478 -\r
479 -----------  lighttpd-1.3.0-1 -----------\r
480 -Initial release\r
481 -\r
482 -Cygwin port maintained by: Jan Kneschke <jan@kneschke.de>\r
483 -Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com>\r
484 -\r
485 +lighttpd
486 +------------------------------------------
487 +A fast, secure and flexible webserver
488 +
489 +Runtime requirements:
490 +  cygwin-1.5.10 or newer
491 +  crypt-1.1 or newer
492 +  libbz2_1-1.0.2 or newer
493 +  libpcre0-4.5 or newer
494 +  openssl-0.9.7d or newer
495 +  zlib-1.2.1 or newer
496 +
497 +Build requirements:
498 +  cygwin-1.5.10 or newer
499 +  gcc-3.3.1-3 or newer
500 +  binutils-20030901-1 or newer
501 +  crypt
502 +  openssl-devel
503 +  openssl
504 +  openldap
505 +  openldap-devel
506 +  zlib
507 +  bzip2
508 +
509 +Canonical homepage:
510 +  http://jan.kneschke.de/projects/lighttpd/
511 +
512 +Canonical download:
513 +  http://jan.kneschke.de/projects/lighttpd/download
514 +
515 +------------------------------------
516 +
517 +Build instructions:
518 +  unpack lighttpd-@VERSION@-<REL>-src.tar.bz2
519 +    if you use setup to install this src package, it will be
520 +        unpacked under /usr/src automatically
521 +  cd /usr/src
522 +  ./lighttpd-@VERSION@-<REL>.sh all
523 +
524 +This will create:
525 +  /usr/src/lighttpd-@VERSION@-<REL>.tar.bz2
526 +  /usr/src/lighttpd-@VERSION@-<REL>-src.tar.bz2
527 +
528 +Or use './lighttpd-@VERSION@-<REL>.sh prep' to get a patched source directory
529 +
530 +-------------------------------------------
531 +
532 +Files included in the binary distribution:
533 +
534 +  /etc/lighttpd/lighttpd.conf.default
535 +  /usr/lib/cyglightcomp.dll
536 +  /usr/lib/lighttpd/mod_access.dll
537 +  /usr/lib/lighttpd/mod_accesslog.dll
538 +  /usr/lib/lighttpd/mod_auth.dll
539 +  /usr/lib/lighttpd/mod_cgi.dll
540 +  /usr/lib/lighttpd/mod_compress.dll
541 +  /usr/lib/lighttpd/mod_evhost.dll
542 +  /usr/lib/lighttpd/mod_expire.dll
543 +  /usr/lib/lighttpd/mod_fastcgi.dll
544 +  /usr/lib/lighttpd/mod_httptls.dll
545 +  /usr/lib/lighttpd/mod_maps.dll
546 +  /usr/lib/lighttpd/mod_proxy.dll
547 +  /usr/lib/lighttpd/mod_redirect.dll
548 +  /usr/lib/lighttpd/mod_rewrite.dll
549 +  /usr/lib/lighttpd/mod_rrdtool.dll
550 +  /usr/lib/lighttpd/mod_secdownload.dll
551 +  /usr/lib/lighttpd/mod_simple_vhost.dll
552 +  /usr/lib/lighttpd/mod_ssi.dll
553 +  /usr/lib/lighttpd/mod_status.dll
554 +  /usr/lib/lighttpd/mod_usertrack.dll
555 +  /usr/sbin/lighttpd.exe
556 +  /usr/share/doc/Cygwin/lighttpd-1.3.0.README
557 +  /usr/share/doc/lighttpd-1.3.0/accesslog.txt
558 +  /usr/share/doc/lighttpd-1.3.0/authentification.txt
559 +  /usr/share/doc/lighttpd-1.3.0/AUTHORS
560 +  /usr/share/doc/lighttpd-1.3.0/cgi.txt
561 +  /usr/share/doc/lighttpd-1.3.0/ChangeLog
562 +  /usr/share/doc/lighttpd-1.3.0/compress.txt
563 +  /usr/share/doc/lighttpd-1.3.0/configuration.txt
564 +  /usr/share/doc/lighttpd-1.3.0/COPYING
565 +  /usr/share/doc/lighttpd-1.3.0/fastcgi-state.txt
566 +  /usr/share/doc/lighttpd-1.3.0/fastcgi.txt
567 +  /usr/share/doc/lighttpd-1.3.0/features.txt
568 +  /usr/share/doc/lighttpd-1.3.0/INSTALL
569 +  /usr/share/doc/lighttpd-1.3.0/NEWS
570 +  /usr/share/doc/lighttpd-1.3.0/performance.txt
571 +  /usr/share/doc/lighttpd-1.3.0/plugins.txt
572 +  /usr/share/doc/lighttpd-1.3.0/proxy.txt
573 +  /usr/share/doc/lighttpd-1.3.0/README
574 +  /usr/share/doc/lighttpd-1.3.0/redirect.txt
575 +  /usr/share/doc/lighttpd-1.3.0/rewrite.txt
576 +  /usr/share/doc/lighttpd-1.3.0/rrdtool.txt
577 +  /usr/share/doc/lighttpd-1.3.0/secdownload.txt
578 +  /usr/share/doc/lighttpd-1.3.0/security.txt
579 +  /usr/share/doc/lighttpd-1.3.0/simple-vhost.txt
580 +  /usr/share/doc/lighttpd-1.3.0/skeleton.txt
581 +  /usr/share/doc/lighttpd-1.3.0/ssi.txt
582 +  /usr/share/doc/lighttpd-1.3.0/state.txt
583 +  /usr/share/man/man1/lighttpd.1.gz
584 +
585 +------------------
586 +
587 +Port Notes:
588 +
589 +----------  lighttpd-1.3.1-1 -----------
590 +
591 +Updated to 1.3.1
592 +
593 +----------  lighttpd-1.3.0-1 -----------
594 +Initial release
595 +
596 +Cygwin port maintained by: Jan Kneschke <jan@kneschke.de>
597 +Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com>
598 +
599 --- ../lighttpd-1.4.11/doc/authentication.txt   2006-01-12 20:34:26.000000000 +0200
600 +++ lighttpd-1.4.12/doc/authentication.txt      2006-07-16 00:26:05.000000000 +0300
601 @@ -7,8 +7,8 @@
602  ----------------
603  
604  :Author: Jan Kneschke
605 -:Date: $Date$
606 -:Revision: $Revision$
607 +:Date: $Date$
608 +:Revision: $Revision$
609  
610  :abstract:
611    The auth module provides ...
612 --- ../lighttpd-1.4.11/doc/compress.txt 2005-08-11 01:26:16.000000000 +0300
613 +++ lighttpd-1.4.12/doc/compress.txt    2006-07-16 00:26:05.000000000 +0300
614 @@ -22,12 +22,38 @@
615  ===========
616  
617  Output compression reduces the network load and can improve the overall
618 -throughput of the webserver. 
619 +throughput of the webserver. All major http-clients support compression by
620 +announcing it in the Accept-Encoding header. This is used to negotiate the 
621 +most suitable compression method. We support deflate, gzip and bzip2.
622  
623 -Only static content is supported up to now.
624 +deflate (RFC1950, RFC1951) and gzip (RFC1952) depend on zlib while bzip2 
625 +depends on libbzip2. bzip2 is only supported by lynx and some other console
626 +text-browsers.
627  
628 -The server negotiates automaticly which compression method is used.
629 -Supported are gzip, deflate, bzip.
630 +Currently we limit to compression support to static files.
631 +
632 +Caching
633 +-------
634 +
635 +mod_compress can stored compressed files on disk to optimized the compression
636 +on a second request away. As soon as compress.cache-dir is set the files are
637 +compressed. 
638 +
639 +The names of the cache files are made of the filename, the compression method
640 +and the etag associated to the file.
641 +
642 +Cleaning the cache is left to the user. A cron job deleting files older than
643 +10 days should do fine.
644 +
645 +Limitations
646 +-----------
647 +
648 +The module limits the compression of files to files larger than 128 Byte and
649 +smaller than 128 MByte.
650 +
651 +The lower limit is set as small files tend to become larger by compressing due
652 +to the compression headers, the upper limit is set to work sensable with
653 +memory and cpu-time.
654  
655  Options
656  =======
657 @@ -47,15 +73,28 @@
658    Default: not set, compress the file for every request
659  
660  compress.filetype
661 -  mimetypes where might get compressed
662 +  mimetypes which might get compressed
663    
664    e.g.: ::
665    
666      compress.filetype           = ("text/plain", "text/html")
667  
668 +  Keep in mind that compressed JavaScript and CSS files are broken in some
669 +  browsers.
670 +
671    Default: not set
672  
673 +compress.max-file-size 
674 +  maximum size of the original file to be compressed kBytes.
675 +
676 +  This is meant to protect the server against DoSing as compressing large
677 +  (let's say 1Gbyte) takes a lot of time and would delay the whole operation
678 +  of the server.
679  
680 +  There is a hard upper limit of 128Mbyte.
681 +
682 +  Default: unlimited (== hard-limit of 128MByte)
683 +  
684  Compressing Dynamic Content
685  ===========================
686  
687 --- ../lighttpd-1.4.11/doc/configuration.txt    2006-03-09 02:10:40.000000000 +0200
688 +++ lighttpd-1.4.12/doc/configuration.txt       2006-07-16 00:26:05.000000000 +0300
689 @@ -7,8 +7,8 @@
690  ------------
691  
692  :Author: Jan Kneschke
693 -:Date: $Date$
694 -:Revision: $Revision$
695 +:Date: $Date$
696 +:Revision: $Revision$
697  
698  :abstract:
699    the layout of the configuration file
700 @@ -511,3 +511,10 @@
701  
702  debug.log-request-handling
703    default: disabled 
704 +
705 +debug.log-condition-handling
706 +  default: disabled 
707 +
708 +debug.log-condition-cache-handling
709 +  for developers only
710 +  default: disabled 
711 --- ../lighttpd-1.4.11/doc/fastcgi.txt  2006-02-16 17:03:52.000000000 +0200
712 +++ lighttpd-1.4.12/doc/fastcgi.txt     2006-07-16 00:26:05.000000000 +0300
713 @@ -144,8 +144,8 @@
714                  PHP can extract PATH_INFO from it (default: disabled)
715    :"disable-time": time to wait before a disabled backend is checked
716                  again
717 -  :"allow-x-send-file": controls if X-LIGHTTPD-send-file headers
718 -                are allowed 
719 +  :"allow-x-send-file": controls if X-LIGHTTPD-send-file and X-Sendfile
720 +                headers are allowed 
721  
722    If bin-path is set:
723  
724 --- ../lighttpd-1.4.11/doc/lighttpd.conf        2006-03-04 14:41:12.000000000 +0200
725 +++ lighttpd-1.4.12/doc/lighttpd.conf   2006-07-16 00:26:05.000000000 +0300
726 @@ -172,10 +172,11 @@
727  #dir-listing.activate       = "enable"
728  
729  ## enable debugging
730 -#debug.log-request-header   = "enable"
731 -#debug.log-response-header  = "enable"
732 -#debug.log-request-handling = "enable"
733 -#debug.log-file-not-found   = "enable"
734 +#debug.log-request-header     = "enable"
735 +#debug.log-response-header    = "enable"
736 +#debug.log-request-handling   = "enable"
737 +#debug.log-file-not-found     = "enable"
738 +#debug.log-condition-handling = "enable"
739  
740  ### only root can use these options
741  #
742 --- ../lighttpd-1.4.11/doc/performance.txt      2006-02-02 13:01:08.000000000 +0200
743 +++ lighttpd-1.4.12/doc/performance.txt 2006-07-16 00:26:05.000000000 +0300
744 @@ -183,6 +183,8 @@
745  
746    server.stat-cache-engine = "fam"   # either fam, simple or disabled
747  
748 +See http://oss.sgi.com/projects/fam/faq.html for information about FAM.
749 +See http://www.gnome.org/~veillard/gamin/overview.html for information about gamin.
750  
751  Platform-Specific Notes
752  =======================
753 --- ../lighttpd-1.4.11/doc/secdownload.txt      2005-12-20 15:58:58.000000000 +0200
754 +++ lighttpd-1.4.12/doc/secdownload.txt 2006-07-16 00:26:05.000000000 +0300
755 @@ -118,7 +118,7 @@
756    $secret = "verysecret";
757    $uri_prefix = "/dl/";
758    
759 -  # filename
760 +  # filename, make sure it's started with a "/" or you'll get 404 in the browser
761    $f = "/secret-file.txt";
762    
763    # current timestamp
764 --- ../lighttpd-1.4.11/lighttpd.spec    2006-03-07 14:22:18.000000000 +0200
765 +++ lighttpd-1.4.12/lighttpd.spec       2006-07-17 22:02:18.000000000 +0300
766 @@ -1,6 +1,6 @@
767  Summary: A fast webserver with minimal memory-footprint (lighttpd)
768  Name: lighttpd
769 -Version: 1.4.11
770 +Version: 1.4.12
771  Release: 1
772  Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-%version.tar.gz
773  Packager: Jan Kneschke <jan@kneschke.de>
774 --- ../lighttpd-1.4.11/openwrt/control  2006-03-07 14:22:19.000000000 +0200
775 +++ lighttpd-1.4.12/openwrt/control     2006-07-17 22:02:18.000000000 +0300
776 @@ -1,8 +1,8 @@
777  Package: lighttpd
778 -Version: 1.4.11
779 +Version: 1.4.12
780  Architecture: mipsel
781  Maintainer: Jan Kneschke <jan@kneschke.de>
782 -Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-1.4.11.tar.gz
783 +Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-1.4.12.tar.gz
784  Section: net
785  Priority: optional
786  Depends:
787 --- ../lighttpd-1.4.11/openwrt/lighttpd.mk      2006-03-07 14:22:19.000000000 +0200
788 +++ lighttpd-1.4.12/openwrt/lighttpd.mk 2006-07-17 22:02:18.000000000 +0300
789 @@ -10,7 +10,7 @@
790  
791  #  For this example we'll use a fairly simple package that compiles easily
792  #  and has sources available for download at sourceforge
793 -LIGHTTPD=lighttpd-1.4.11
794 +LIGHTTPD=lighttpd-1.4.12
795  LIGHTTPD_TARGET=.built
796  LIGHTTPD_DIR=$(BUILD_DIR)/$(LIGHTTPD)
797  LIGHTTPD_IPK=$(BUILD_DIR)/$(LIGHTTPD)_mipsel.ipk
798 --- ../lighttpd-1.4.11/src/Makefile.am  2006-03-07 14:20:20.000000000 +0200
799 +++ lighttpd-1.4.12/src/Makefile.am     2006-07-18 13:03:40.000000000 +0300
800 @@ -16,18 +16,24 @@
801  else
802  configparser.y: lemon
803  mod_ssi_exprparser.y: lemon
804 +http_resp_parser.y: lemon
805  
806  configparser.c configparser.h: configparser.y
807         rm -f configparser.h
808 -       $(LEMON) -q $(srcdir)/configparser.y $(srcdir)/lempar.c
809 +       $(LEMON) -q $(srcdir)/$< $(srcdir)/lempar.c
810 +
811 +http_resp_parser.c http_resp_parser.h: http_resp_parser.y
812 +       rm -f http_resp_parser.h
813 +       $(LEMON) -q $(srcdir)/$< $(srcdir)/lempar.c
814  
815  mod_ssi_exprparser.c mod_ssi_exprparser.h: mod_ssi_exprparser.y 
816         rm -f mod_ssi_exprparser.h
817 -       $(LEMON) -q $(srcdir)/mod_ssi_exprparser.y $(srcdir)/lempar.c
818 +       $(LEMON) -q $(srcdir)/$< $(srcdir)/lempar.c
819  endif
820  
821  configfile.c: configparser.h
822  mod_ssi_expr.c: mod_ssi_exprparser.h
823 +http_resp.c: http_resp_parser.h
824  
825  common_src=buffer.c log.c \
826        keyvalue.c chunk.c  \
827 @@ -40,13 +46,13 @@
828        fdevent_solaris_devpoll.c fdevent_freebsd_kqueue.c \
829        data_config.c bitset.c \
830        inet_ntop_cache.c crc32.c \
831 -      connections-glue.c \
832 +      connections-glue.c iosocket.c \
833        configfile-glue.c \
834        http-header-glue.c \
835        network_write.c network_linux_sendfile.c \
836        network_freebsd_sendfile.c network_writev.c \
837        network_solaris_sendfilev.c network_openssl.c \
838 -      splaytree.c 
839 +      splaytree.c http_resp.c http_resp_parser.c 
840        
841  src = server.c response.c connections.c network.c \
842        configfile.c configparser.c request.c proc_open.c
843 @@ -82,9 +88,9 @@
844  
845  lib_LTLIBRARIES += mod_webdav.la
846  mod_webdav_la_SOURCES = mod_webdav.c
847 -mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS)
848 +mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS) 
849  mod_webdav_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
850 -mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS)
851 +mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS) $(UUID_LIB)
852  
853  lib_LTLIBRARIES += mod_cml.la
854  mod_cml_la_SOURCES = mod_cml.c mod_cml_lua.c mod_cml_funcs.c
855 @@ -103,6 +109,11 @@
856  mod_mysql_vhost_la_LIBADD = $(MYSQL_LIBS) $(common_libadd)
857  mod_mysql_vhost_la_CPPFLAGS = $(MYSQL_INCLUDE)
858  
859 +lib_LTLIBRARIES += mod_sql_vhost_core.la
860 +mod_sql_vhost_core_la_SOURCES = mod_sql_vhost_core.c
861 +mod_sql_vhost_core_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
862 +mod_sql_vhost_core_la_LIBADD = $(common_libadd)
863 +
864  lib_LTLIBRARIES += mod_cgi.la
865  mod_cgi_la_SOURCES = mod_cgi.c 
866  mod_cgi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
867 @@ -158,6 +169,13 @@
868  mod_proxy_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
869  mod_proxy_la_LIBADD = $(common_libadd)
870  
871 +lib_LTLIBRARIES += mod_proxy_core.la
872 +mod_proxy_core_la_SOURCES = mod_proxy_core.c mod_proxy_core_pool.c \
873 +                           mod_proxy_core_backend.c mod_proxy_core_address.c mod_proxy_core_backlog.c
874 +mod_proxy_core_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
875 +mod_proxy_core_la_LIBADD = $(common_libadd)
876 +
877 +
878  lib_LTLIBRARIES += mod_ssi.la
879  mod_ssi_la_SOURCES = mod_ssi_exprparser.c mod_ssi_expr.c mod_ssi.c 
880  mod_ssi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
881 @@ -240,7 +258,12 @@
882        mod_ssi.h mod_ssi_expr.h inet_ntop_cache.h \
883        configparser.h mod_ssi_exprparser.h \
884        sys-mmap.h sys-socket.h mod_cml.h mod_cml_funcs.h \
885 -      splaytree.h proc_open.h
886 +      splaytree.h proc_open.h http_resp.h mod_sql_vhost_core.h \
887 +      sys-files.h sys-process.h sys-strings.h http_resp_parser.h \
888 +      iosocket.h array-static.h \
889 +      mod_proxy_core_address.h mod_proxy_core_backend.h \
890 +      mod_proxy_core_backlog.h mod_proxy_core.h  \
891 +      mod_proxy_core_pool.h
892  
893  DEFS= @DEFS@ -DLIBRARY_DIR="\"$(libdir)\""
894  
895 @@ -267,4 +290,4 @@
896  #ajp_SOURCES = ajp.c
897  
898  noinst_HEADERS   = $(hdr)
899 -EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c
900 +EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c http_resp_parser.y
901 --- ../lighttpd-1.4.11/src/array-static.h       1970-01-01 03:00:00.000000000 +0300
902 +++ lighttpd-1.4.12/src/array-static.h  2006-07-18 13:03:40.000000000 +0300
903 @@ -0,0 +1,33 @@
904 +#ifndef _ARRAY_STATIC_H_
905 +#define _ARRAY_STATIC_H_
906 +
907 +/* define a generic array of <type>
908 + * */
909 +
910 +#define ARRAY_STATIC_DEF(name, type, extra) \
911 +typedef struct { \
912 +       type **ptr; \
913 +       size_t used; \
914 +       size_t size; \
915 +       extra\
916 +} name
917 +
918 +/* all append operations need a 'resize' for the +1 */
919 +
920 +#define ARRAY_STATIC_PREPARE_APPEND(a) \
921 +        if (a->size == 0) { \
922 +               a->size = 16; \
923 +               a->ptr = malloc(a->size * sizeof(*(a->ptr))); \
924 +       } else if (a->size == a->used) { \
925 +               a->size += 16; \
926 +               a->ptr = realloc(a->ptr, a->size * sizeof(*(a->ptr))); \
927 +       }
928 +       
929 +#define FOREACH(array, element, func) \
930 +do { size_t _i; for (_i = 0; _i < array->used; _i++) { void *element = array->ptr[_i]; func; } } while(0);
931 +
932 +#define STRUCT_INIT(type, var) \
933 +       type *var;\
934 +       var = calloc(1, sizeof(*var))
935 +
936 +#endif
937 --- ../lighttpd-1.4.11/src/array.c      2005-11-18 13:58:32.000000000 +0200
938 +++ lighttpd-1.4.12/src/array.c 2006-07-16 00:26:03.000000000 +0300
939 @@ -11,12 +11,12 @@
940  
941  array *array_init(void) {
942         array *a;
943 -       
944 +
945         a = calloc(1, sizeof(*a));
946         assert(a);
947 -       
948 +
949         a->next_power_of_2 = 1;
950 -       
951 +
952         return a;
953  }
954  
955 @@ -43,29 +43,29 @@
956  void array_free(array *a) {
957         size_t i;
958         if (!a) return;
959 -       
960 +
961         if (!a->is_weakref) {
962                 for (i = 0; i < a->size; i++) {
963                         if (a->data[i]) a->data[i]->free(a->data[i]);
964                 }
965         }
966 -       
967 +
968         if (a->data) free(a->data);
969         if (a->sorted) free(a->sorted);
970 -       
971 +
972         free(a);
973  }
974  
975  void array_reset(array *a) {
976         size_t i;
977         if (!a) return;
978 -       
979 +
980         if (!a->is_weakref) {
981                 for (i = 0; i < a->used; i++) {
982                         a->data[i]->reset(a->data[i]);
983                 }
984         }
985 -       
986 +
987         a->used = 0;
988  }
989  
990 @@ -84,20 +84,20 @@
991  static int array_get_index(array *a, const char *key, size_t keylen, int *rndx) {
992         int ndx = -1;
993         int i, pos = 0;
994 -       
995 +
996         if (key == NULL) return -1;
997 -       
998 +
999         /* try to find the string */
1000         for (i = pos = a->next_power_of_2 / 2; ; i >>= 1) {
1001                 int cmp;
1002 -               
1003 +
1004                 if (pos < 0) {
1005                         pos += i;
1006                 } else if (pos >= (int)a->used) {
1007                         pos -= i;
1008                 } else {
1009                         cmp = buffer_caseless_compare(key, keylen, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used);
1010 -                       
1011 +
1012                         if (cmp == 0) {
1013                                 /* found */
1014                                 ndx = a->sorted[pos];
1015 @@ -110,46 +110,46 @@
1016                 }
1017                 if (i == 0) break;
1018         }
1019 -       
1020 +
1021         if (rndx) *rndx = pos;
1022 -       
1023 +
1024         return ndx;
1025  }
1026  
1027  data_unset *array_get_element(array *a, const char *key) {
1028         int ndx;
1029 -       
1030 +
1031         if (-1 != (ndx = array_get_index(a, key, strlen(key) + 1, NULL))) {
1032                 /* found, leave here */
1033 -               
1034 +
1035                 return a->data[ndx];
1036 -       } 
1037 -       
1038 +       }
1039 +
1040         return NULL;
1041  }
1042  
1043  data_unset *array_get_unused_element(array *a, data_type_t t) {
1044         data_unset *ds = NULL;
1045 -       
1046 +
1047         UNUSED(t);
1048  
1049         if (a->size == 0) return NULL;
1050 -       
1051 +
1052         if (a->used == a->size) return NULL;
1053  
1054         if (a->data[a->used]) {
1055                 ds = a->data[a->used];
1056 -               
1057 +
1058                 a->data[a->used] = NULL;
1059         }
1060 -       
1061 +
1062         return ds;
1063  }
1064  
1065  /* replace or insert data, return the old one with the same key */
1066  data_unset *array_replace(array *a, data_unset *du) {
1067         int ndx;
1068 -       
1069 +
1070         if (-1 == (ndx = array_get_index(a, du->key->ptr, du->key->used, NULL))) {
1071                 array_insert_unique(a, du);
1072                 return NULL;
1073 @@ -164,13 +164,13 @@
1074         int ndx = -1;
1075         int pos = 0;
1076         size_t j;
1077 -       
1078 -       /* generate unique index if neccesary */
1079 +
1080 +       /* generate unique index if necessary */
1081         if (str->key->used == 0 || str->is_index_key) {
1082                 buffer_copy_long(str->key, a->unique_ndx++);
1083                 str->is_index_key = 1;
1084         }
1085 -       
1086 +
1087         /* try to find the string */
1088         if (-1 != (ndx = array_get_index(a, str->key->ptr, str->key->used, &pos))) {
1089                 /* found, leave here */
1090 @@ -181,14 +181,14 @@
1091                 }
1092                 return 0;
1093         }
1094 -       
1095 +
1096         /* insert */
1097 -       
1098 +
1099         if (a->used+1 > INT_MAX) {
1100                 /* we can't handle more then INT_MAX entries: see array_get_index() */
1101                 return -1;
1102         }
1103 -       
1104 +
1105         if (a->size == 0) {
1106                 a->size   = 16;
1107                 a->data   = malloc(sizeof(*a->data)     * a->size);
1108 @@ -204,27 +204,27 @@
1109                 assert(a->sorted);
1110                 for (j = a->used; j < a->size; j++) a->data[j] = NULL;
1111         }
1112 -       
1113 +
1114         ndx = (int) a->used;
1115 -       
1116 +
1117         a->data[a->used++] = str;
1118 -       
1119 +
1120         if (pos != ndx &&
1121 -           ((pos < 0) || 
1122 +           ((pos < 0) ||
1123              buffer_caseless_compare(str->key->ptr, str->key->used, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used) > 0)) {
1124                 pos++;
1125 -       } 
1126 -       
1127 -       /* move everything on step to the right */
1128 +       }
1129 +
1130 +       /* move everything one step to the right */
1131         if (pos != ndx) {
1132                 memmove(a->sorted + (pos + 1), a->sorted + (pos), (ndx - pos) * sizeof(*a->sorted));
1133         }
1134 -       
1135 +
1136         /* insert */
1137         a->sorted[pos] = ndx;
1138 -       
1139 +
1140         if (a->next_power_of_2 == (size_t)ndx) a->next_power_of_2 <<= 1;
1141 -       
1142 +
1143         return 0;
1144  }
1145  
1146 @@ -254,7 +254,7 @@
1147         size_t i;
1148         size_t maxlen;
1149         int oneline = 1;
1150 -       
1151 +
1152         if (a->used > 5) {
1153                 oneline = 0;
1154         }
1155 @@ -314,7 +314,7 @@
1156         }
1157         array_print_indent(depth);
1158         fprintf(stderr, ")");
1159 -       
1160 +
1161         return 0;
1162  }
1163  
1164 @@ -323,47 +323,47 @@
1165         array *a;
1166         data_string *ds;
1167         data_count *dc;
1168 -       
1169 +
1170         UNUSED(argc);
1171         UNUSED(argv);
1172  
1173         a = array_init();
1174 -       
1175 +
1176         ds = data_string_init();
1177         buffer_copy_string(ds->key, "abc");
1178         buffer_copy_string(ds->value, "alfrag");
1179 -       
1180 +
1181         array_insert_unique(a, (data_unset *)ds);
1182 -       
1183 +
1184         ds = data_string_init();
1185         buffer_copy_string(ds->key, "abc");
1186         buffer_copy_string(ds->value, "hameplman");
1187 -       
1188 +
1189         array_insert_unique(a, (data_unset *)ds);
1190 -       
1191 +
1192         ds = data_string_init();
1193         buffer_copy_string(ds->key, "123");
1194         buffer_copy_string(ds->value, "alfrag");
1195 -       
1196 +
1197         array_insert_unique(a, (data_unset *)ds);
1198 -       
1199 +
1200         dc = data_count_init();
1201         buffer_copy_string(dc->key, "def");
1202 -       
1203 +
1204         array_insert_unique(a, (data_unset *)dc);
1205 -       
1206 +
1207         dc = data_count_init();
1208         buffer_copy_string(dc->key, "def");
1209 -       
1210 +
1211         array_insert_unique(a, (data_unset *)dc);
1212 -       
1213 +
1214         array_print(a, 0);
1215 -       
1216 +
1217         array_free(a);
1218 -       
1219 +
1220         fprintf(stderr, "%d\n",
1221                buffer_caseless_compare(CONST_STR_LEN("Content-Type"), CONST_STR_LEN("Content-type")));
1222 -       
1223 +
1224         return 0;
1225  }
1226  #endif
1227 --- ../lighttpd-1.4.11/src/array.h      2005-09-23 21:24:18.000000000 +0300
1228 +++ lighttpd-1.4.12/src/array.h 2006-07-16 00:26:03.000000000 +0300
1229 @@ -16,7 +16,7 @@
1230  #define DATA_UNSET \
1231         data_type_t type; \
1232         buffer *key; \
1233 -       int is_index_key; /* 1 if key is a array index (autogenerated keys) */ \
1234 +       int is_index_key; /* 1 if key is an array index (auto-generated keys) */ \
1235         struct data_unset *(*copy)(const struct data_unset *src); \
1236         void (* free)(struct data_unset *p); \
1237         void (* reset)(struct data_unset *p); \
1238 @@ -29,21 +29,21 @@
1239  
1240  typedef struct {
1241         data_unset  **data;
1242 -       
1243 +
1244         size_t *sorted;
1245 -       
1246 +
1247         size_t used;
1248         size_t size;
1249 -       
1250 +
1251         size_t unique_ndx;
1252 -       
1253 +
1254         size_t next_power_of_2;
1255         int is_weakref; /* data is weakref, don't bother the data */
1256  } array;
1257  
1258  typedef struct {
1259         DATA_UNSET;
1260 -       
1261 +
1262         int count;
1263  } data_count;
1264  
1265 @@ -51,7 +51,7 @@
1266  
1267  typedef struct {
1268         DATA_UNSET;
1269 -       
1270 +
1271         buffer *value;
1272  } data_string;
1273  
1274 @@ -60,7 +60,7 @@
1275  
1276  typedef struct {
1277         DATA_UNSET;
1278 -       
1279 +
1280         array *value;
1281  } data_array;
1282  
1283 @@ -74,7 +74,7 @@
1284         COMP_SERVER_SOCKET, COMP_HTTP_URL, COMP_HTTP_HOST, COMP_HTTP_REFERER, COMP_HTTP_USERAGENT, COMP_HTTP_COOKIE, COMP_HTTP_REMOTEIP
1285  } comp_key_t;
1286  
1287 -/* $HTTP["host"] ==    "incremental.home.kneschke.de" { ... } 
1288 +/* $HTTP["host"] ==    "incremental.home.kneschke.de" { ... }
1289   * for print:   comp_key      op    string
1290   * for compare: comp          cond  string/regex
1291   */
1292 @@ -82,15 +82,15 @@
1293  typedef struct _data_config data_config;
1294  struct _data_config {
1295         DATA_UNSET;
1296 -       
1297 +
1298         array *value;
1299 -       
1300 +
1301         buffer *comp_key;
1302         comp_key_t comp;
1303 -       
1304 +
1305         config_cond_t cond;
1306         buffer *op;
1307 -       
1308 +
1309         int context_ndx; /* more or less like an id */
1310         array *childs;
1311         /* nested */
1312 @@ -98,7 +98,7 @@
1313         /* for chaining only */
1314         data_config *prev;
1315         data_config *next;
1316 -       
1317 +
1318         buffer *string;
1319  #ifdef HAVE_PCRE_H
1320         pcre   *regex;
1321 @@ -110,7 +110,7 @@
1322  
1323  typedef struct {
1324         DATA_UNSET;
1325 -       
1326 +
1327         int value;
1328  } data_integer;
1329  
1330 @@ -120,13 +120,13 @@
1331         DATA_UNSET;
1332  
1333         buffer *host;
1334 -       
1335 +
1336         unsigned short port;
1337  
1338         time_t disable_ts;
1339         int is_disabled;
1340         size_t balance;
1341 -               
1342 +
1343         int usage; /* fair-balancing needs the no. of connections active on this host */
1344         int last_used_ndx; /* round robin */
1345  } data_fastcgi;
1346 --- ../lighttpd-1.4.11/src/base.h       2006-01-11 16:51:04.000000000 +0200
1347 +++ lighttpd-1.4.12/src/base.h  2006-07-18 13:03:40.000000000 +0300
1348 @@ -2,7 +2,6 @@
1349  #define _BASE_H_
1350  
1351  #include <sys/types.h>
1352 -#include <sys/time.h>
1353  #include <sys/stat.h>
1354  
1355  #ifdef HAVE_CONFIG_H
1356 @@ -26,10 +25,9 @@
1357  #include "sys-socket.h"
1358  #include "splaytree.h"
1359  
1360 -
1361  #if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
1362  # define USE_OPENSSL
1363 -# include <openssl/ssl.h> 
1364 +# include <openssl/ssl.h>
1365  #endif
1366  
1367  #ifdef HAVE_FAM_H
1368 @@ -40,10 +38,6 @@
1369  # define O_BINARY 0
1370  #endif
1371  
1372 -#ifndef O_LARGEFILE
1373 -# define O_LARGEFILE 0
1374 -#endif
1375 -
1376  #ifndef SIZE_MAX
1377  # ifdef SIZE_T_MAX
1378  #  define SIZE_MAX SIZE_T_MAX
1379 @@ -70,7 +64,8 @@
1380  
1381  /* solaris and NetBSD 1.3.x again */
1382  #if (!defined(HAVE_STDINT_H)) && (!defined(HAVE_INTTYPES_H)) && (!defined(uint32_t))
1383 -# define uint32_t u_int32_t
1384 +/* # define uint32_t u_int32_t */
1385 +typedef unsigned __int32 uint32_t;
1386  #endif
1387  
1388  
1389 @@ -80,24 +75,24 @@
1390  
1391  #include "settings.h"
1392  
1393 -typedef enum { T_CONFIG_UNSET, 
1394 -               T_CONFIG_STRING, 
1395 -               T_CONFIG_SHORT, 
1396 -               T_CONFIG_BOOLEAN, 
1397 -               T_CONFIG_ARRAY, 
1398 -               T_CONFIG_LOCAL, 
1399 +typedef enum { T_CONFIG_UNSET,
1400 +               T_CONFIG_STRING,
1401 +               T_CONFIG_SHORT,
1402 +               T_CONFIG_BOOLEAN,
1403 +               T_CONFIG_ARRAY,
1404 +               T_CONFIG_LOCAL,
1405                 T_CONFIG_DEPRECATED
1406  } config_values_type_t;
1407  
1408 -typedef enum { T_CONFIG_SCOPE_UNSET, 
1409 -               T_CONFIG_SCOPE_SERVER, 
1410 +typedef enum { T_CONFIG_SCOPE_UNSET,
1411 +               T_CONFIG_SCOPE_SERVER,
1412                 T_CONFIG_SCOPE_CONNECTION
1413  } config_scope_type_t;
1414  
1415  typedef struct {
1416         const char *key;
1417         void *destination;
1418 -       
1419 +
1420         config_values_type_t type;
1421         config_scope_type_t scope;
1422  } config_values_t;
1423 @@ -118,18 +113,6 @@
1424         short factor;
1425  } fcgi_connections;
1426  
1427 -
1428 -typedef union {
1429 -#ifdef HAVE_IPV6
1430 -       struct sockaddr_in6 ipv6;
1431 -#endif
1432 -       struct sockaddr_in ipv4;
1433 -#ifdef HAVE_SYS_UN_H
1434 -       struct sockaddr_un un;
1435 -#endif
1436 -       struct sockaddr plain;
1437 -} sock_addr;
1438 -
1439  /* fcgi_response_header contains ... */
1440  #define HTTP_STATUS         BV(0)
1441  #define HTTP_CONNECTION     BV(1)
1442 @@ -142,40 +125,40 @@
1443         /* the request-line */
1444         buffer *request;
1445         buffer *uri;
1446 -       
1447 +
1448         buffer *orig_uri;
1449 -       
1450 +
1451         http_method_t  http_method;
1452         http_version_t http_version;
1453 -       
1454 +
1455         buffer *request_line;
1456 -       
1457 +
1458         /* strings to the header */
1459         buffer *http_host; /* not alloced */
1460         const char   *http_range;
1461         const char   *http_content_type;
1462         const char   *http_if_modified_since;
1463         const char   *http_if_none_match;
1464 -       
1465 +
1466         array  *headers;
1467 -       
1468 +
1469         /* CONTENT */
1470         size_t content_length; /* returned by strtoul() */
1471 -       
1472 +
1473         /* internal representation */
1474         int     accept_encoding;
1475 -       
1476 +
1477         /* internal */
1478         buffer *pathinfo;
1479  } request;
1480  
1481  typedef struct {
1482         off_t   content_length;
1483 -       int     keep_alive;               /* used by  the subrequests in proxy, cgi and fcgi to say the subrequest was keep-alive or not */
1484 -       
1485 +       int     keep_alive;               /* used by the subrequests in proxy, cgi and fcgi to say whether the subrequest was keep-alive or not */
1486 +
1487         array  *headers;
1488 -       
1489 -       enum { 
1490 +
1491 +       enum {
1492                 HTTP_TRANSFER_ENCODING_IDENTITY, HTTP_TRANSFER_ENCODING_CHUNKED
1493         } transfer_encoding;
1494  } response;
1495 @@ -191,21 +174,21 @@
1496  typedef struct {
1497         buffer *path;
1498         buffer *basedir; /* path = "(basedir)(.*)" */
1499 -       
1500 +
1501         buffer *doc_root; /* path = doc_root + rel_path */
1502         buffer *rel_path;
1503 -       
1504 +
1505         buffer *etag;
1506  } physical;
1507  
1508  typedef struct {
1509         buffer *name;
1510         buffer *etag;
1511 -       
1512 +
1513         struct stat st;
1514 -       
1515 +
1516         time_t stat_ts;
1517 -       
1518 +
1519  #ifdef HAVE_FAM_H
1520         int    dir_version;
1521         int    dir_ndx;
1522 @@ -215,20 +198,20 @@
1523  } stat_cache_entry;
1524  
1525  typedef struct {
1526 -       splay_tree *files; /* the nodes of the tree are stat_cache_entry's */
1527 -       
1528 +       splay_tree *files; /* the nodes of the tree are stat_cache_entries */
1529 +
1530         buffer *dir_name; /* for building the dirname from the filename */
1531  #ifdef HAVE_FAM_H
1532         splay_tree *dirs; /* the nodes of the tree are fam_dir_entry */
1533  
1534         FAMConnection *fam;
1535 -       int    fam_fcce_ndx;
1536 +       iosocket *sock;
1537  #endif
1538  } stat_cache;
1539  
1540  typedef struct {
1541         array *mimetypes;
1542 -       
1543 +
1544         /* virtual-servers */
1545         buffer *document_root;
1546         buffer *server_name;
1547 @@ -236,7 +219,7 @@
1548         buffer *server_tag;
1549         buffer *dirlist_encoding;
1550         buffer *errorfile_prefix;
1551 -       
1552 +
1553         unsigned short max_keep_alive_requests;
1554         unsigned short max_keep_alive_idle;
1555         unsigned short max_read_idle;
1556 @@ -244,16 +227,17 @@
1557         unsigned short use_xattr;
1558         unsigned short follow_symlink;
1559         unsigned short range_requests;
1560 -       
1561 +
1562         /* debug */
1563 -       
1564 +
1565         unsigned short log_file_not_found;
1566         unsigned short log_request_header;
1567         unsigned short log_request_handling;
1568         unsigned short log_response_header;
1569         unsigned short log_condition_handling;
1570 -       
1571 -       
1572 +       unsigned short log_condition_cache_handling;
1573 +
1574 +
1575         /* server wide */
1576         buffer *ssl_pemfile;
1577         buffer *ssl_ca_file;
1578 @@ -268,22 +252,22 @@
1579         /* configside */
1580         unsigned short global_kbytes_per_second; /*  */
1581  
1582 -       off_t  global_bytes_per_second_cnt; 
1583 +       off_t  global_bytes_per_second_cnt;
1584         /* server-wide traffic-shaper
1585 -        * 
1586 +        *
1587          * each context has the counter which is inited once
1588 -        * a second by the global_kbytes_per_second config-var
1589 +        * per second by the global_kbytes_per_second config-var
1590          *
1591          * as soon as global_kbytes_per_second gets below 0
1592          * the connected conns are "offline" a little bit
1593          *
1594          * the problem:
1595 -        * we somehow have to loose our "we are writable" signal 
1596 +        * we somehow have to lose our "we are writable" signal
1597          * on the way.
1598 -        * 
1599 +        *
1600          */
1601         off_t *global_bytes_per_second_cnt_ptr; /*  */
1602 -       
1603 +
1604  #ifdef USE_OPENSSL
1605         SSL_CTX *ssl_ctx;
1606  #endif
1607 @@ -291,18 +275,18 @@
1608  
1609  /* the order of the items should be the same as they are processed
1610   * read before write as we use this later */
1611 -typedef enum { 
1612 -       CON_STATE_CONNECT, 
1613 -       CON_STATE_REQUEST_START, 
1614 -       CON_STATE_READ, 
1615 -       CON_STATE_REQUEST_END, 
1616 -       CON_STATE_READ_POST, 
1617 -       CON_STATE_HANDLE_REQUEST, 
1618 -       CON_STATE_RESPONSE_START, 
1619 -       CON_STATE_WRITE, 
1620 -       CON_STATE_RESPONSE_END, 
1621 -       CON_STATE_ERROR, 
1622 -       CON_STATE_CLOSE 
1623 +typedef enum {
1624 +       CON_STATE_CONNECT,
1625 +       CON_STATE_REQUEST_START,
1626 +       CON_STATE_READ,
1627 +       CON_STATE_REQUEST_END,
1628 +       CON_STATE_READ_POST,
1629 +       CON_STATE_HANDLE_REQUEST,
1630 +       CON_STATE_RESPONSE_START,
1631 +       CON_STATE_WRITE,
1632 +       CON_STATE_RESPONSE_END,
1633 +       CON_STATE_ERROR,
1634 +       CON_STATE_CLOSE
1635  } connection_state_t;
1636  
1637  typedef enum { COND_RESULT_UNSET, COND_RESULT_FALSE, COND_RESULT_TRUE } cond_result_t;
1638 @@ -315,91 +299,86 @@
1639  
1640  typedef struct {
1641         connection_state_t state;
1642 -       
1643 +
1644         /* timestamps */
1645         time_t read_idle_ts;
1646         time_t close_timeout_ts;
1647         time_t write_request_ts;
1648 -       
1649 +
1650         time_t connection_start;
1651         time_t request_start;
1652 -       
1653 +
1654         struct timeval start_tv;
1655 -       
1656 +
1657         size_t request_count;        /* number of requests handled in this connection */
1658         size_t loops_per_request;    /* to catch endless loops in a single request
1659 -                                     * 
1660 +                                     *
1661                                       * used by mod_rewrite, mod_fastcgi, ... and others
1662                                       * this is self-protection
1663                                       */
1664 -       
1665 -       int fd;                      /* the FD for this connection */
1666 -       int fde_ndx;                 /* index for the fdevent-handler */
1667 +
1668 +       iosocket *sock;
1669         int ndx;                     /* reverse mapping to server->connection[ndx] */
1670 -       
1671 +
1672         /* fd states */
1673         int is_readable;
1674         int is_writable;
1675 -       
1676 -       int     keep_alive;           /* only request.c can enable it, all other just disable */
1677 -       
1678 +
1679 +       int     keep_alive;           /* only request.c can enable it, all others just disable */
1680 +
1681         int file_started;
1682         int file_finished;
1683 -       
1684 +
1685         chunkqueue *write_queue;      /* a large queue for low-level write ( HTTP response ) [ file, mem ] */
1686         chunkqueue *read_queue;       /* a small queue for low-level read ( HTTP request ) [ mem ] */
1687         chunkqueue *request_content_queue; /* takes request-content into tempfile if necessary [ tempfile, mem ]*/
1688 -       
1689 +
1690         int traffic_limit_reached;
1691 -       
1692 +
1693         off_t bytes_written;          /* used by mod_accesslog, mod_rrd */
1694         off_t bytes_written_cur_second; /* used by mod_accesslog, mod_rrd */
1695         off_t bytes_read;             /* used by mod_accesslog, mod_rrd */
1696         off_t bytes_header;
1697 -       
1698 +
1699         int http_status;
1700 -       
1701 +
1702         sock_addr dst_addr;
1703         buffer *dst_addr_buf;
1704  
1705         /* request */
1706         buffer *parse_request;
1707         unsigned int parsed_response; /* bitfield which contains the important header-fields of the parsed response header */
1708 -       
1709 +
1710         request  request;
1711         request_uri uri;
1712 -       physical physical; 
1713 +       physical physical;
1714         response response;
1715 -       
1716 +
1717         size_t header_len;
1718 -       
1719 +
1720         buffer *authed_user;
1721         array  *environment; /* used to pass lighttpd internal stuff to the FastCGI/CGI apps, setenv does that */
1722 -       
1723 +
1724         /* response */
1725         int    got_response;
1726 -       
1727 +
1728         int    in_joblist;
1729 -       
1730 +
1731         connection_type mode;
1732 -       
1733 +
1734         void **plugin_ctx;           /* plugin connection specific config */
1735 -       
1736 +
1737         specific_config conf;        /* global connection specific config */
1738         cond_cache_t *cond_cache;
1739 -       
1740 +
1741         buffer *server_name;
1742 -       
1743 +
1744         /* error-handler */
1745         buffer *error_handler;
1746         int error_handler_saved_status;
1747         int in_error_handler;
1748 -       
1749 +
1750         void *srv_socket;   /* reference to the server-socket (typecast to server_socket) */
1751 -       
1752 -#ifdef USE_OPENSSL
1753 -       SSL *ssl;
1754 -#endif
1755  } connection;
1756  
1757  typedef struct {
1758 @@ -439,55 +418,63 @@
1759         size_t size;
1760  } buffer_plugin;
1761  
1762 +typedef enum {
1763 +    NETWORK_STATUS_UNSET,
1764 +    NETWORK_STATUS_SUCCESS,
1765 +    NETWORK_STATUS_FATAL_ERROR,
1766 +    NETWORK_STATUS_CONNECTION_CLOSE,
1767 +    NETWORK_STATUS_WAIT_FOR_EVENT,
1768 +    NETWORK_STATUS_INTERRUPTED
1769 +} network_status_t;
1770 +
1771  typedef struct {
1772         unsigned short port;
1773         buffer *bindhost;
1774 -       
1775 -       buffer *errorlog_file;
1776 -       unsigned short errorlog_use_syslog;
1777 -       
1778 +
1779         unsigned short dont_daemonize;
1780         buffer *changeroot;
1781         buffer *username;
1782         buffer *groupname;
1783 -       
1784 +
1785         buffer *pid_file;
1786 -       
1787 +
1788         buffer *event_handler;
1789 -       
1790 +
1791         buffer *modules_dir;
1792         buffer *network_backend;
1793         array *modules;
1794         array *upload_tempdirs;
1795 -       
1796 +
1797         unsigned short max_worker;
1798         unsigned short max_fds;
1799         unsigned short max_conns;
1800         unsigned short max_request_size;
1801 -       
1802 +
1803         unsigned short log_request_header_on_error;
1804         unsigned short log_state_handling;
1805 -       
1806 -       enum { STAT_CACHE_ENGINE_UNSET, 
1807 -                       STAT_CACHE_ENGINE_NONE, 
1808 -                       STAT_CACHE_ENGINE_SIMPLE, 
1809 -                       STAT_CACHE_ENGINE_FAM 
1810 +
1811 +       enum { STAT_CACHE_ENGINE_UNSET,
1812 +                       STAT_CACHE_ENGINE_NONE,
1813 +                       STAT_CACHE_ENGINE_SIMPLE,
1814 +                       STAT_CACHE_ENGINE_FAM
1815         } stat_cache_engine;
1816         unsigned short enable_cores;
1817 +
1818 +       buffer *errorlog_file;
1819 +       unsigned short errorlog_use_syslog;
1820  } server_config;
1821  
1822  typedef struct {
1823         sock_addr addr;
1824 -       int       fd;
1825 -       int       fde_ndx;
1826 -       
1827 +       iosocket *sock;
1828 +
1829         buffer *ssl_pemfile;
1830         buffer *ssl_ca_file;
1831         unsigned short use_ipv6;
1832         unsigned short is_ssl;
1833 -       
1834 +
1835         buffer *srv_token;
1836 -       
1837 +
1838  #ifdef USE_OPENSSL
1839         SSL_CTX *ssl_ctx;
1840  #endif
1841 @@ -495,37 +482,32 @@
1842  
1843  typedef struct {
1844         server_socket **ptr;
1845 -       
1846 +
1847         size_t size;
1848         size_t used;
1849  } server_socket_array;
1850  
1851  typedef struct server {
1852         server_socket_array srv_sockets;
1853 -       
1854 -       /* the errorlog */
1855 -       int errorlog_fd;
1856 -       enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG } errorlog_mode;
1857 -       buffer *errorlog_buf;
1858 -       
1859 +
1860         fdevents *ev, *ev_ins;
1861 -       
1862 +
1863         buffer_plugin plugins;
1864         void *plugin_slots;
1865 -       
1866 +
1867         /* counters */
1868         int con_opened;
1869         int con_read;
1870         int con_written;
1871         int con_closed;
1872 -       
1873 +
1874         int ssl_is_init;
1875 -       
1876 +
1877         int max_fds;    /* max possible fds */
1878         int cur_fds;    /* currently used fds */
1879         int want_fds;   /* waiting fds */
1880         int sockets_disabled;
1881 -       
1882 +
1883         size_t max_conns;
1884  
1885         /* buffers */
1886 @@ -533,13 +515,13 @@
1887         buffer *response_header;
1888         buffer *response_range;
1889         buffer *tmp_buf;
1890 -       
1891 +
1892         buffer *tmp_chunk_len;
1893 -       
1894 +
1895         buffer *empty_string; /* is necessary for cond_match */
1896  
1897         buffer *cond_check_buf;
1898 -       
1899 +
1900         /* caches */
1901  #ifdef HAVE_IPV6
1902         inet_ntop_cache_type inet_ntop_cache[INET_NTOP_CACHE_MAX];
1903 @@ -547,31 +529,31 @@
1904         mtime_cache_type mtime_cache[FILE_CACHE_MAX];
1905  
1906         array *split_vals;
1907 -       
1908 +
1909         /* Timestamps */
1910         time_t cur_ts;
1911         time_t last_generated_date_ts;
1912         time_t last_generated_debug_ts;
1913         time_t startup_ts;
1914 -       
1915 +
1916         buffer *ts_debug_str;
1917         buffer *ts_date_str;
1918 -       
1919 +
1920         /* config-file */
1921         array *config;
1922         array *config_touched;
1923 -       
1924 +
1925         array *config_context;
1926         specific_config **config_storage;
1927 -       
1928 +
1929         server_config  srvconf;
1930 -       
1931 +
1932         int config_deprecated;
1933 -       
1934 +
1935         connections *conns;
1936         connections *joblist;
1937         connections *fdwaitqueue;
1938 -       
1939 +
1940         stat_cache  *stat_cache;
1941  
1942         /**
1943 @@ -588,18 +570,20 @@
1944          *   fastcgi.backend.<key>.disconnects = ...
1945          */
1946         array *status;
1947 -       
1948 +
1949         fdevent_handler_t event_handler;
1950  
1951 -       int (* network_backend_write)(struct server *srv, connection *con, int fd, chunkqueue *cq);
1952 -       int (* network_backend_read)(struct server *srv, connection *con, int fd, chunkqueue *cq);
1953 +       network_status_t (* network_backend_write)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1954 +       network_status_t (* network_backend_read)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1955  #ifdef USE_OPENSSL
1956 -       int (* network_ssl_backend_write)(struct server *srv, connection *con, SSL *ssl, chunkqueue *cq);
1957 -       int (* network_ssl_backend_read)(struct server *srv, connection *con, SSL *ssl, chunkqueue *cq);
1958 +       network_status_t (* network_ssl_backend_write)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1959 +       network_status_t (* network_ssl_backend_read)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1960  #endif
1961  
1962 +#ifdef HAVE_PWD_H
1963         uid_t uid;
1964         gid_t gid;
1965 +#endif
1966  } server;
1967  
1968  
1969 --- ../lighttpd-1.4.11/src/bitset.c     2005-08-22 01:54:12.000000000 +0300
1970 +++ lighttpd-1.4.12/src/bitset.c        2006-07-18 13:03:40.000000000 +0300
1971 @@ -6,6 +6,7 @@
1972  
1973  #include "bitset.h"
1974  #include "buffer.h"
1975 +#include "log.h"
1976  
1977  #define BITSET_BITS \
1978         ( CHAR_BIT * sizeof(size_t) )
1979 --- ../lighttpd-1.4.11/src/buffer.c     2006-01-13 00:00:45.000000000 +0200
1980 +++ lighttpd-1.4.12/src/buffer.c        2006-07-18 13:03:40.000000000 +0300
1981 @@ -12,20 +12,20 @@
1982  
1983  
1984  /**
1985 - * init the buffer 
1986 - * 
1987 + * init the buffer
1988 + *
1989   */
1990  
1991  buffer* buffer_init(void) {
1992         buffer *b;
1993 -       
1994 +
1995         b = malloc(sizeof(*b));
1996         assert(b);
1997 -       
1998 +
1999         b->ptr = NULL;
2000         b->size = 0;
2001         b->used = 0;
2002 -       
2003 +
2004         return b;
2005  }
2006  
2007 @@ -36,8 +36,8 @@
2008  }
2009  
2010  /**
2011 - * free the buffer 
2012 - * 
2013 + * free the buffer
2014 + *
2015   */
2016  
2017  void buffer_free(buffer *b) {
2018 @@ -49,39 +49,39 @@
2019  
2020  void buffer_reset(buffer *b) {
2021         if (!b) return;
2022 -       
2023 +
2024         /* limit don't reuse buffer larger than ... bytes */
2025         if (b->size > BUFFER_MAX_REUSE_SIZE) {
2026                 free(b->ptr);
2027                 b->ptr = NULL;
2028                 b->size = 0;
2029         }
2030 -       
2031 +
2032         b->used = 0;
2033  }
2034  
2035  
2036  /**
2037 - * 
2038 - * allocate (if neccessary) enough space for 'size' bytes and 
2039 + *
2040 + * allocate (if necessary) enough space for 'size' bytes and
2041   * set the 'used' counter to 0
2042 - * 
2043 + *
2044   */
2045  
2046  #define BUFFER_PIECE_SIZE 64
2047  
2048  int buffer_prepare_copy(buffer *b, size_t size) {
2049         if (!b) return -1;
2050 -       
2051 -       if ((0 == b->size) || 
2052 +
2053 +       if ((0 == b->size) ||
2054             (size > b->size)) {
2055                 if (b->size) free(b->ptr);
2056 -               
2057 +
2058                 b->size = size;
2059 -               
2060 -               /* always allocate a multiply of BUFFER_PIECE_SIZE */
2061 +
2062 +               /* always allocate a multiple of BUFFER_PIECE_SIZE */
2063                 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2064 -               
2065 +
2066                 b->ptr = malloc(b->size);
2067                 assert(b->ptr);
2068         }
2069 @@ -90,30 +90,30 @@
2070  }
2071  
2072  /**
2073 - * 
2074 - * increase the internal buffer (if neccessary) to append another 'size' byte
2075 + *
2076 + * increase the internal buffer (if necessary) to append another 'size' byte
2077   * ->used isn't changed
2078 - * 
2079 + *
2080   */
2081  
2082  int buffer_prepare_append(buffer *b, size_t size) {
2083         if (!b) return -1;
2084 -       
2085 +
2086         if (0 == b->size) {
2087                 b->size = size;
2088 -               
2089 -               /* always allocate a multiply of BUFFER_PIECE_SIZE */
2090 +
2091 +               /* always allocate a multiple of BUFFER_PIECE_SIZE */
2092                 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2093 -               
2094 +
2095                 b->ptr = malloc(b->size);
2096                 b->used = 0;
2097                 assert(b->ptr);
2098         } else if (b->used + size > b->size) {
2099                 b->size += size;
2100 -               
2101 -               /* always allocate a multiply of BUFFER_PIECE_SIZE */
2102 +
2103 +               /* always allocate a multiple of BUFFER_PIECE_SIZE */
2104                 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2105 -               
2106 +
2107                 b->ptr = realloc(b->ptr, b->size);
2108                 assert(b->ptr);
2109         }
2110 @@ -122,7 +122,7 @@
2111  
2112  int buffer_copy_string(buffer *b, const char *s) {
2113         size_t s_len;
2114 -       
2115 +
2116         if (!s || !b) return -1;
2117  
2118         s_len = strlen(s) + 1;
2119 @@ -136,26 +136,26 @@
2120  
2121  int buffer_copy_string_len(buffer *b, const char *s, size_t s_len) {
2122         if (!s || !b) return -1;
2123 -#if 0  
2124 -       /* removed optimization as we have to keep the empty string 
2125 +#if 0
2126 +       /* removed optimization as we have to keep the empty string
2127          * in some cases for the config handling
2128 -        * 
2129 +        *
2130          * url.access-deny = ( "" )
2131          */
2132         if (s_len == 0) return 0;
2133 -#endif 
2134 +#endif
2135         buffer_prepare_copy(b, s_len + 1);
2136 -       
2137 +
2138         memcpy(b->ptr, s, s_len);
2139         b->ptr[s_len] = '\0';
2140         b->used = s_len + 1;
2141 -       
2142 +
2143         return 0;
2144  }
2145  
2146  int buffer_copy_string_buffer(buffer *b, const buffer *src) {
2147         if (!src) return -1;
2148 -       
2149 +
2150         if (src->used == 0) {
2151                 b->used = 0;
2152                 return 0;
2153 @@ -201,10 +201,10 @@
2154  
2155  /**
2156   * append a string to the end of the buffer
2157 - * 
2158 - * the resulting buffer is terminated with a '\0' 
2159 - * s is treated as a un-terminated string (a \0 is handled a normal character)
2160 - * 
2161 + *
2162 + * the resulting buffer is terminated with a '\0'
2163 + * s is treated as an un-terminated string (a \0 is handled as a normal character)
2164 + *
2165   * @param b a buffer
2166   * @param s the string
2167   * @param s_len size of the string (without the terminating \0)
2168 @@ -228,7 +228,7 @@
2169  int buffer_append_string_buffer(buffer *b, const buffer *src) {
2170         if (!src) return -1;
2171         if (src->used == 0) return 0;
2172 -       
2173 +
2174         return buffer_append_string_len(b, src->ptr, src->used - 1);
2175  }
2176  
2177 @@ -245,9 +245,9 @@
2178  
2179  int buffer_copy_memory(buffer *b, const char *s, size_t s_len) {
2180         if (!s || !b) return -1;
2181 -       
2182 +
2183         b->used = 0;
2184 -       
2185 +
2186         return buffer_append_memory(b, s, s_len);
2187  }
2188  
2189 @@ -402,46 +402,115 @@
2190  
2191  
2192  /**
2193 - * init the buffer 
2194 - * 
2195 + * init the ptr buffer
2196 + *
2197 + */
2198 +buffer_ptr *buffer_ptr_init(buffer_ptr_free_t freer)
2199 +{
2200 +       buffer_ptr *l = calloc(1, sizeof(buffer_ptr));
2201 +       l->free = freer;
2202 +
2203 +       return l;
2204 +}
2205 +
2206 +/**
2207 + * free the buffer_array
2208 + *
2209 + */
2210 +void buffer_ptr_free(buffer_ptr *l)
2211 +{
2212 +       if (NULL != l) {
2213 +               buffer_ptr_clear(l);
2214 +               free(l);
2215 +       }
2216 +}
2217 +
2218 +void buffer_ptr_clear(buffer_ptr *l)
2219 +{
2220 +       assert(NULL != l);
2221 +
2222 +       if (l->free && l->used) {
2223 +               size_t i;
2224 +               for (i = 0; i < l->used; i ++) {
2225 +                       l->free(l->ptr[i]);
2226 +               }
2227 +       }
2228 +
2229 +       if (l->ptr) {
2230 +               free(l->ptr);
2231 +               l->ptr = NULL;
2232 +       }
2233 +       l->used = 0;
2234 +       l->size = 0;
2235 +}
2236 +
2237 +void buffer_ptr_append(buffer_ptr* l, void *item)
2238 +{
2239 +       assert(NULL != l);
2240 +       if (l->ptr == NULL) {
2241 +               l->size = 16;
2242 +               l->ptr = (void **)malloc(sizeof(void *) * l->size);
2243 +       }
2244 +       else if (l->used == l->size) {
2245 +               l->size += 16;
2246 +               l->ptr = realloc(l->ptr, sizeof(void *) * l->size);
2247 +       }
2248 +       l->ptr[l->used++] = item;
2249 +}
2250 +
2251 +void *buffer_ptr_pop(buffer_ptr* l)
2252 +{
2253 +       assert(NULL != l && l->used > 0);
2254 +       return l->ptr[--l->used];
2255 +}
2256 +
2257 +void *buffer_ptr_top(buffer_ptr* l)
2258 +{
2259 +       assert(NULL != l && l->used > 0);
2260 +       return l->ptr[l->used-1];
2261 +}
2262 +
2263 +/**
2264 + * init the buffer
2265 + *
2266   */
2267  
2268  buffer_array* buffer_array_init(void) {
2269         buffer_array *b;
2270 -       
2271 +
2272         b = malloc(sizeof(*b));
2273 -       
2274 +
2275         assert(b);
2276         b->ptr = NULL;
2277         b->size = 0;
2278         b->used = 0;
2279 -       
2280 +
2281         return b;
2282  }
2283  
2284  void buffer_array_reset(buffer_array *b) {
2285         size_t i;
2286 -       
2287 +
2288         if (!b) return;
2289 -       
2290 +
2291         /* if they are too large, reduce them */
2292         for (i = 0; i < b->used; i++) {
2293                 buffer_reset(b->ptr[i]);
2294         }
2295 -       
2296 +
2297         b->used = 0;
2298  }
2299  
2300  
2301  /**
2302 - * free the buffer_array 
2303 - * 
2304 + * free the buffer_array
2305 + *
2306   */
2307  
2308  void buffer_array_free(buffer_array *b) {
2309         size_t i;
2310         if (!b) return;
2311 -       
2312 +
2313         for (i = 0; i < b->size; i++) {
2314                 if (b->ptr[i]) buffer_free(b->ptr[i]);
2315         }
2316 @@ -451,7 +520,7 @@
2317  
2318  buffer *buffer_array_append_get_buffer(buffer_array *b) {
2319         size_t i;
2320 -       
2321 +
2322         if (b->size == 0) {
2323                 b->size = 16;
2324                 b->ptr = malloc(sizeof(*b->ptr) * b->size);
2325 @@ -467,13 +536,13 @@
2326                         b->ptr[i] = NULL;
2327                 }
2328         }
2329 -       
2330 +
2331         if (b->ptr[b->used] == NULL) {
2332                 b->ptr[b->used] = buffer_init();
2333         }
2334 -       
2335 +
2336         b->ptr[b->used]->used = 0;
2337 -       
2338 +
2339         return b->ptr[b->used++];
2340  }
2341  
2342 @@ -482,23 +551,23 @@
2343         size_t i;
2344         if (len == 0) return NULL;
2345         if (needle == NULL) return NULL;
2346 -       
2347 +
2348         if (b->used < len) return NULL;
2349 -       
2350 +
2351         for(i = 0; i < b->used - len; i++) {
2352                 if (0 == memcmp(b->ptr + i, needle, len)) {
2353                         return b->ptr + i;
2354                 }
2355         }
2356 -       
2357 +
2358         return NULL;
2359  }
2360  
2361  buffer *buffer_init_string(const char *str) {
2362         buffer *b = buffer_init();
2363 -       
2364 +
2365         buffer_copy_string(b, str);
2366 -       
2367 +
2368         return b;
2369  }
2370  
2371 @@ -507,8 +576,8 @@
2372  }
2373  
2374  /**
2375 - * check if two buffer contain the same data
2376 - * 
2377 + * check if two buffers contain the same data
2378 + *
2379   * HISTORY: this function was pretty much optimized, but didn't handled
2380   * alignment properly.
2381   */
2382 @@ -517,105 +586,105 @@
2383         if (a->used != b->used) return 0;
2384         if (a->used == 0) return 1;
2385  
2386 -       return (0 == strcmp(a->ptr, b->ptr));
2387 +       return (0 == strncmp(a->ptr, b->ptr, a->used - 1));
2388  }
2389  
2390  int buffer_is_equal_string(buffer *a, const char *s, size_t b_len) {
2391         buffer b;
2392 -       
2393 +
2394         b.ptr = (char *)s;
2395         b.used = b_len + 1;
2396 -       
2397 +
2398         return buffer_is_equal(a, &b);
2399  }
2400  
2401  /* simple-assumption:
2402 - * 
2403 - * most parts are equal and doing a case conversion needs time
2404 - * 
2405 + *
2406 + * most parts are equal and doing a case conversion takes time
2407 + *
2408   */
2409  int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b_len) {
2410         size_t ndx = 0, max_ndx;
2411         size_t *al, *bl;
2412         size_t mask = sizeof(*al) - 1;
2413 -       
2414 +
2415         al = (size_t *)a;
2416         bl = (size_t *)b;
2417 -       
2418 -       /* is the alignment correct ? */
2419 +
2420 +       /* is the alignment correct? */
2421         if ( ((size_t)al & mask) == 0 &&
2422              ((size_t)bl & mask) == 0 ) {
2423 -               
2424 +
2425                 max_ndx = ((a_len < b_len) ? a_len : b_len) & ~mask;
2426 -               
2427 +
2428                 for (; ndx < max_ndx; ndx += sizeof(*al)) {
2429                         if (*al != *bl) break;
2430                         al++; bl++;
2431 -                       
2432 +
2433                 }
2434 -               
2435 +
2436         }
2437 -       
2438 +
2439         a = (char *)al;
2440         b = (char *)bl;
2441 -       
2442 +
2443         max_ndx = ((a_len < b_len) ? a_len : b_len);
2444 -       
2445 +
2446         for (; ndx < max_ndx; ndx++) {
2447                 char a1 = *a++, b1 = *b++;
2448 -               
2449 +
2450                 if (a1 != b1) {
2451                         if ((a1 >= 'A' && a1 <= 'Z') && (b1 >= 'a' && b1 <= 'z'))
2452                                 a1 |= 32;
2453                         else if ((a1 >= 'a' && a1 <= 'z') && (b1 >= 'A' && b1 <= 'Z'))
2454                                 b1 |= 32;
2455                         if ((a1 - b1) != 0) return (a1 - b1);
2456 -                       
2457 +
2458                 }
2459         }
2460 -       
2461 +
2462         return 0;
2463  }
2464  
2465  
2466  /**
2467   * check if the rightmost bytes of the string are equal.
2468 - * 
2469 - * 
2470 + *
2471 + *
2472   */
2473  
2474  int buffer_is_equal_right_len(buffer *b1, buffer *b2, size_t len) {
2475         /* no, len -> equal */
2476         if (len == 0) return 1;
2477 -       
2478 +
2479         /* len > 0, but empty buffers -> not equal */
2480         if (b1->used == 0 || b2->used == 0) return 0;
2481 -       
2482 +
2483         /* buffers too small -> not equal */
2484 -       if (b1->used - 1 < len || b1->used - 1 < len) return 0;
2485 -       
2486 -       if (0 == strncmp(b1->ptr + b1->used - 1 - len, 
2487 +       if (b1->used - 1 < len || b2->used - 1 < len) return 0;
2488 +
2489 +       if (0 == strncmp(b1->ptr + b1->used - 1 - len,
2490                          b2->ptr + b2->used - 1 - len, len)) {
2491                 return 1;
2492         }
2493 -       
2494 +
2495         return 0;
2496  }
2497  
2498  int buffer_copy_string_hex(buffer *b, const char *in, size_t in_len) {
2499         size_t i;
2500 -       
2501 +
2502         /* BO protection */
2503         if (in_len * 2 < in_len) return -1;
2504 -       
2505 +
2506         buffer_prepare_copy(b, in_len * 2 + 1);
2507 -       
2508 +
2509         for (i = 0; i < in_len; i++) {
2510                 b->ptr[b->used++] = hex_chars[(in[i] >> 4) & 0x0F];
2511                 b->ptr[b->used++] = hex_chars[in[i] & 0x0F];
2512         }
2513         b->ptr[b->used++] = '\0';
2514 -       
2515 +
2516         return 0;
2517  }
2518  
2519 @@ -624,7 +693,7 @@
2520         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2521         */
2522         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2523 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2524 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2525         1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1,  /*  20 -  2F space " # $ % & ' + , / */
2526         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,  /*  30 -  3F : ; = ? @ < > */
2527         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
2528 @@ -646,7 +715,7 @@
2529         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2530         */
2531         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2532 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2533 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2534         1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0,  /*  20 -  2F space " # $ % & ' + , / */
2535         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,  /*  30 -  3F : ; = ? @ < > */
2536         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
2537 @@ -668,7 +737,7 @@
2538         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2539         */
2540         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2541 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2542 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2543         0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  20 -  2F & */
2544         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,  /*  30 -  3F < > */
2545         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
2546 @@ -690,7 +759,7 @@
2547         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2548         */
2549         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2550 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2551 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2552         0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  20 -  2F & */
2553         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,  /*  30 -  3F < > */
2554         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
2555 @@ -712,12 +781,12 @@
2556         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2557         */
2558         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2559 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2560 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  20 -  2F */ 
2561 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  30 -  3F */ 
2562 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  40 -  4F */ 
2563 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  50 -  5F */ 
2564 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  60 -  6F */ 
2565 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2566 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  20 -  2F */
2567 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  30 -  3F */
2568 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  40 -  4F */
2569 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  50 -  5F */
2570 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  60 -  6F */
2571         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  70 -  7F */
2572         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */
2573         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  90 -  9F */
2574 @@ -734,13 +803,12 @@
2575         unsigned char *ds, *d;
2576         size_t d_len, ndx;
2577         const char *map = NULL;
2578 -       
2579 +
2580         if (!s || !b) return -1;
2581 -       
2582 -       if (b->ptr[b->used - 1] != '\0') {
2583 -               SEGFAULT();
2584 -       }
2585 -       
2586 +       if (b->used == 0) return -1;
2587 +
2588 +       if (b->ptr[b->used - 1] != '\0') return -1;
2589 +
2590         if (s_len == 0) return 0;
2591  
2592         switch(encoding) {
2593 @@ -760,12 +828,12 @@
2594                 map = encoded_chars_hex;
2595                 break;
2596         case ENCODING_UNSET:
2597 -               break;
2598 +               return buffer_append_string_len(b, s, s_len);
2599         }
2600  
2601         assert(map != NULL);
2602 -       
2603 -       /* count to-be-encoded-characters */
2604 +
2605 +       /* count to-be-encoded characters */
2606         for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
2607                 if (map[*ds]) {
2608                         switch(encoding) {
2609 @@ -787,9 +855,9 @@
2610                         d_len ++;
2611                 }
2612         }
2613 -       
2614 +
2615         buffer_prepare_append(b, d_len);
2616 -       
2617 +
2618         for (ds = (unsigned char *)s, d = (unsigned char *)b->ptr + b->used - 1, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
2619                 if (map[*ds]) {
2620                         switch(encoding) {
2621 @@ -820,16 +888,16 @@
2622                 }
2623         }
2624  
2625 -       /* terminate buffer and calculate new length */ 
2626 +       /* terminate buffer and calculate new length */
2627         b->ptr[b->used + d_len - 1] = '\0';
2628 -       
2629 +
2630         b->used += d_len;
2631  
2632         return 0;
2633  }
2634  
2635  
2636 -/* decodes url-special-chars inplace.
2637 +/* decodes url-special chars in-place.
2638   * replaces non-printable characters with '_'
2639   */
2640  
2641 @@ -854,10 +922,10 @@
2642                                 low = hex2int(*(src + 2));
2643                                 if (low != 0xFF) {
2644                                         high = (high << 4) | low;
2645 -                                       
2646 -                                       /* map control-characters out */        
2647 +
2648 +                                       /* map out control characters */
2649                                         if (high < 32 || high == 127) high = '_';
2650 -                                       
2651 +
2652                                         *dst = high;
2653                                         src += 2;
2654                                 }
2655 @@ -891,7 +959,7 @@
2656   * /abc/./xyz       gets  /abc/xyz
2657   * /abc//xyz        gets  /abc/xyz
2658   *
2659 - * NOTE: src and dest can point to the same buffer, in which case,
2660 + * NOTE: src and dest can point to the same buffer, in which case
2661   *       the operation is performed in-place.
2662   */
2663  
2664 @@ -979,7 +1047,7 @@
2665  
2666  int light_isxdigit(int c) {
2667         if (light_isdigit(c)) return 1;
2668 -       
2669 +
2670         c |= 32;
2671         return (c >= 'a' && c <= 'f');
2672  }
2673 @@ -993,31 +1061,56 @@
2674         return light_isdigit(c) || light_isalpha(c);
2675  }
2676  
2677 +#undef BUFFER_CTYPE_FUNC
2678 +#define BUFFER_CTYPE_FUNC(type) \
2679 +       int buffer_is##type(buffer *b) { \
2680 +               size_t i, len; \
2681 +               if (b->used < 2) return 0; \
2682 +               /* strlen */ \
2683 +               len = b->used - 1; \
2684 +               /* c-string only */ \
2685 +               if (b->ptr[len] != '\0') { \
2686 +                       return 0; \
2687 +               } \
2688 +               /* check on the whole string */ \
2689 +               for (i = 0; i < len; i ++) { \
2690 +                       if (!light_is##type(b->ptr[i])) { \
2691 +                               return 0; \
2692 +                       } \
2693 +               } \
2694 +               return 1; \
2695 +       }
2696 +
2697 +BUFFER_CTYPE_FUNC(digit)
2698 +BUFFER_CTYPE_FUNC(xdigit)
2699 +BUFFER_CTYPE_FUNC(alpha)
2700 +BUFFER_CTYPE_FUNC(alnum)
2701 +
2702  int buffer_to_lower(buffer *b) {
2703         char *c;
2704 -       
2705 +
2706         if (b->used == 0) return 0;
2707 -       
2708 +
2709         for (c = b->ptr; *c; c++) {
2710                 if (*c >= 'A' && *c <= 'Z') {
2711                         *c |= 32;
2712                 }
2713         }
2714 -       
2715 +
2716         return 0;
2717  }
2718  
2719  
2720  int buffer_to_upper(buffer *b) {
2721         char *c;
2722 -       
2723 +
2724         if (b->used == 0) return 0;
2725 -       
2726 +
2727         for (c = b->ptr; *c; c++) {
2728                 if (*c >= 'a' && *c <= 'z') {
2729                         *c &= ~32;
2730                 }
2731         }
2732 -       
2733 +
2734         return 0;
2735  }
2736 --- ../lighttpd-1.4.11/src/buffer.h     2006-01-13 00:00:45.000000000 +0200
2737 +++ lighttpd-1.4.12/src/buffer.h        2006-07-18 13:03:40.000000000 +0300
2738 @@ -12,27 +12,43 @@
2739  
2740  typedef struct {
2741         char *ptr;
2742 -       
2743 +
2744         size_t used;
2745         size_t size;
2746  } buffer;
2747  
2748 +typedef void (*buffer_ptr_free_t)(void *p);
2749 +
2750 +typedef struct {
2751 +       void **ptr;
2752 +       size_t size;
2753 +       size_t used;
2754 +       buffer_ptr_free_t free;
2755 +} buffer_ptr;
2756 +
2757  typedef struct {
2758         buffer **ptr;
2759 -       
2760 +
2761         size_t used;
2762         size_t size;
2763  } buffer_array;
2764  
2765  typedef struct {
2766         char *ptr;
2767 -       
2768 -       size_t offset; /* input-pointer */
2769 -       
2770 -       size_t used;   /* output-pointer */
2771 +
2772 +       size_t offset; /* input pointer */
2773 +
2774 +       size_t used;   /* output pointer */
2775         size_t size;
2776  } read_buffer;
2777  
2778 +buffer_ptr *buffer_ptr_init(buffer_ptr_free_t freer);
2779 +void buffer_ptr_free(buffer_ptr *b);
2780 +void buffer_ptr_clear(buffer_ptr *b);
2781 +void buffer_ptr_append(buffer_ptr *b, void *item);
2782 +void *buffer_ptr_pop(buffer_ptr *b);
2783 +void *buffer_ptr_top(buffer_ptr *b);
2784 +
2785  buffer_array* buffer_array_init(void);
2786  void buffer_array_free(buffer_array *b);
2787  void buffer_array_reset(buffer_array *b);
2788 @@ -43,7 +59,7 @@
2789  buffer* buffer_init_string(const char *str);
2790  void buffer_free(buffer *b);
2791  void buffer_reset(buffer *b);
2792 -       
2793 +
2794  int buffer_prepare_copy(buffer *b, size_t size);
2795  int buffer_prepare_append(buffer *b, size_t size);
2796  
2797 @@ -85,9 +101,9 @@
2798  
2799  typedef enum {
2800         ENCODING_UNSET,
2801 -       ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of a href */
2802 -       ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus coding / too as %2F */
2803 -       ENCODING_HTML,    /* & becomes &amp; and so on */
2804 +       ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of an href */
2805 +       ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus encoding "/" as "%2F" */
2806 +       ENCODING_HTML,    /* "&" becomes "&amp;" and so on */
2807         ENCODING_MINIMAL_XML, /* minimal encoding for xml */
2808         ENCODING_HEX      /* encode string as hex */
2809  } buffer_encoding_t;
2810 @@ -111,20 +127,23 @@
2811  int light_isalpha(int c);
2812  int light_isalnum(int c);
2813  
2814 +#define BUFFER_CTYPE_FUNC(type) int buffer_is##type(buffer *b);
2815 +BUFFER_CTYPE_FUNC(digit)
2816 +BUFFER_CTYPE_FUNC(xdigit)
2817 +BUFFER_CTYPE_FUNC(alpha)
2818 +BUFFER_CTYPE_FUNC(alnum)
2819 +
2820 +#define BUF_STR(x) x->ptr
2821  #define BUFFER_APPEND_STRING_CONST(x, y) \
2822         buffer_append_string_len(x, y, sizeof(y) - 1)
2823  
2824  #define BUFFER_COPY_STRING_CONST(x, y) \
2825         buffer_copy_string_len(x, y, sizeof(y) - 1)
2826  
2827 -#define BUFFER_APPEND_SLASH(x) \
2828 -       if (x->used > 1 && x->ptr[x->used - 2] != '/') { BUFFER_APPEND_STRING_CONST(x, "/"); }
2829 -
2830  #define CONST_STR_LEN(x) x, x ? sizeof(x) - 1 : 0
2831 -#define CONST_BUF_LEN(x) x->ptr, x->used ? x->used - 1 : 0
2832 +#define CONST_BUF_LEN(x) BUF_STR(x), x->used ? x->used - 1 : 0
2833  
2834 -
2835 -#define SEGFAULT() do { fprintf(stderr, "%s.%d: aborted\n", __FILE__, __LINE__); abort(); } while(0)
2836 +       
2837  #define UNUSED(x) ( (void)(x) )
2838  
2839  #endif
2840 --- ../lighttpd-1.4.11/src/chunk.c      2005-11-18 15:18:19.000000000 +0200
2841 +++ lighttpd-1.4.12/src/chunk.c 2006-07-18 13:03:40.000000000 +0300
2842 @@ -1,16 +1,14 @@
2843  /**
2844   * the network chunk-API
2845 - * 
2846 - * 
2847 + *
2848 + *
2849   */
2850  
2851  #include <sys/types.h>
2852  #include <sys/stat.h>
2853 -#include <sys/mman.h>
2854  
2855  #include <stdlib.h>
2856  #include <fcntl.h>
2857 -#include <unistd.h>
2858  
2859  #include <stdio.h>
2860  #include <errno.h>
2861 @@ -18,36 +16,39 @@
2862  
2863  #include "chunk.h"
2864  
2865 +#include "sys-mmap.h"
2866 +#include "sys-files.h"
2867 +
2868  chunkqueue *chunkqueue_init(void) {
2869         chunkqueue *cq;
2870 -       
2871 +
2872         cq = calloc(1, sizeof(*cq));
2873 -       
2874 +
2875         cq->first = NULL;
2876         cq->last = NULL;
2877 -       
2878 +
2879         cq->unused = NULL;
2880 -       
2881 +
2882         return cq;
2883  }
2884  
2885  static chunk *chunk_init(void) {
2886         chunk *c;
2887 -       
2888 +
2889         c = calloc(1, sizeof(*c));
2890 -       
2891 +
2892         c->mem = buffer_init();
2893         c->file.name = buffer_init();
2894         c->file.fd = -1;
2895         c->file.mmap.start = MAP_FAILED;
2896         c->next = NULL;
2897 -       
2898 +
2899         return c;
2900  }
2901  
2902  static void chunk_free(chunk *c) {
2903         if (!c) return;
2904 -       
2905 +
2906         buffer_free(c->mem);
2907         buffer_free(c->file.name);
2908  
2909 @@ -56,13 +57,13 @@
2910  
2911  static void chunk_reset(chunk *c) {
2912         if (!c) return;
2913 -       
2914 +
2915         buffer_reset(c->mem);
2916  
2917         if (c->file.is_temp && !buffer_is_empty(c->file.name)) {
2918                 unlink(c->file.name->ptr);
2919         }
2920 -       
2921 +
2922         buffer_reset(c->file.name);
2923  
2924         if (c->file.fd != -1) {
2925 @@ -78,28 +79,28 @@
2926  
2927  void chunkqueue_free(chunkqueue *cq) {
2928         chunk *c, *pc;
2929 -       
2930 +
2931         if (!cq) return;
2932 -       
2933 +
2934         for (c = cq->first; c; ) {
2935                 pc = c;
2936                 c = c->next;
2937                 chunk_free(pc);
2938         }
2939 -       
2940 +
2941         for (c = cq->unused; c; ) {
2942                 pc = c;
2943                 c = c->next;
2944                 chunk_free(pc);
2945         }
2946 -       
2947 +
2948         free(cq);
2949  }
2950  
2951  static chunk *chunkqueue_get_unused_chunk(chunkqueue *cq) {
2952         chunk *c;
2953 -       
2954 -       /* check if we have a unused chunk */
2955 +
2956 +       /* check if we have an unused chunk */
2957         if (!cq->unused) {
2958                 c = chunk_init();
2959         } else {
2960 @@ -109,18 +110,18 @@
2961                 c->next = NULL;
2962                 cq->unused_chunks--;
2963         }
2964 -       
2965 +
2966         return c;
2967  }
2968  
2969  static int chunkqueue_prepend_chunk(chunkqueue *cq, chunk *c) {
2970         c->next = cq->first;
2971         cq->first = c;
2972 -       
2973 +
2974         if (cq->last == NULL) {
2975                 cq->last = c;
2976         }
2977 -       
2978 +
2979         return 0;
2980  }
2981  
2982 @@ -129,19 +130,19 @@
2983                 cq->last->next = c;
2984         }
2985         cq->last = c;
2986 -       
2987 +
2988         if (cq->first == NULL) {
2989                 cq->first = c;
2990         }
2991 -       
2992 +
2993         return 0;
2994  }
2995  
2996  void chunkqueue_reset(chunkqueue *cq) {
2997         chunk *c;
2998         /* move everything to the unused queue */
2999 -       
3000 -       /* mark all read written */ 
3001 +
3002 +       /* mark all read written */
3003         for (c = cq->first; c; c = c->next) {
3004                 switch(c->type) {
3005                 case MEM_CHUNK:
3006 @@ -150,7 +151,7 @@
3007                 case FILE_CHUNK:
3008                         c->offset = c->file.length;
3009                         break;
3010 -               default: 
3011 +               default:
3012                         break;
3013                 }
3014         }
3015 @@ -162,93 +163,93 @@
3016  
3017  int chunkqueue_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len) {
3018         chunk *c;
3019 -       
3020 +
3021         if (len == 0) return 0;
3022 -       
3023 +
3024         c = chunkqueue_get_unused_chunk(cq);
3025 -       
3026 +
3027         c->type = FILE_CHUNK;
3028 -       
3029 +
3030         buffer_copy_string_buffer(c->file.name, fn);
3031         c->file.start = offset;
3032         c->file.length = len;
3033         c->offset = 0;
3034 -       
3035 +
3036         chunkqueue_append_chunk(cq, c);
3037 -       
3038 +
3039         return 0;
3040  }
3041  
3042  int chunkqueue_append_buffer(chunkqueue *cq, buffer *mem) {
3043         chunk *c;
3044 -       
3045 +
3046         if (mem->used == 0) return 0;
3047 -       
3048 +
3049         c = chunkqueue_get_unused_chunk(cq);
3050         c->type = MEM_CHUNK;
3051         c->offset = 0;
3052         buffer_copy_string_buffer(c->mem, mem);
3053 -       
3054 +
3055         chunkqueue_append_chunk(cq, c);
3056 -       
3057 +
3058         return 0;
3059  }
3060  
3061  int chunkqueue_prepend_buffer(chunkqueue *cq, buffer *mem) {
3062         chunk *c;
3063 -       
3064 +
3065         if (mem->used == 0) return 0;
3066 -       
3067 +
3068         c = chunkqueue_get_unused_chunk(cq);
3069         c->type = MEM_CHUNK;
3070         c->offset = 0;
3071         buffer_copy_string_buffer(c->mem, mem);
3072 -       
3073 +
3074         chunkqueue_prepend_chunk(cq, c);
3075 -       
3076 +
3077         return 0;
3078  }
3079  
3080  int chunkqueue_append_mem(chunkqueue *cq, const char * mem, size_t len) {
3081         chunk *c;
3082 -       
3083 +
3084         if (len == 0) return 0;
3085 -       
3086 +
3087         c = chunkqueue_get_unused_chunk(cq);
3088         c->type = MEM_CHUNK;
3089         c->offset = 0;
3090         buffer_copy_string_len(c->mem, mem, len - 1);
3091 -       
3092 +
3093         chunkqueue_append_chunk(cq, c);
3094 -       
3095 +
3096         return 0;
3097  }
3098  
3099  buffer * chunkqueue_get_prepend_buffer(chunkqueue *cq) {
3100         chunk *c;
3101 -       
3102 +
3103         c = chunkqueue_get_unused_chunk(cq);
3104 -       
3105 +
3106         c->type = MEM_CHUNK;
3107         c->offset = 0;
3108         buffer_reset(c->mem);
3109 -       
3110 +
3111         chunkqueue_prepend_chunk(cq, c);
3112 -       
3113 +
3114         return c->mem;
3115  }
3116  
3117  buffer *chunkqueue_get_append_buffer(chunkqueue *cq) {
3118         chunk *c;
3119 -       
3120 +
3121         c = chunkqueue_get_unused_chunk(cq);
3122 -       
3123 +
3124         c->type = MEM_CHUNK;
3125         c->offset = 0;
3126         buffer_reset(c->mem);
3127 -       
3128 +
3129         chunkqueue_append_chunk(cq, c);
3130 -       
3131 +
3132         return c->mem;
3133  }
3134  
3135 @@ -263,7 +264,7 @@
3136  chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) {
3137         chunk *c;
3138         buffer *template = buffer_init_string("/var/tmp/lighttpd-upload-XXXXXX");
3139 -       
3140 +
3141         c = chunkqueue_get_unused_chunk(cq);
3142  
3143         c->type = FILE_CHUNK;
3144 @@ -273,12 +274,12 @@
3145                 size_t i;
3146  
3147                 /* we have several tempdirs, only if all of them fail we jump out */
3148 -               
3149 +
3150                 for (i = 0; i < cq->tempdirs->used; i++) {
3151                         data_string *ds = (data_string *)cq->tempdirs->data[i];
3152  
3153                         buffer_copy_string_buffer(template, ds->value);
3154 -                       BUFFER_APPEND_SLASH(template);
3155 +                       PATHNAME_APPEND_SLASH(template);
3156                         BUFFER_APPEND_STRING_CONST(template, "lighttpd-upload-XXXXXX");
3157  
3158                         if (-1 != (c->file.fd = mkstemp(template->ptr))) {
3159 @@ -300,7 +301,7 @@
3160         chunkqueue_append_chunk(cq, c);
3161  
3162         buffer_free(template);
3163 -       
3164 +
3165         return c;
3166  }
3167  
3168 @@ -308,7 +309,7 @@
3169  off_t chunkqueue_length(chunkqueue *cq) {
3170         off_t len = 0;
3171         chunk *c;
3172 -       
3173 +
3174         for (c = cq->first; c; c = c->next) {
3175                 switch (c->type) {
3176                 case MEM_CHUNK:
3177 @@ -321,14 +322,14 @@
3178                         break;
3179                 }
3180         }
3181 -       
3182 +
3183         return len;
3184  }
3185  
3186  off_t chunkqueue_written(chunkqueue *cq) {
3187         off_t len = 0;
3188         chunk *c;
3189 -       
3190 +
3191         for (c = cq->first; c; c = c->next) {
3192                 switch (c->type) {
3193                 case MEM_CHUNK:
3194 @@ -339,7 +340,7 @@
3195                         break;
3196                 }
3197         }
3198 -       
3199 +
3200         return len;
3201  }
3202  
3203 @@ -355,12 +356,13 @@
3204  
3205                 switch (c->type) {
3206                 case MEM_CHUNK:
3207 +                       if (c->mem->used == 0) is_finished = 1;
3208                         if (c->offset == (off_t)c->mem->used - 1) is_finished = 1;
3209                         break;
3210                 case FILE_CHUNK:
3211 -                       if (c->offset == c->file.length) is_finished = 1; 
3212 +                       if (c->offset == c->file.length) is_finished = 1;
3213                         break;
3214 -               default: 
3215 +               default:
3216                         break;
3217                 }
3218  
3219 @@ -383,3 +385,50 @@
3220  
3221         return 0;
3222  }
3223 +
3224 +void chunkqueue_print(chunkqueue *cq) {
3225 +       chunk *c;
3226 +
3227 +       for (c = cq->first; c; c = c->next) {
3228 +               fprintf(stderr, "(mem) %s", c->mem->ptr + c->offset);
3229 +       }
3230 +       fprintf(stderr, "\r\n");
3231 +}
3232 +
3233 +
3234 +/**
3235 + * remove the last chunk if it is empty
3236 + */
3237 +
3238 +void chunkqueue_remove_empty_last_chunk(chunkqueue *cq) {
3239 +       chunk *c;
3240 +       if (!cq->last) return;
3241 +       if (!cq->first) return;
3242 +
3243 +       if (cq->first == cq->last) {
3244 +               c = cq->first;
3245 +
3246 +               if (c->type != MEM_CHUNK) return;
3247 +               if (c->mem->used == 0) {
3248 +                       chunk_free(c);
3249 +                       cq->first = cq->last = NULL;
3250 +               }
3251 +               return;
3252 +       }
3253 +
3254 +       for (c = cq->first; c->next; c = c->next) {
3255 +               if (c->type != MEM_CHUNK) continue;
3256 +               if (c->mem->used != 0) continue;
3257 +
3258 +               if (c->next == cq->last) {
3259 +                       cq->last = c;
3260 +
3261 +                       chunk_free(c->next);
3262 +                       c->next = NULL;
3263 +
3264 +                       return;
3265 +               }
3266 +       }
3267 +}
3268 +
3269 +
3270 --- ../lighttpd-1.4.11/src/chunk.h      2005-11-01 09:32:21.000000000 +0200
3271 +++ lighttpd-1.4.12/src/chunk.h 2006-07-18 13:03:40.000000000 +0300
3272 @@ -6,7 +6,7 @@
3273  
3274  typedef struct chunk {
3275         enum { UNUSED_CHUNK, MEM_CHUNK, FILE_CHUNK } type;
3276 -       
3277 +
3278         buffer *mem; /* either the storage of the mem-chunk or the read-ahead buffer */
3279  
3280         struct {
3281 @@ -16,28 +16,28 @@
3282                 off_t  length; /* octets to send from the starting offset */
3283  
3284                 int    fd;
3285 -               struct { 
3286 +               struct {
3287                         char   *start; /* the start pointer of the mmap'ed area */
3288                         size_t length; /* size of the mmap'ed area */
3289 -                       off_t  offset; /* start is <n> octet away from the start of the file */
3290 +                       off_t  offset; /* start is <n> octets away from the start of the file */
3291                 } mmap;
3292  
3293 -               int is_temp; /* file is temporary and will be deleted if on cleanup */
3294 +               int is_temp; /* file is temporary and will be deleted on cleanup */
3295         } file;
3296 -       
3297 -       off_t  offset; /* octets sent from this chunk 
3298 -                         the size of the chunk is either 
3299 +
3300 +       off_t  offset; /* octets sent from this chunk
3301 +                         the size of the chunk is either
3302                           - mem-chunk: mem->used - 1
3303                           - file-chunk: file.length
3304                         */
3305 -       
3306 +
3307         struct chunk *next;
3308  } chunk;
3309  
3310  typedef struct {
3311         chunk *first;
3312         chunk *last;
3313 -       
3314 +
3315         chunk *unused;
3316         size_t unused_chunks;
3317  
3318 @@ -56,6 +56,7 @@
3319  buffer * chunkqueue_get_append_buffer(chunkqueue *c);
3320  buffer * chunkqueue_get_prepend_buffer(chunkqueue *c);
3321  chunk * chunkqueue_get_append_tempfile(chunkqueue *cq);
3322 +void chunkqueue_remove_empty_last_chunk(chunkqueue *cq);
3323  
3324  int chunkqueue_remove_finished_chunks(chunkqueue *cq);
3325  
3326 @@ -66,4 +67,6 @@
3327  
3328  int chunkqueue_is_empty(chunkqueue *c);
3329  
3330 +void chunkqueue_print(chunkqueue *cq);
3331 +
3332  #endif
3333 --- ../lighttpd-1.4.11/src/configfile-glue.c    2006-03-03 20:14:56.000000000 +0200
3334 +++ lighttpd-1.4.12/src/configfile-glue.c       2006-07-16 00:26:03.000000000 +0300
3335 @@ -1,4 +1,5 @@
3336  #include <string.h>
3337 +#include <ctype.h>
3338  
3339  #include "base.h"
3340  #include "buffer.h"
3341 @@ -11,10 +12,10 @@
3342   * are the external interface of lighttpd. The functions
3343   * are used by the server itself and the plugins.
3344   *
3345 - * The main-goal is to have a small library in the end 
3346 - * which is linked against both and which will define 
3347 + * The main-goal is to have a small library in the end
3348 + * which is linked against both and which will define
3349   * the interface itself in the end.
3350 - * 
3351 + *
3352   */
3353  
3354  
3355 @@ -24,56 +25,60 @@
3356  int config_insert_values_internal(server *srv, array *ca, const config_values_t cv[]) {
3357         size_t i;
3358         data_unset *du;
3359 -       
3360 +
3361         for (i = 0; cv[i].key; i++) {
3362 -               
3363 +
3364                 if (NULL == (du = array_get_element(ca, cv[i].key))) {
3365                         /* no found */
3366 -                       
3367 +
3368                         continue;
3369                 }
3370 -               
3371 +
3372                 switch (cv[i].type) {
3373                 case T_CONFIG_ARRAY:
3374                         if (du->type == TYPE_ARRAY) {
3375                                 size_t j;
3376                                 data_array *da = (data_array *)du;
3377 -                               
3378 +
3379                                 for (j = 0; j < da->value->used; j++) {
3380                                         if (da->value->data[j]->type == TYPE_STRING) {
3381                                                 data_string *ds = data_string_init();
3382 -                                               
3383 +
3384                                                 buffer_copy_string_buffer(ds->value, ((data_string *)(da->value->data[j]))->value);
3385                                                 if (!da->is_index_key) {
3386                                                         /* the id's were generated automaticly, as we copy now we might have to renumber them
3387 -                                                        * this is used to prepend server.modules by mod_indexfiles as it has to be loaded 
3388 +                                                        * this is used to prepend server.modules by mod_indexfiles as it has to be loaded
3389                                                          * before mod_fastcgi and friends */
3390                                                         buffer_copy_string_buffer(ds->key, ((data_string *)(da->value->data[j]))->key);
3391                                                 }
3392 -                                               
3393 +
3394                                                 array_insert_unique(cv[i].destination, (data_unset *)ds);
3395                                         } else {
3396 -                                               log_error_write(srv, __FILE__, __LINE__, "sssd", 
3397 -                                                               "the key of and array can only be a string or a integer, variable:", 
3398 -                                                               cv[i].key, "type:", da->value->data[j]->type); 
3399 -                                               
3400 +                                               log_error_write(srv, __FILE__, __LINE__, "sssd",
3401 +                                                               "the key of and array can only be a string or a integer, variable:",
3402 +                                                               cv[i].key, "type:", da->value->data[j]->type);
3403 +
3404                                                 return -1;
3405                                         }
3406                                 }
3407                         } else {
3408                                 log_error_write(srv, __FILE__, __LINE__, "sss", "unexpected type for key: ", cv[i].key, "array of strings");
3409 -                               
3410 +
3411                                 return -1;
3412                         }
3413                         break;
3414                 case T_CONFIG_STRING:
3415                         if (du->type == TYPE_STRING) {
3416                                 data_string *ds = (data_string *)du;
3417 -                               
3418 +
3419                                 buffer_copy_string_buffer(cv[i].destination, ds->value);
3420 +                       } else if (du->type == TYPE_INTEGER) {
3421 +                               data_integer *di = (data_integer *)du;
3422 +
3423 +                               buffer_copy_long(cv[i].destination, di->value);
3424                         } else {
3425                                 log_error_write(srv, __FILE__, __LINE__, "ssss", "unexpected type for key: ", cv[i].key, "(string)", "\"...\"");
3426 -                               
3427 +
3428                                 return -1;
3429                         }
3430                         break;
3431 @@ -81,15 +86,20 @@
3432                         switch(du->type) {
3433                         case TYPE_INTEGER: {
3434                                 data_integer *di = (data_integer *)du;
3435 -                               
3436 +
3437                                 *((unsigned short *)(cv[i].destination)) = di->value;
3438                                 break;
3439                         }
3440                         case TYPE_STRING: {
3441                                 data_string *ds = (data_string *)du;
3442 -                                       
3443 +
3444 +                               if (buffer_isdigit(ds->value)) {
3445 +                                       *((unsigned short *)(cv[i].destination)) = strtol(ds->value->ptr, NULL, 10);
3446 +                                       break;
3447 +                               }
3448 +
3449                                 log_error_write(srv, __FILE__, __LINE__, "ssb", "get a string but expected a short:", cv[i].key, ds->value);
3450 -                               
3451 +
3452                                 return -1;
3453                         }
3454                         default:
3455 @@ -100,19 +110,19 @@
3456                 case T_CONFIG_BOOLEAN:
3457                         if (du->type == TYPE_STRING) {
3458                                 data_string *ds = (data_string *)du;
3459 -                               
3460 +
3461                                 if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable"))) {
3462                                         *((unsigned short *)(cv[i].destination)) = 1;
3463                                 } else if (buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))) {
3464                                         *((unsigned short *)(cv[i].destination)) = 0;
3465                                 } else {
3466                                         log_error_write(srv, __FILE__, __LINE__, "ssbs", "ERROR: unexpected value for key:", cv[i].key, ds->value, "(enable|disable)");
3467 -                                               
3468 +
3469                                         return -1;
3470                                 }
3471                         } else {
3472                                 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: unexpected type for key:", cv[i].key, "(string)", "\"(enable|disable)\"");
3473 -                               
3474 +
3475                                 return -1;
3476                         }
3477                         break;
3478 @@ -121,9 +131,9 @@
3479                         break;
3480                 case T_CONFIG_DEPRECATED:
3481                         log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found deprecated key:", cv[i].key, "-", (char *)(cv[i].destination));
3482 -                       
3483 +
3484                         srv->config_deprecated = 1;
3485 -                       
3486 +
3487                         break;
3488                 }
3489         }
3490 @@ -133,25 +143,25 @@
3491  int config_insert_values_global(server *srv, array *ca, const config_values_t cv[]) {
3492         size_t i;
3493         data_unset *du;
3494 -       
3495 +
3496         for (i = 0; cv[i].key; i++) {
3497                 data_string *touched;
3498 -               
3499 +
3500                 if (NULL == (du = array_get_element(ca, cv[i].key))) {
3501                         /* no found */
3502 -                       
3503 +
3504                         continue;
3505                 }
3506 -               
3507 +
3508                 /* touched */
3509                 touched = data_string_init();
3510 -               
3511 +
3512                 buffer_copy_string(touched->value, "");
3513                 buffer_copy_string_buffer(touched->key, du->key);
3514 -               
3515 +
3516                 array_insert_unique(srv->config_touched, (data_unset *)touched);
3517         }
3518 -       
3519 +
3520         return config_insert_values_internal(srv, ca, cv);
3521  }
3522  
3523 @@ -191,25 +201,25 @@
3524         }
3525  
3526         /* pass the rules */
3527 -       
3528 +
3529         switch (dc->comp) {
3530         case COMP_HTTP_HOST: {
3531                 char *ck_colon = NULL, *val_colon = NULL;
3532 -               
3533 +
3534                 if (!buffer_is_empty(con->uri.authority)) {
3535 -               
3536 -                       /* 
3537 +
3538 +                       /*
3539                          * append server-port to the HTTP_POST if necessary
3540                          */
3541 -                       
3542 +
3543                         l = con->uri.authority;
3544 -                       
3545 +
3546                         switch(dc->cond) {
3547                         case CONFIG_COND_NE:
3548                         case CONFIG_COND_EQ:
3549                                 ck_colon = strchr(dc->string->ptr, ':');
3550                                 val_colon = strchr(l->ptr, ':');
3551 -                               
3552 +
3553                                 if (ck_colon == val_colon) {
3554                                         /* nothing to do with it */
3555                                         break;
3556 @@ -230,21 +240,21 @@
3557                                 break;
3558                         }
3559                 } else {
3560 -                       l = NULL;
3561 +                       l = srv->empty_string;
3562                 }
3563                 break;
3564         }
3565         case COMP_HTTP_REMOTEIP: {
3566                 char *nm_slash;
3567 -               /* handle remoteip limitations 
3568 -                * 
3569 +               /* handle remoteip limitations
3570 +                *
3571                  * "10.0.0.1" is provided for all comparisions
3572 -                * 
3573 +                *
3574                  * only for == and != we support
3575 -                * 
3576 +                *
3577                  * "10.0.0.1/24"
3578                  */
3579 -               
3580 +
3581                 if ((dc->cond == CONFIG_COND_EQ ||
3582                      dc->cond == CONFIG_COND_NE) &&
3583                     (con->dst_addr.plain.sa_family == AF_INET) &&
3584 @@ -253,41 +263,48 @@
3585                         long nm;
3586                         char *err;
3587                         struct in_addr val_inp;
3588 -                       
3589 +
3590 +                       if (con->conf.log_condition_handling) {
3591 +                               l = srv->empty_string;
3592 +
3593 +                               log_error_write(srv, __FILE__, __LINE__,  "bsbsb", dc->comp_key,
3594 +                                               "(", l, ") compare to", dc->string);
3595 +                       }
3596 +
3597                         if (*(nm_slash+1) == '\0') {
3598                                 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: no number after / ", dc->string);
3599 -                                       
3600 +
3601                                 return COND_RESULT_FALSE;
3602                         }
3603 -                       
3604 +
3605                         nm_bits = strtol(nm_slash + 1, &err, 10);
3606 -                       
3607 +
3608                         if (*err) {
3609                                 log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", dc->string, *err);
3610 -                               
3611 +
3612                                 return COND_RESULT_FALSE;
3613                         }
3614 -                       
3615 +
3616                         /* take IP convert to the native */
3617                         buffer_copy_string_len(srv->cond_check_buf, dc->string->ptr, nm_slash - dc->string->ptr);
3618 -#ifdef __WIN32                 
3619 +#ifdef _WIN32
3620                         if (INADDR_NONE == (val_inp.s_addr = inet_addr(srv->cond_check_buf->ptr))) {
3621                                 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
3622 -                               
3623 +
3624                                 return COND_RESULT_FALSE;
3625                         }
3626  
3627  #else
3628                         if (0 == inet_aton(srv->cond_check_buf->ptr, &val_inp)) {
3629                                 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
3630 -                               
3631 +
3632                                 return COND_RESULT_FALSE;
3633                         }
3634  #endif
3635 -                       
3636 +
3637                         /* build netmask */
3638                         nm = htonl(~((1 << (32 - nm_bits)) - 1));
3639 -                       
3640 +
3641                         if ((val_inp.s_addr & nm) == (con->dst_addr.ipv4.sin_addr.s_addr & nm)) {
3642                                 return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
3643                         } else {
3644 @@ -308,7 +325,7 @@
3645  
3646         case COMP_HTTP_REFERER: {
3647                 data_string *ds;
3648 -               
3649 +
3650                 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Referer"))) {
3651                         l = ds->value;
3652                 } else {
3653 @@ -338,7 +355,7 @@
3654         default:
3655                 return COND_RESULT_FALSE;
3656         }
3657 -       
3658 +
3659         if (NULL == l) {
3660                 if (con->conf.log_condition_handling) {
3661                         log_error_write(srv, __FILE__, __LINE__,  "bsbs", dc->comp_key,
3662 @@ -346,10 +363,10 @@
3663                 }
3664                 return COND_RESULT_FALSE;
3665         }
3666 -       
3667 +
3668         if (con->conf.log_condition_handling) {
3669                 log_error_write(srv, __FILE__, __LINE__,  "bsbsb", dc->comp_key,
3670 -                               "(", l, ") compare to ", dc->string);
3671 +                               "(", l, ") compare to", dc->string);
3672         }
3673         switch(dc->cond) {
3674         case CONFIG_COND_NE:
3675 @@ -365,13 +382,13 @@
3676         case CONFIG_COND_MATCH: {
3677                 cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
3678                 int n;
3679 -               
3680 +
3681  #ifndef elementsof
3682  #define elementsof(x) (sizeof(x) / sizeof(x[0]))
3683  #endif
3684                 n = pcre_exec(dc->regex, dc->regex_study, l->ptr, l->used - 1, 0, 0,
3685                                 cache->matches, elementsof(cache->matches));
3686 -               
3687 +
3688                 cache->patterncount = n;
3689                 if (n > 0) {
3690                         cache->comp_value = l;
3691 @@ -387,7 +404,7 @@
3692                 /* no way */
3693                 break;
3694         }
3695 -       
3696 +
3697         return COND_RESULT_FALSE;
3698  }
3699  
3700 @@ -395,6 +412,9 @@
3701         cond_cache_t *caches = con->cond_cache;
3702  
3703         if (COND_RESULT_UNSET == caches[dc->context_ndx].result) {
3704 +               if (con->conf.log_condition_handling) {
3705 +                       log_error_write(srv, __FILE__, __LINE__,  "sds",  "=== start of", dc->context_ndx, "condition block ===");
3706 +               }
3707                 if (COND_RESULT_TRUE == (caches[dc->context_ndx].result = config_check_cond_nocache(srv, con, dc))) {
3708                         if (dc->next) {
3709                                 data_config *c;
3710 @@ -409,11 +429,11 @@
3711                 }
3712                 if (con->conf.log_condition_handling) {
3713                         log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
3714 -                                       "(uncached) result:",
3715 +                                       "result:",
3716                                         caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
3717                 }
3718         } else {
3719 -               if (con->conf.log_condition_handling) {
3720 +               if (con->conf.log_condition_cache_handling) {
3721                         log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
3722                                         "(cached) result:",
3723                                         caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
3724 @@ -423,9 +443,6 @@
3725  }
3726  
3727  int config_check_cond(server *srv, connection *con, data_config *dc) {
3728 -       if (con->conf.log_condition_handling) {
3729 -               log_error_write(srv, __FILE__, __LINE__,  "s",  "=== start of condition block ===");
3730 -       }
3731         return (config_check_cond_cached(srv, con, dc) == COND_RESULT_TRUE);
3732  }
3733  
3734 @@ -443,3 +460,85 @@
3735         return 1;
3736  }
3737  
3738 +/* return <0 on error
3739 + * return 0-x if matched (and replaced)
3740 + */
3741 +int config_exec_pcre_keyvalue_buffer(connection *con, pcre_keyvalue_buffer *kvb, data_config *context, buffer *match_buf, buffer *result)
3742 +{
3743 +#ifdef HAVE_PCRE_H
3744 +       pcre *match;
3745 +       pcre_extra *extra;
3746 +       const char *pattern;
3747 +       size_t pattern_len;
3748 +       int n;
3749 +       size_t i;
3750 +       pcre_keyvalue *kv;
3751 +# define N 10
3752 +       int ovec[N * 3];
3753 +
3754 +       for (i = 0; i < kvb->used; i++) {
3755 +               kv = kvb->kv[i];
3756 +
3757 +               match       = kv->key;
3758 +               extra       = kv->key_extra;
3759 +               pattern     = kv->value->ptr;
3760 +               pattern_len = kv->value->used - 1;
3761 +
3762 +               if ((n = pcre_exec(match, extra, match_buf->ptr, match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
3763 +                       if (n != PCRE_ERROR_NOMATCH) {
3764 +                               return n;
3765 +                       }
3766 +               } else {
3767 +                       const char **list;
3768 +                       size_t start, end;
3769 +                       size_t k;
3770 +
3771 +                       /* it matched */
3772 +                       pcre_get_substring_list(match_buf->ptr, ovec, n, &list);
3773 +
3774 +                       /* search for $[0-9] */
3775 +
3776 +                       buffer_reset(result);
3777 +
3778 +                       start = 0; end = pattern_len;
3779 +                       for (k = 0; k < pattern_len; k++) {
3780 +                               if ((pattern[k] == '$' || pattern[k] == '%') &&
3781 +                                   isdigit((unsigned char)pattern[k + 1])) {
3782 +                                       /* got one */
3783 +
3784 +                                       size_t num = pattern[k + 1] - '0';
3785 +
3786 +                                       end = k;
3787 +
3788 +                                       buffer_append_string_len(result, pattern + start, end - start);
3789 +
3790 +                                       if (pattern[k] == '$') {
3791 +                                               /* n is always > 0 */
3792 +                                               if (num < (size_t)n) {
3793 +                                                       buffer_append_string(result, list[num]);
3794 +                                               }
3795 +                                       } else {
3796 +                                               config_append_cond_match_buffer(con, context, result, num);
3797 +                                       }
3798 +
3799 +                                       k++;
3800 +                                       start = k + 1;
3801 +                               }
3802 +                       }
3803 +
3804 +                       buffer_append_string_len(result, pattern + start, pattern_len - start);
3805 +
3806 +                       pcre_free(list);
3807 +
3808 +                       return i;
3809 +               }
3810 +       }
3811 +
3812 +       return PCRE_ERROR_NOMATCH;
3813 +#undef N
3814 +#else
3815 +       UNUSED(kvb);
3816 +       return -2;
3817 +#endif
3818 +}
3819 +
3820 --- ../lighttpd-1.4.11/src/configfile.c 2006-02-15 14:26:42.000000000 +0200
3821 +++ lighttpd-1.4.12/src/configfile.c    2006-07-18 13:03:40.000000000 +0300
3822 @@ -2,7 +2,6 @@
3823  
3824  #include <stdlib.h>
3825  #include <fcntl.h>
3826 -#include <unistd.h>
3827  #include <errno.h>
3828  #include <string.h>
3829  #include <stdio.h>
3830 @@ -13,21 +12,24 @@
3831  #include "log.h"
3832  #include "stream.h"
3833  #include "plugin.h"
3834 -#ifdef USE_LICENSE
3835 -#include "license.h"
3836 -#endif
3837 -
3838  #include "configparser.h"
3839  #include "configfile.h"
3840  #include "proc_open.h"
3841  
3842 +#include "sys-files.h"
3843 +#include "sys-process.h"
3844 +
3845 +#ifndef PATH_MAX
3846 +/* win32 */
3847 +#define PATH_MAX 64
3848 +#endif
3849  
3850  static int config_insert(server *srv) {
3851         size_t i;
3852         int ret = 0;
3853         buffer *stat_cache_string;
3854 -       
3855 -       config_values_t cv[] = { 
3856 +
3857 +       config_values_t cv[] = {
3858                 { "server.bind",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 0 */
3859                 { "server.errorlog",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 1 */
3860                 { "server.errorfile-prefix",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 2 */
3861 @@ -38,7 +40,7 @@
3862                 { "server.tag",                  NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 7 */
3863                 { "server.use-ipv6",             NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
3864                 { "server.modules",              NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_SERVER },       /* 9 */
3865 -               
3866 +
3867                 { "server.event-handler",        NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 10 */
3868                 { "server.pid-file",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 11 */
3869                 { "server.max-request-size",     NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 12 */
3870 @@ -49,7 +51,7 @@
3871                 { "server.max-keep-alive-requests", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 17 */
3872                 { "server.name",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 18 */
3873                 { "server.max-keep-alive-idle",  NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 19 */
3874 -               
3875 +
3876                 { "server.max-read-idle",        NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 20 */
3877                 { "server.max-write-idle",       NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 21 */
3878                 { "server.error-handler-404",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 22 */
3879 @@ -60,19 +62,19 @@
3880                 { "mimetype.use-xattr",          NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 27 */
3881                 { "mimetype.assign",             NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },   /* 28 */
3882                 { "ssl.pemfile",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 29 */
3883 -               
3884 +
3885                 { "ssl.engine",                  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 30 */
3886 -               
3887 +
3888                 { "debug.log-file-not-found",    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 31 */
3889                 { "debug.log-request-handling",  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 32 */
3890                 { "debug.log-response-header",   NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 33 */
3891                 { "debug.log-request-header",    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 34 */
3892 -               
3893 +
3894                 { "server.protocol-http11",      NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 35 */
3895                 { "debug.log-request-header-on-error", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 36 */
3896                 { "debug.log-state-handling",    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 37 */
3897                 { "ssl.ca-file",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 38 */
3898 -               
3899 +
3900                 { "server.errorlog-use-syslog",  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 39 */
3901                 { "server.range-requests",       NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 40 */
3902                 { "server.stat-cache-engine",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 41 */
3903 @@ -80,7 +82,8 @@
3904                 { "server.network-backend",      NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 43 */
3905                 { "server.upload-dirs",          NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },   /* 44 */
3906                 { "server.core-files",           NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 45 */
3907 -               
3908 +               { "debug.log-condition-cache-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },    /* 46 */
3909 +
3910                 { "server.host",                 "use server.bind instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3911                 { "server.docroot",              "use server.document-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3912                 { "server.virtual-root",         "load mod_simple_vhost and use simple-vhost.server-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3913 @@ -90,11 +93,11 @@
3914                 { "server.groupid",              "use server.groupname instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3915                 { "server.use-keep-alive",       "use server.max-keep-alive-requests = 0 instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3916                 { "server.force-lower-case-files",       "use server.force-lowercase-filenames instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3917 -               
3918 +
3919                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
3920         };
3921  
3922 -       
3923 +
3924         /* 0 */
3925         cv[0].destination = srv->srvconf.bindhost;
3926         cv[1].destination = srv->srvconf.errorlog_file;
3927 @@ -102,33 +105,33 @@
3928         cv[4].destination = srv->srvconf.username;
3929         cv[5].destination = srv->srvconf.groupname;
3930         cv[6].destination = &(srv->srvconf.port);
3931 -       
3932 +
3933         cv[9].destination = srv->srvconf.modules;
3934         cv[10].destination = srv->srvconf.event_handler;
3935         cv[11].destination = srv->srvconf.pid_file;
3936 -       
3937 +
3938         cv[13].destination = &(srv->srvconf.max_worker);
3939         cv[23].destination = &(srv->srvconf.max_fds);
3940         cv[36].destination = &(srv->srvconf.log_request_header_on_error);
3941         cv[37].destination = &(srv->srvconf.log_state_handling);
3942 -       
3943 +
3944         cv[39].destination = &(srv->srvconf.errorlog_use_syslog);
3945 -       
3946 +
3947         stat_cache_string = buffer_init();
3948         cv[41].destination = stat_cache_string;
3949         cv[43].destination = srv->srvconf.network_backend;
3950         cv[44].destination = srv->srvconf.upload_tempdirs;
3951         cv[45].destination = &(srv->srvconf.enable_cores);
3952 -       
3953 +
3954         cv[42].destination = &(srv->srvconf.max_conns);
3955         cv[12].destination = &(srv->srvconf.max_request_size);
3956         srv->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
3957  
3958         assert(srv->config_storage);
3959 -       
3960 +
3961         for (i = 0; i < srv->config_context->used; i++) {
3962                 specific_config *s;
3963 -               
3964 +
3965                 s = calloc(1, sizeof(specific_config));
3966                 assert(s);
3967                 s->document_root = buffer_init();
3968 @@ -154,17 +157,18 @@
3969                 s->global_kbytes_per_second = 0;
3970                 s->global_bytes_per_second_cnt = 0;
3971                 s->global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
3972 -               
3973 +
3974                 cv[2].destination = s->errorfile_prefix;
3975 -               
3976 +
3977                 cv[7].destination = s->server_tag;
3978                 cv[8].destination = &(s->use_ipv6);
3979 -               
3980 -               
3981 +
3982 +
3983                 /* 13 max-worker */
3984                 cv[14].destination = s->document_root;
3985                 cv[15].destination = &(s->force_lowercase_filenames);
3986                 cv[16].destination = &(s->log_condition_handling);
3987 +               cv[46].destination = &(s->log_condition_cache_handling);
3988                 cv[17].destination = &(s->max_keep_alive_requests);
3989                 cv[18].destination = s->server_name;
3990                 cv[19].destination = &(s->max_keep_alive_idle);
3991 @@ -179,23 +183,23 @@
3992                 cv[28].destination = s->mimetypes;
3993                 cv[29].destination = s->ssl_pemfile;
3994                 cv[30].destination = &(s->is_ssl);
3995 -               
3996 +
3997                 cv[31].destination = &(s->log_file_not_found);
3998                 cv[32].destination = &(s->log_request_handling);
3999                 cv[33].destination = &(s->log_response_header);
4000                 cv[34].destination = &(s->log_request_header);
4001 -               
4002 +
4003                 cv[35].destination = &(s->allow_http11);
4004                 cv[38].destination = s->ssl_ca_file;
4005                 cv[40].destination = &(s->range_requests);
4006 -               
4007 +
4008                 srv->config_storage[i] = s;
4009 -       
4010 +
4011                 if (0 != (ret = config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv))) {
4012                         break;
4013                 }
4014         }
4015 -       
4016 +
4017         if (buffer_is_empty(stat_cache_string)) {
4018                 srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
4019         } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("simple"))) {
4020 @@ -205,22 +209,22 @@
4021         } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("disable"))) {
4022                 srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_NONE;
4023         } else {
4024 -               log_error_write(srv, __FILE__, __LINE__, "sb", 
4025 +               log_error_write(srv, __FILE__, __LINE__, "sb",
4026                                 "server.stat-cache-engine can be one of \"disable\", \"simple\", \"fam\", but not:", stat_cache_string);
4027                 ret = HANDLER_ERROR;
4028         }
4029 -       
4030 +
4031         buffer_free(stat_cache_string);
4032 -       
4033 +
4034         return ret;
4035 -                                                                
4036 -}
4037  
4038 +}
4039  
4040 -#define PATCH(x) con->conf.x = s->x
4041 +#define PATCH(x) \
4042 +       con->conf.x = s->x
4043  int config_setup_connection(server *srv, connection *con) {
4044         specific_config *s = srv->config_storage[0];
4045 -       
4046 +
4047         PATCH(allow_http11);
4048         PATCH(mimetypes);
4049         PATCH(document_root);
4050 @@ -236,20 +240,21 @@
4051         PATCH(kbytes_per_second);
4052         PATCH(global_kbytes_per_second);
4053         PATCH(global_bytes_per_second_cnt);
4054 -       
4055 +
4056         con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
4057         buffer_copy_string_buffer(con->server_name, s->server_name);
4058 -       
4059 +
4060         PATCH(log_request_header);
4061         PATCH(log_response_header);
4062         PATCH(log_request_handling);
4063         PATCH(log_condition_handling);
4064 +       PATCH(log_condition_cache_handling);
4065         PATCH(log_file_not_found);
4066 -       
4067 +
4068         PATCH(range_requests);
4069         PATCH(force_lowercase_filenames);
4070         PATCH(is_ssl);
4071 -       
4072 +
4073         PATCH(ssl_pemfile);
4074         PATCH(ssl_ca_file);
4075         return 0;
4076 @@ -257,22 +262,22 @@
4077  
4078  int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
4079         size_t i, j;
4080 -       
4081 +
4082         /* skip the first, the global context */
4083         for (i = 1; i < srv->config_context->used; i++) {
4084                 data_config *dc = (data_config *)srv->config_context->data[i];
4085                 specific_config *s = srv->config_storage[i];
4086 -               
4087 +
4088                 /* not our stage */
4089                 if (comp != dc->comp) continue;
4090 -               
4091 +
4092                 /* condition didn't match */
4093                 if (!config_check_cond(srv, con, dc)) continue;
4094 -               
4095 +
4096                 /* merge config */
4097                 for (j = 0; j < dc->value->used; j++) {
4098                         data_unset *du = dc->value->data[j];
4099 -                       
4100 +
4101                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.document-root"))) {
4102                                 PATCH(document_root);
4103                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.range-requests"))) {
4104 @@ -315,11 +320,13 @@
4105                                 PATCH(log_response_header);
4106                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-condition-handling"))) {
4107                                 PATCH(log_condition_handling);
4108 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-condition-cache-handling"))) {
4109 +                               PATCH(log_condition_cache_handling);
4110                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-file-not-found"))) {
4111                                 PATCH(log_file_not_found);
4112                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.protocol-http11"))) {
4113                                 PATCH(allow_http11);
4114 -                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {  
4115 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {
4116                                 PATCH(force_lowercase_filenames);
4117                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.kbytes-per-second"))) {
4118                                 PATCH(global_kbytes_per_second);
4119 @@ -328,7 +335,7 @@
4120                         }
4121                 }
4122         }
4123 -       
4124 +
4125         return 0;
4126  }
4127  #undef PATCH
4128 @@ -336,15 +343,15 @@
4129  typedef struct {
4130         int foo;
4131         int bar;
4132 -       
4133 +
4134         const buffer *source;
4135         const char *input;
4136         size_t offset;
4137         size_t size;
4138 -       
4139 +
4140         int line_pos;
4141         int line;
4142 -       
4143 +
4144         int in_key;
4145         int in_brace;
4146         int in_cond;
4147 @@ -362,7 +369,7 @@
4148         }
4149  
4150         if (0 != stream_open(&(t->s), t->file)) {
4151 -               log_error_write(srv, __FILE__, __LINE__, "sbss", 
4152 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
4153                                 "opening configfile ", t->file, "failed:", strerror(errno));
4154                 buffer_free(t->file);
4155                 return -1;
4156 @@ -373,7 +380,7 @@
4157         t->size = t->s.size;
4158         t->line = 1;
4159         t->line_pos = 1;
4160 -       
4161 +
4162         t->in_key = 1;
4163         t->in_brace = 0;
4164         t->in_cond = 0;
4165 @@ -401,7 +408,7 @@
4166  static int config_skip_comment(tokenizer_t *t) {
4167         int i;
4168         assert(t->input[t->offset] == '#');
4169 -       for (i = 1; t->input[t->offset + i] && 
4170 +       for (i = 1; t->input[t->offset + i] &&
4171              (t->input[t->offset + i] != '\n' && t->input[t->offset + i] != '\r');
4172              i++);
4173         t->offset += i;
4174 @@ -411,44 +418,44 @@
4175  static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *token) {
4176         int tid = 0;
4177         size_t i;
4178 -       
4179 +
4180         for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
4181                 char c = t->input[t->offset];
4182                 const char *start = NULL;
4183 -               
4184 +
4185                 switch (c) {
4186 -               case '=': 
4187 +               case '=':
4188                         if (t->in_brace) {
4189                                 if (t->input[t->offset + 1] == '>') {
4190                                         t->offset += 2;
4191 -                                       
4192 +
4193                                         buffer_copy_string(token, "=>");
4194 -                                       
4195 +
4196                                         tid = TK_ARRAY_ASSIGN;
4197                                 } else {
4198 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4199 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4200                                                         "source:", t->source,
4201 -                                                       "line:", t->line, "pos:", t->line_pos, 
4202 +                                                       "line:", t->line, "pos:", t->line_pos,
4203                                                         "use => for assignments in arrays");
4204                                         return -1;
4205                                 }
4206                         } else if (t->in_cond) {
4207                                 if (t->input[t->offset + 1] == '=') {
4208                                         t->offset += 2;
4209 -                                       
4210 +
4211                                         buffer_copy_string(token, "==");
4212 -                                       
4213 +
4214                                         tid = TK_EQ;
4215                                 } else if (t->input[t->offset + 1] == '~') {
4216                                         t->offset += 2;
4217 -                                       
4218 +
4219                                         buffer_copy_string(token, "=~");
4220 -                                       
4221 +
4222                                         tid = TK_MATCH;
4223                                 } else {
4224 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4225 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4226                                                         "source:", t->source,
4227 -                                                       "line:", t->line, "pos:", t->line_pos, 
4228 +                                                       "line:", t->line, "pos:", t->line_pos,
4229                                                         "only =~ and == are allowed in the condition");
4230                                         return -1;
4231                                 }
4232 @@ -456,51 +463,51 @@
4233                                 t->in_cond = 0;
4234                         } else if (t->in_key) {
4235                                 tid = TK_ASSIGN;
4236 -                               
4237 +
4238                                 buffer_copy_string_len(token, t->input + t->offset, 1);
4239 -                               
4240 +
4241                                 t->offset++;
4242                                 t->line_pos++;
4243                         } else {
4244 -                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4245 +                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4246                                                 "source:", t->source,
4247 -                                               "line:", t->line, "pos:", t->line_pos, 
4248 +                                               "line:", t->line, "pos:", t->line_pos,
4249                                                 "unexpected equal-sign: =");
4250                                 return -1;
4251                         }
4252 -                       
4253 +
4254                         break;
4255 -               case '!': 
4256 +               case '!':
4257                         if (t->in_cond) {
4258                                 if (t->input[t->offset + 1] == '=') {
4259                                         t->offset += 2;
4260 -                                       
4261 +
4262                                         buffer_copy_string(token, "!=");
4263 -                                       
4264 +
4265                                         tid = TK_NE;
4266                                 } else if (t->input[t->offset + 1] == '~') {
4267                                         t->offset += 2;
4268 -                                       
4269 +
4270                                         buffer_copy_string(token, "!~");
4271 -                                       
4272 +
4273                                         tid = TK_NOMATCH;
4274                                 } else {
4275 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4276 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4277                                                         "source:", t->source,
4278 -                                                       "line:", t->line, "pos:", t->line_pos, 
4279 +                                                       "line:", t->line, "pos:", t->line_pos,
4280                                                         "only !~ and != are allowed in the condition");
4281                                         return -1;
4282                                 }
4283                                 t->in_key = 1;
4284                                 t->in_cond = 0;
4285                         } else {
4286 -                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4287 +                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4288                                                 "source:", t->source,
4289 -                                               "line:", t->line, "pos:", t->line_pos, 
4290 +                                               "line:", t->line, "pos:", t->line_pos,
4291                                                 "unexpected exclamation-marks: !");
4292                                 return -1;
4293                         }
4294 -                       
4295 +
4296                         break;
4297                 case '\t':
4298                 case ' ':
4299 @@ -546,10 +553,10 @@
4300                 case ',':
4301                         if (t->in_brace > 0) {
4302                                 tid = TK_COMMA;
4303 -                               
4304 +
4305                                 buffer_copy_string(token, "(COMMA)");
4306                         }
4307 -                       
4308 +
4309                         t->offset++;
4310                         t->line_pos++;
4311                         break;
4312 @@ -557,70 +564,70 @@
4313                         /* search for the terminating " */
4314                         start = t->input + t->offset + 1;
4315                         buffer_copy_string(token, "");
4316 -                       
4317 +
4318                         for (i = 1; t->input[t->offset + i]; i++) {
4319                                 if (t->input[t->offset + i] == '\\' &&
4320                                     t->input[t->offset + i + 1] == '"') {
4321 -                                       
4322 +
4323                                         buffer_append_string_len(token, start, t->input + t->offset + i - start);
4324 -                                       
4325 +
4326                                         start = t->input + t->offset + i + 1;
4327 -                                       
4328 +
4329                                         /* skip the " */
4330                                         i++;
4331                                         continue;
4332                                 }
4333 -                               
4334 -                               
4335 +
4336 +
4337                                 if (t->input[t->offset + i] == '"') {
4338                                         tid = TK_STRING;
4339 -                               
4340 +
4341                                         buffer_append_string_len(token, start, t->input + t->offset + i - start);
4342 -                                       
4343 +
4344                                         break;
4345                                 }
4346                         }
4347  
4348                         if (t->input[t->offset + i] == '\0') {
4349                                 /* ERROR */
4350 -                               
4351 -                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4352 +
4353 +                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4354                                                 "source:", t->source,
4355 -                                               "line:", t->line, "pos:", t->line_pos, 
4356 +                                               "line:", t->line, "pos:", t->line_pos,
4357                                                 "missing closing quote");
4358 -                               
4359 +
4360                                 return -1;
4361                         }
4362 -                       
4363 +
4364                         t->offset += i + 1;
4365                         t->line_pos += i + 1;
4366 -                       
4367 +
4368                         break;
4369                 case '(':
4370                         t->offset++;
4371                         t->in_brace++;
4372 -                               
4373 +
4374                         tid = TK_LPARAN;
4375 -                               
4376 +
4377                         buffer_copy_string(token, "(");
4378                         break;
4379                 case ')':
4380                         t->offset++;
4381                         t->in_brace--;
4382 -                               
4383 +
4384                         tid = TK_RPARAN;
4385 -                               
4386 +
4387                         buffer_copy_string(token, ")");
4388                         break;
4389                 case '$':
4390                         t->offset++;
4391 -                               
4392 +
4393                         tid = TK_DOLLAR;
4394                         t->in_cond = 1;
4395                         t->in_key = 0;
4396 -                               
4397 +
4398                         buffer_copy_string(token, "$");
4399 -                       
4400 +
4401                         break;
4402  
4403                 case '+':
4404 @@ -637,115 +644,107 @@
4405  
4406                 case '{':
4407                         t->offset++;
4408 -                               
4409 +
4410                         tid = TK_LCURLY;
4411 -                               
4412 +
4413                         buffer_copy_string(token, "{");
4414 -                       
4415 +
4416                         break;
4417 -                       
4418 +
4419                 case '}':
4420                         t->offset++;
4421 -                               
4422 +
4423                         tid = TK_RCURLY;
4424 -                               
4425 +
4426                         buffer_copy_string(token, "}");
4427 -                       
4428 +
4429                         break;
4430  
4431                 case '[':
4432                         t->offset++;
4433 -                               
4434 +
4435                         tid = TK_LBRACKET;
4436 -                               
4437 +
4438                         buffer_copy_string(token, "[");
4439 -                       
4440 +
4441                         break;
4442 -                       
4443 +
4444                 case ']':
4445                         t->offset++;
4446 -                               
4447 +
4448                         tid = TK_RBRACKET;
4449 -                               
4450 +
4451                         buffer_copy_string(token, "]");
4452 -                       
4453 +
4454                         break;
4455                 case '#':
4456                         t->line_pos += config_skip_comment(t);
4457 -                       
4458 +
4459                         break;
4460                 default:
4461                         if (t->in_cond) {
4462 -                               for (i = 0; t->input[t->offset + i] && 
4463 +                               for (i = 0; t->input[t->offset + i] &&
4464                                      (isalpha((unsigned char)t->input[t->offset + i])
4465                                       ); i++);
4466 -                               
4467 +
4468                                 if (i && t->input[t->offset + i]) {
4469                                         tid = TK_SRVVARNAME;
4470                                         buffer_copy_string_len(token, t->input + t->offset, i);
4471 -                                       
4472 +
4473                                         t->offset += i;
4474                                         t->line_pos += i;
4475                                 } else {
4476                                         /* ERROR */
4477 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4478 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4479                                                         "source:", t->source,
4480 -                                                       "line:", t->line, "pos:", t->line_pos, 
4481 +                                                       "line:", t->line, "pos:", t->line_pos,
4482                                                         "invalid character in condition");
4483                                         return -1;
4484                                 }
4485                         } else if (isdigit((unsigned char)c)) {
4486                                 /* take all digits */
4487                                 for (i = 0; t->input[t->offset + i] && isdigit((unsigned char)t->input[t->offset + i]);  i++);
4488 -                               
4489 +
4490                                 /* was there it least a digit ? */
4491 -                               if (i && t->input[t->offset + i]) {
4492 +                               if (i) {
4493                                         tid = TK_INTEGER;
4494 -                                       
4495 +
4496                                         buffer_copy_string_len(token, t->input + t->offset, i);
4497 -                                       
4498 +
4499                                         t->offset += i;
4500                                         t->line_pos += i;
4501 -                               } else {
4502 -                                       /* ERROR */
4503 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4504 -                                                       "source:", t->source,
4505 -                                                       "line:", t->line, "pos:", t->line_pos, 
4506 -                                                       "unexpected EOF");
4507 -                                       
4508 -                                       return -1;
4509                                 }
4510                         } else {
4511                                 /* the key might consist of [-.0-9a-z] */
4512 -                               for (i = 0; t->input[t->offset + i] && 
4513 -                                    (isalnum((unsigned char)t->input[t->offset + i]) || 
4514 +                               for (i = 0; t->input[t->offset + i] &&
4515 +                                    (isalnum((unsigned char)t->input[t->offset + i]) ||
4516                                       t->input[t->offset + i] == '.' ||
4517                                       t->input[t->offset + i] == '_' || /* for env.* */
4518                                       t->input[t->offset + i] == '-'
4519                                       ); i++);
4520 -                               
4521 +
4522                                 if (i && t->input[t->offset + i]) {
4523                                         buffer_copy_string_len(token, t->input + t->offset, i);
4524 -                                       
4525 -                                       if (strcmp(token->ptr, "include") == 0) {
4526 +
4527 +                                       if (buffer_is_equal_string(token, CONST_STR_LEN("include"))) {
4528                                                 tid = TK_INCLUDE;
4529 -                                       } else if (strcmp(token->ptr, "include_shell") == 0) {
4530 +                                       } else if (buffer_is_equal_string(token, CONST_STR_LEN("include_shell"))) {
4531                                                 tid = TK_INCLUDE_SHELL;
4532 -                                       } else if (strcmp(token->ptr, "global") == 0) {
4533 +                                       } else if (buffer_is_equal_string(token, CONST_STR_LEN("global"))) {
4534                                                 tid = TK_GLOBAL;
4535 -                                       } else if (strcmp(token->ptr, "else") == 0) {
4536 +                                       } else if (buffer_is_equal_string(token, CONST_STR_LEN("else"))) {
4537                                                 tid = TK_ELSE;
4538                                         } else {
4539                                                 tid = TK_LKEY;
4540                                         }
4541 -                                       
4542 +
4543                                         t->offset += i;
4544                                         t->line_pos += i;
4545                                 } else {
4546                                         /* ERROR */
4547 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4548 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4549                                                         "source:", t->source,
4550 -                                                       "line:", t->line, "pos:", t->line_pos, 
4551 +                                                       "line:", t->line, "pos:", t->line_pos,
4552                                                         "invalid character in variable name");
4553                                         return -1;
4554                                 }
4555 @@ -753,16 +752,16 @@
4556                         break;
4557                 }
4558         }
4559 -       
4560 +
4561         if (tid) {
4562                 *token_id = tid;
4563  #if 0
4564 -               log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd", 
4565 +               log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd",
4566                                 "source:", t->source,
4567                                 "line:", t->line, "pos:", t->line_pos,
4568                                 token, token->used - 1, tid);
4569  #endif
4570 -               
4571 +
4572                 return 1;
4573         } else if (t->offset < t->size) {
4574                 fprintf(stderr, "%s.%d: %d, %s\n",
4575 @@ -781,10 +780,11 @@
4576         pParser = configparserAlloc( malloc );
4577         lasttoken = buffer_init();
4578         token = buffer_init();
4579 +
4580         while((1 == (ret = config_tokenizer(srv, t, &token_id, token))) && context->ok) {
4581                 buffer_copy_string_buffer(lasttoken, token);
4582                 configparser(pParser, token_id, token, context);
4583 -               
4584 +
4585                 token = buffer_init();
4586         }
4587         buffer_free(token);
4588 @@ -797,14 +797,14 @@
4589                 }
4590         }
4591         configparserFree(pParser, free);
4592 -       
4593 +
4594         if (ret == -1) {
4595 -               log_error_write(srv, __FILE__, __LINE__, "sb", 
4596 +               log_error_write(srv, __FILE__, __LINE__, "sb",
4597                                 "configfile parser failed:", lasttoken);
4598         } else if (context->ok == 0) {
4599 -               log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb", 
4600 +               log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb",
4601                                 "source:", t->source,
4602 -                               "line:", t->line, "pos:", t->line_pos, 
4603 +                               "line:", t->line, "pos:", t->line_pos,
4604                                 "parser failed somehow near here:", lasttoken);
4605                 ret = -1;
4606         }
4607 @@ -821,7 +821,7 @@
4608         t->offset = 0;
4609         t->line = 1;
4610         t->line_pos = 1;
4611 -       
4612 +
4613         t->in_key = 1;
4614         t->in_brace = 0;
4615         t->in_cond = 0;
4616 @@ -844,7 +844,7 @@
4617         }
4618  
4619         if (0 != stream_open(&s, filename)) {
4620 -               log_error_write(srv, __FILE__, __LINE__, "sbss", 
4621 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
4622                                 "opening configfile ", filename, "failed:", strerror(errno));
4623                 ret = -1;
4624         } else {
4625 @@ -866,7 +866,7 @@
4626         char oldpwd[PATH_MAX];
4627  
4628         if (NULL == getcwd(oldpwd, sizeof(oldpwd))) {
4629 -               log_error_write(srv, __FILE__, __LINE__, "s", 
4630 +               log_error_write(srv, __FILE__, __LINE__, "s",
4631                                 "cannot get cwd", strerror(errno));
4632                 return -1;
4633         }
4634 @@ -879,7 +879,7 @@
4635         }
4636  
4637         if (0 != proc_open_buffer(&proc, cmd, NULL, out, NULL)) {
4638 -               log_error_write(srv, __FILE__, __LINE__, "sbss", 
4639 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
4640                                 "opening", source, "failed:", strerror(errno));
4641                 ret = -1;
4642         } else {
4643 @@ -896,13 +896,12 @@
4644  static void context_init(server *srv, config_t *context) {
4645         context->srv = srv;
4646         context->ok = 1;
4647 -       context->configs_stack = array_init();
4648 -       context->configs_stack->is_weakref = 1;
4649 +       context->configs_stack = buffer_ptr_init(NULL);
4650         context->basedir = buffer_init();
4651  }
4652  
4653  static void context_free(config_t *context) {
4654 -       array_free(context->configs_stack);
4655 +       buffer_ptr_free(context->configs_stack);
4656         buffer_free(context->basedir);
4657  }
4658  
4659 @@ -918,18 +917,15 @@
4660         context_init(srv, &context);
4661         context.all_configs = srv->config_context;
4662  
4663 -       pos = strrchr(fn,
4664 -#ifdef __WIN32
4665 -                       '\\'
4666 -#else
4667 -                       '/'
4668 -#endif
4669 -                       );
4670 +    /* use the current dir as basedir for all other includes
4671 +    */
4672 +       pos = strrchr(fn, DIR_SEPERATOR);
4673 +
4674         if (pos) {
4675                 buffer_copy_string_len(context.basedir, fn, pos - fn + 1);
4676                 fn = pos + 1;
4677         }
4678 -       
4679 +
4680         dc = data_config_init();
4681         buffer_copy_string(dc->key, "global");
4682  
4683 @@ -944,7 +940,7 @@
4684         dpid->value = getpid();
4685         buffer_copy_string(dpid->key, "var.PID");
4686         array_insert_unique(srv->config, (data_unset *)dpid);
4687 -       
4688 +
4689         dcwd = data_string_init();
4690         buffer_prepare_copy(dcwd->value, 1024);
4691         if (NULL != getcwd(dcwd->value->ptr, dcwd->value->size - 1)) {
4692 @@ -968,7 +964,7 @@
4693         } else {
4694                 return -1;
4695         }
4696 -       
4697 +
4698         if (NULL != (modules = (data_array *)array_get_element(srv->config, "server.modules"))) {
4699                 data_string *ds;
4700                 data_array *prepends;
4701 @@ -1026,22 +1022,23 @@
4702                 buffer_copy_string(modules->key, "server.modules");
4703                 array_insert_unique(srv->config, (data_unset *)modules);
4704         }
4705 -       
4706 +
4707  
4708         if (0 != config_insert(srv)) {
4709                 return -1;
4710         }
4711 -       
4712 +
4713         return 0;
4714  }
4715  
4716 +
4717  int config_set_defaults(server *srv) {
4718         size_t i;
4719         specific_config *s = srv->config_storage[0];
4720         struct stat st1, st2;
4721 -       
4722 -       struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] = 
4723 -       { 
4724 +
4725 +       struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
4726 +       {
4727                 /* - poll is most reliable
4728                  * - select works everywhere
4729                  * - linux-* are experimental
4730 @@ -1067,20 +1064,21 @@
4731  #endif
4732                 { FDEVENT_HANDLER_UNSET,          NULL }
4733         };
4734 -       
4735  
4736 -       if (buffer_is_empty(s->document_root)) {  
4737 -               log_error_write(srv, __FILE__, __LINE__, "s",  
4738 -                               "a default document-root has to be set");  
4739 -               
4740 -               return -1;  
4741 -       }  
4742 -       
4743 +
4744 +       if (buffer_is_empty(s->document_root)) {
4745 +               log_error_write(srv, __FILE__, __LINE__, "s",
4746 +                               "a default document-root has to be set");
4747 +
4748 +               return -1;
4749 +       }
4750 +
4751         if (buffer_is_empty(srv->srvconf.changeroot)) {
4752 -               if (-1 == stat(s->document_root->ptr, &st1)) {  
4753 -                       log_error_write(srv, __FILE__, __LINE__, "sb",  
4754 +        pathname_unix2local(s->document_root);
4755 +               if (-1 == stat(s->document_root->ptr, &st1)) {
4756 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
4757                                         "base-docroot doesn't exist:",
4758 -                                       s->document_root);  
4759 +                                       s->document_root, strerror(errno));
4760                         return -1;
4761                 }
4762  
4763 @@ -1088,18 +1086,18 @@
4764                 buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.changeroot);
4765                 buffer_append_string_buffer(srv->tmp_buf, s->document_root);
4766  
4767 -               if (-1 == stat(srv->tmp_buf->ptr, &st1)) {  
4768 -                       log_error_write(srv, __FILE__, __LINE__, "sb",  
4769 +               if (-1 == stat(srv->tmp_buf->ptr, &st1)) {
4770 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
4771                                         "base-docroot doesn't exist:",
4772 -                                       srv->tmp_buf);  
4773 +                                       srv->tmp_buf);
4774                         return -1;
4775                 }
4776 -               
4777 +
4778         }
4779 -       
4780 -       buffer_copy_string_buffer(srv->tmp_buf, s->document_root);  
4781  
4782 -       buffer_to_lower(srv->tmp_buf);  
4783 +       buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
4784 +
4785 +       buffer_to_lower(srv->tmp_buf);
4786  
4787         if (0 == stat(srv->tmp_buf->ptr, &st1)) {
4788                 int is_lower = 0;
4789 @@ -1107,68 +1105,68 @@
4790                 is_lower = buffer_is_equal(srv->tmp_buf, s->document_root);
4791  
4792                 /* lower-case existed, check upper-case */
4793 -               buffer_copy_string_buffer(srv->tmp_buf, s->document_root);  
4794 +               buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
4795  
4796 -               buffer_to_upper(srv->tmp_buf);  
4797 +               buffer_to_upper(srv->tmp_buf);
4798  
4799                 /* we have to handle the special case that upper and lower-casing results in the same filename
4800                  * as in server.document-root = "/" or "/12345/" */
4801  
4802                 if (is_lower && buffer_is_equal(srv->tmp_buf, s->document_root)) {
4803 -                       /* lower-casing and upper-casing didn't result in  
4804 -                        * an other filename, no need to stat(), 
4805 +                       /* lower-casing and upper-casing didn't result in
4806 +                        * an other filename, no need to stat(),
4807                          * just assume it is case-sensitive. */
4808  
4809                         s->force_lowercase_filenames = 0;
4810 -               } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {  
4811 +               } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {
4812 +
4813 +                       /* upper case exists too, doesn't the FS handle this ? */
4814 +
4815 +                       /* upper and lower have the same inode -> case-insensitve FS */
4816 +
4817 +                       if (st1.st_ino == st2.st_ino) {
4818 +                               /* upper and lower have the same inode -> case-insensitve FS */
4819 +
4820 +                               s->force_lowercase_filenames = 1;
4821 +                       }
4822 +               }
4823 +       }
4824  
4825 -                       /* upper case exists too, doesn't the FS handle this ? */  
4826 -                       
4827 -                       /* upper and lower have the same inode -> case-insensitve FS */  
4828 -                       
4829 -                       if (st1.st_ino == st2.st_ino) {  
4830 -                               /* upper and lower have the same inode -> case-insensitve FS */  
4831 -                               
4832 -                               s->force_lowercase_filenames = 1;  
4833 -                       }  
4834 -               }  
4835 -       }  
4836 -       
4837         if (srv->srvconf.port == 0) {
4838                 srv->srvconf.port = s->is_ssl ? 443 : 80;
4839         }
4840 -       
4841 +
4842         if (srv->srvconf.event_handler->used == 0) {
4843                 /* choose a good default
4844 -                * 
4845 -                * the event_handler list is sorted by 'goodness' 
4846 +                *
4847 +                * the event_handler list is sorted by 'goodness'
4848                  * taking the first available should be the best solution
4849                  */
4850                 srv->event_handler = event_handlers[0].et;
4851 -               
4852 +
4853                 if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
4854 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
4855 +                       log_error_write(srv, __FILE__, __LINE__, "s",
4856                                         "sorry, there is no event handler for this system");
4857 -                       
4858 +
4859                         return -1;
4860                 }
4861         } else {
4862                 /*
4863                  * User override
4864                  */
4865 -               
4866 +
4867                 for (i = 0; event_handlers[i].name; i++) {
4868                         if (0 == strcmp(event_handlers[i].name, srv->srvconf.event_handler->ptr)) {
4869                                 srv->event_handler = event_handlers[i].et;
4870                                 break;
4871                         }
4872                 }
4873 -               
4874 +
4875                 if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
4876 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
4877 -                                       "the selected event-handler in unknown or not supported:", 
4878 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
4879 +                                       "the selected event-handler in unknown or not supported:",
4880                                         srv->srvconf.event_handler );
4881 -                       
4882 +
4883                         return -1;
4884                 }
4885         }
4886 @@ -1176,19 +1174,19 @@
4887         if (s->is_ssl) {
4888                 if (buffer_is_empty(s->ssl_pemfile)) {
4889                         /* PEM file is require */
4890 -                       
4891 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
4892 +
4893 +                       log_error_write(srv, __FILE__, __LINE__, "s",
4894                                         "ssl.pemfile has to be set");
4895                         return -1;
4896                 }
4897 -               
4898 +
4899  #ifndef USE_OPENSSL
4900 -               log_error_write(srv, __FILE__, __LINE__, "s", 
4901 +               log_error_write(srv, __FILE__, __LINE__, "s",
4902                                 "ssl support is missing, recompile with --with-openssl");
4903 -               
4904 +
4905                 return -1;
4906  #endif
4907         }
4908 -       
4909 +
4910         return 0;
4911  }
4912 --- ../lighttpd-1.4.11/src/configfile.h 2005-08-23 17:36:12.000000000 +0300
4913 +++ lighttpd-1.4.12/src/configfile.h    2006-07-16 00:26:03.000000000 +0300
4914 @@ -9,7 +9,7 @@
4915         server *srv;
4916         int     ok;
4917         array  *all_configs;
4918 -       array  *configs_stack; /* to parse nested block */
4919 +       buffer_ptr  *configs_stack; /* to parse nested block */
4920         data_config *current; /* current started with { */
4921         buffer *basedir;
4922  } config_t;
4923 --- ../lighttpd-1.4.11/src/configparser.c       2006-02-01 19:51:15.000000000 +0200
4924 +++ lighttpd-1.4.12/src/configparser.c  2006-07-17 22:02:23.000000000 +0300
4925 @@ -24,52 +24,34 @@
4926      dc->parent = ctx->current;
4927      array_insert_unique(dc->parent->childs, (data_unset *)dc);
4928    }
4929 -  array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
4930 +  buffer_ptr_append(ctx->configs_stack, (void *)ctx->current);
4931    ctx->current = dc;
4932  }
4933  
4934  static data_config *configparser_pop(config_t *ctx) {
4935    data_config *old = ctx->current;
4936 -  ctx->current = (data_config *) array_pop(ctx->configs_stack);
4937 +  ctx->current = (data_config *) buffer_ptr_pop(ctx->configs_stack);
4938    return old;
4939  }
4940  
4941  /* return a copied variable */
4942  static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
4943 -  if (strncmp(key->ptr, "env.", sizeof("env.") - 1) == 0) {
4944 -    char *env;
4945 -
4946 -    if (NULL != (env = getenv(key->ptr + 4))) {
4947 -      data_string *ds;
4948 -      ds = data_string_init();
4949 -      buffer_append_string(ds->value, env);
4950 -      return (data_unset *)ds;
4951 -    }
4952 -
4953 -    fprintf(stderr, "Undefined env variable: %s\n", key->ptr + 4);
4954 -    ctx->ok = 0;
4955 -
4956 -    return NULL;
4957 -  } else {
4958 -    data_unset *du;
4959 -    data_config *dc;
4960 +  data_unset *du;
4961 +  data_config *dc;
4962  
4963  #if 0
4964 -    fprintf(stderr, "get var %s\n", key->ptr);
4965 +  fprintf(stderr, "get var %s\n", key->ptr);
4966  #endif
4967 -    for (dc = ctx->current; dc; dc = dc->parent) {
4968 +  for (dc = ctx->current; dc; dc = dc->parent) {
4969  #if 0
4970 -      fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
4971 -      array_print(dc->value, 0);
4972 +    fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
4973 +    array_print(dc->value, 0);
4974  #endif
4975 -      if (NULL != (du = array_get_element(dc->value, key->ptr))) {
4976 -        return du->copy(du);
4977 -      }
4978 +    if (NULL != (du = array_get_element(dc->value, key->ptr))) {
4979 +      return du->copy(du);
4980      }
4981 -    fprintf(stderr, "Undefined config variable: %s\n", key->ptr);
4982 -    ctx->ok = 0;
4983 -    return NULL;
4984    }
4985 +  return NULL;
4986  }
4987  
4988  /* op1 is to be eat/return by this function, op1->key is not cared
4989 @@ -124,14 +106,14 @@
4990  }
4991  
4992  
4993 -#line 128 "configparser.c"
4994 +#line 110 "configparser.c"
4995  /* Next is all token values, in a form suitable for use by makeheaders.
4996  ** This section will be null unless lemon is run with the -m switch.
4997  */
4998 -/* 
4999 +/*
5000  ** These constants (all generated automatically by the parser generator)
5001  ** specify the various kinds of tokens (terminals) that the parser
5002 -** understands. 
5003 +** understands.
5004  **
5005  ** Each symbol here is a terminal symbol in the grammar.
5006  */
5007 @@ -148,7 +130,7 @@
5008  **                       and nonterminals.  "int" is used otherwise.
5009  **    YYNOCODE           is a number of type YYCODETYPE which corresponds
5010  **                       to no legal terminal or nonterminal number.  This
5011 -**                       number is used to fill in empty slots of the hash 
5012 +**                       number is used to fill in empty slots of the hash
5013  **                       table.
5014  **    YYFALLBACK         If defined, this indicates that one or more tokens
5015  **                       have fall-back values which should be used if the
5016 @@ -157,7 +139,7 @@
5017  **                       and nonterminal numbers.  "unsigned char" is
5018  **                       used if there are fewer than 250 rules and
5019  **                       states combined.  "int" is used otherwise.
5020 -**    configparserTOKENTYPE     is the data type used for minor tokens given 
5021 +**    configparserTOKENTYPE     is the data type used for minor tokens given
5022  **                       directly to the parser from the tokenizer.
5023  **    YYMINORTYPE        is the data type used for all minor tokens.
5024  **                       This is typically a union of many types, one of
5025 @@ -192,8 +174,8 @@
5026  #define configparserARG_PDECL ,config_t *ctx
5027  #define configparserARG_FETCH config_t *ctx = yypParser->ctx
5028  #define configparserARG_STORE yypParser->ctx = ctx
5029 -#define YYNSTATE 62
5030 -#define YYNRULE 39
5031 +#define YYNSTATE 63
5032 +#define YYNRULE 40
5033  #define YYERRORSYMBOL 26
5034  #define YYERRSYMDT yy95
5035  #define YY_NO_ACTION      (YYNSTATE+YYNRULE+2)
5036 @@ -203,7 +185,7 @@
5037  /* Next are that tables used to determine what action to take based on the
5038  ** current state and lookahead token.  These tables are used to implement
5039  ** functions that take a state number and lookahead value and return an
5040 -** action integer.  
5041 +** action integer.
5042  **
5043  ** Suppose the action integer is N.  Then the action is determined as
5044  ** follows
5045 @@ -228,7 +210,7 @@
5046  ** If the index value yy_shift_ofst[S]+X is out of range or if the value
5047  ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
5048  ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
5049 -** and that yy_default[S] should be used instead.  
5050 +** and that yy_default[S] should be used instead.
5051  **
5052  ** The formula above is for computing the action when the lookahead is
5053  ** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
5054 @@ -248,67 +230,69 @@
5055  **  yy_default[]       Default action for each state.
5056  */
5057  static YYACTIONTYPE yy_action[] = {
5058 - /*     0 */     2,    3,    4,    5,   13,   14,   62,   15,    7,   44,
5059 - /*    10 */    20,   86,   16,   45,   28,   48,   40,   10,   39,   25,
5060 - /*    20 */    22,   49,   45,    8,   15,  102,    1,   20,   28,   18,
5061 - /*    30 */    57,   59,   19,   25,   22,   39,   19,   61,   98,   45,
5062 - /*    40 */    20,    6,   23,   24,   26,   28,   35,   57,   59,   12,
5063 - /*    50 */    25,   22,   28,   27,   36,   87,   29,   25,   22,   33,
5064 - /*    60 */    15,   30,   31,   20,   28,   38,    9,   17,   37,   25,
5065 - /*    70 */    22,   39,   42,   43,   10,   45,   11,   53,   54,   55,
5066 - /*    80 */    56,   28,   52,   57,   59,   34,   25,   22,   28,   27,
5067 - /*    90 */    32,   88,   41,   25,   22,   33,   28,   48,   46,   28,
5068 - /*   100 */    48,   25,   22,   58,   25,   22,   60,   21,   19,   47,
5069 - /*   110 */    51,   50,   25,   22,   88,   88,   93,
5070 + /*     0 */     2,    3,    4,    5,   13,   14,   63,   15,    7,   45,
5071 + /*    10 */    20,   88,   16,   46,   28,   49,   41,   10,   40,   25,
5072 + /*    20 */    22,   50,   46,    8,   15,  104,    1,   20,   28,   18,
5073 + /*    30 */    58,   60,    6,   25,   22,   40,   47,   62,   11,   46,
5074 + /*    40 */    20,    9,   23,   24,   26,   29,   89,   58,   60,   10,
5075 + /*    50 */    17,   38,   28,   27,   37,   19,   30,   25,   22,   34,
5076 + /*    60 */    15,  100,   20,   20,   23,   24,   26,   12,   19,   31,
5077 + /*    70 */    32,   40,   19,   44,   43,   46,   95,   35,   90,   89,
5078 + /*    80 */    28,   49,   42,   58,   60,   25,   22,   59,   28,   27,
5079 + /*    90 */    33,   48,   52,   25,   22,   34,   28,   49,   51,   28,
5080 + /*   100 */    36,   25,   22,   61,   25,   22,   89,   28,   39,   89,
5081 + /*   110 */    89,   89,   25,   22,   54,   55,   56,   57,   89,   28,
5082 + /*   120 */    53,   21,   89,   89,   25,   22,   25,   22,
5083  };
5084  static YYCODETYPE yy_lookahead[] = {
5085   /*     0 */    29,   30,   31,   32,   33,   34,    0,    1,   44,   38,
5086   /*    10 */     4,   15,   41,   16,   35,   36,   45,   46,   12,   40,
5087   /*    20 */    41,   42,   16,   15,    1,   27,   28,    4,   35,   36,
5088 - /*    30 */    24,   25,    5,   40,   41,   12,    5,   14,   11,   16,
5089 - /*    40 */     4,    1,    6,    7,    8,   35,   36,   24,   25,   28,
5090 - /*    50 */    40,   41,   35,   36,   37,   15,   39,   40,   41,   42,
5091 - /*    60 */     1,    9,   10,    4,   35,   36,   38,    2,    3,   40,
5092 - /*    70 */    41,   12,   28,   14,   46,   16,   13,   20,   21,   22,
5093 - /*    80 */    23,   35,   36,   24,   25,   11,   40,   41,   35,   36,
5094 - /*    90 */    37,   13,   13,   40,   41,   42,   35,   36,   17,   35,
5095 - /*   100 */    36,   40,   41,   42,   40,   41,   42,   35,    5,   18,
5096 - /*   110 */    43,   19,   40,   41,   47,   47,   13,
5097 + /*    30 */    24,   25,    1,   40,   41,   12,   17,   14,   13,   16,
5098 + /*    40 */     4,   38,    6,    7,    8,    9,   15,   24,   25,   46,
5099 + /*    50 */     2,    3,   35,   36,   37,    5,   39,   40,   41,   42,
5100 + /*    60 */     1,   11,    4,    4,    6,    7,    8,   28,    5,    9,
5101 + /*    70 */    10,   12,    5,   14,   28,   16,   13,   11,   13,   47,
5102 + /*    80 */    35,   36,   13,   24,   25,   40,   41,   42,   35,   36,
5103 + /*    90 */    37,   18,   43,   40,   41,   42,   35,   36,   19,   35,
5104 + /*   100 */    36,   40,   41,   42,   40,   41,   47,   35,   36,   47,
5105 + /*   110 */    47,   47,   40,   41,   20,   21,   22,   23,   47,   35,
5106 + /*   120 */    36,   35,   47,   47,   40,   41,   40,   41,
5107  };
5108  #define YY_SHIFT_USE_DFLT (-5)
5109  static signed char yy_shift_ofst[] = {
5110 - /*     0 */    -5,    6,   -5,   -5,   -5,   40,   -4,    8,   -3,   -5,
5111 - /*    10 */    63,   -5,   23,   -5,   -5,   -5,   65,   36,   31,   36,
5112 - /*    20 */    -5,   -5,   -5,   -5,   -5,   -5,   36,   27,   -5,   52,
5113 - /*    30 */    -5,   36,   -5,   74,   36,   31,   -5,   36,   31,   78,
5114 - /*    40 */    79,   -5,   59,   -5,   -5,   81,   91,   36,   31,   92,
5115 - /*    50 */    57,   36,  103,   -5,   -5,   -5,   -5,   36,   -5,   36,
5116 - /*    60 */    -5,   -5,
5117 + /*     0 */    -5,    6,   -5,   -5,   -5,   31,   -4,    8,   -3,   -5,
5118 + /*    10 */    25,   -5,   23,   -5,   -5,   -5,   48,   58,   67,   58,
5119 + /*    20 */    -5,   -5,   -5,   -5,   -5,   -5,   36,   50,   -5,   -5,
5120 + /*    30 */    60,   -5,   58,   -5,   66,   58,   67,   -5,   58,   67,
5121 + /*    40 */    65,   69,   -5,   59,   -5,   -5,   19,   73,   58,   67,
5122 + /*    50 */    79,   94,   58,   63,   -5,   -5,   -5,   -5,   58,   -5,
5123 + /*    60 */    58,   -5,   -5,
5124  };
5125  #define YY_REDUCE_USE_DFLT (-37)
5126  static signed char yy_reduce_ofst[] = {
5127 - /*     0 */    -2,  -29,  -37,  -37,  -37,  -36,  -37,  -37,   28,  -37,
5128 - /*    10 */   -37,   21,  -29,  -37,  -37,  -37,  -37,   -7,  -37,   72,
5129 + /*     0 */    -2,  -29,  -37,  -37,  -37,  -36,  -37,  -37,    3,  -37,
5130 + /*    10 */   -37,   39,  -29,  -37,  -37,  -37,  -37,   -7,  -37,   86,
5131   /*    20 */   -37,  -37,  -37,  -37,  -37,  -37,   17,  -37,  -37,  -37,
5132 - /*    30 */   -37,   53,  -37,  -37,   10,  -37,  -37,   29,  -37,  -37,
5133 - /*    40 */   -37,   44,  -29,  -37,  -37,  -37,  -37,  -21,  -37,  -37,
5134 - /*    50 */    67,   46,  -37,  -37,  -37,  -37,  -37,   61,  -37,   64,
5135 - /*    60 */   -37,  -37,
5136 + /*    30 */   -37,  -37,   53,  -37,  -37,   64,  -37,  -37,   72,  -37,
5137 + /*    40 */   -37,  -37,   46,  -29,  -37,  -37,  -37,  -37,  -21,  -37,
5138 + /*    50 */   -37,   49,   84,  -37,  -37,  -37,  -37,  -37,   45,  -37,
5139 + /*    60 */    61,  -37,  -37,
5140  };
5141  static YYACTIONTYPE yy_default[] = {
5142 - /*     0 */    64,  101,   63,   65,   66,  101,   67,  101,  101,   90,
5143 - /*    10 */   101,   64,  101,   68,   69,   70,  101,  101,   71,  101,
5144 - /*    20 */    73,   74,   76,   77,   78,   79,  101,   84,   75,  101,
5145 - /*    30 */    80,   82,   81,  101,  101,   85,   83,  101,   72,  101,
5146 - /*    40 */   101,   64,  101,   89,   91,  101,  101,  101,   98,  101,
5147 - /*    50 */   101,  101,  101,   94,   95,   96,   97,  101,   99,  101,
5148 - /*    60 */   100,   92,
5149 + /*     0 */    65,  103,   64,   66,   67,  103,   68,  103,  103,   92,
5150 + /*    10 */   103,   65,  103,   69,   70,   71,  103,  103,   72,  103,
5151 + /*    20 */    74,   75,   77,   78,   79,   80,  103,   86,   76,   81,
5152 + /*    30 */   103,   82,   84,   83,  103,  103,   87,   85,  103,   73,
5153 + /*    40 */   103,  103,   65,  103,   91,   93,  103,  103,  103,  100,
5154 + /*    50 */   103,  103,  103,  103,   96,   97,   98,   99,  103,  101,
5155 + /*    60 */   103,  102,   94,
5156  };
5157  #define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
5158  
5159  /* The next table maps tokens into fallback tokens.  If a construct
5160  ** like the following:
5161 -** 
5162 +**
5163  **      %fallback ID X Y Z.
5164  **
5165  ** appears in the grammer, then ID becomes a fallback token for X, Y,
5166 @@ -359,10 +343,10 @@
5167  #endif /* NDEBUG */
5168  
5169  #ifndef NDEBUG
5170 -/* 
5171 +/*
5172  ** Turn parser tracing on by giving a stream to which to write the trace
5173  ** and a prompt to preface each trace message.  Tracing is turned off
5174 -** by making either argument NULL 
5175 +** by making either argument NULL
5176  **
5177  ** Inputs:
5178  ** <ul>
5179 @@ -387,7 +371,7 @@
5180  #ifndef NDEBUG
5181  /* For tracing shifts, the names of all terminals and nonterminals
5182  ** are required.  The following table supplies these names */
5183 -static const char *yyTokenName[] = { 
5184 +static const char *yyTokenName[] = {
5185    "$",             "EOL",           "ASSIGN",        "APPEND",      
5186    "LKEY",          "PLUS",          "STRING",        "INTEGER",     
5187    "LPARAN",        "RPARAN",        "COMMA",         "ARRAY_ASSIGN",
5188 @@ -425,27 +409,28 @@
5189   /*  15 */ "value ::= STRING",
5190   /*  16 */ "value ::= INTEGER",
5191   /*  17 */ "value ::= array",
5192 - /*  18 */ "array ::= LPARAN aelements RPARAN",
5193 - /*  19 */ "aelements ::= aelements COMMA aelement",
5194 - /*  20 */ "aelements ::= aelements COMMA",
5195 - /*  21 */ "aelements ::= aelement",
5196 - /*  22 */ "aelement ::= expression",
5197 - /*  23 */ "aelement ::= stringop ARRAY_ASSIGN expression",
5198 - /*  24 */ "eols ::= EOL",
5199 - /*  25 */ "eols ::=",
5200 - /*  26 */ "globalstart ::= GLOBAL",
5201 - /*  27 */ "global ::= globalstart LCURLY metalines RCURLY",
5202 - /*  28 */ "condlines ::= condlines eols ELSE condline",
5203 - /*  29 */ "condlines ::= condline",
5204 - /*  30 */ "condline ::= context LCURLY metalines RCURLY",
5205 - /*  31 */ "context ::= DOLLAR SRVVARNAME LBRACKET stringop RBRACKET cond expression",
5206 - /*  32 */ "cond ::= EQ",
5207 - /*  33 */ "cond ::= MATCH",
5208 - /*  34 */ "cond ::= NE",
5209 - /*  35 */ "cond ::= NOMATCH",
5210 - /*  36 */ "stringop ::= expression",
5211 - /*  37 */ "include ::= INCLUDE stringop",
5212 - /*  38 */ "include_shell ::= INCLUDE_SHELL stringop",
5213 + /*  18 */ "array ::= LPARAN RPARAN",
5214 + /*  19 */ "array ::= LPARAN aelements RPARAN",
5215 + /*  20 */ "aelements ::= aelements COMMA aelement",
5216 + /*  21 */ "aelements ::= aelements COMMA",
5217 + /*  22 */ "aelements ::= aelement",
5218 + /*  23 */ "aelement ::= expression",
5219 + /*  24 */ "aelement ::= stringop ARRAY_ASSIGN expression",
5220 + /*  25 */ "eols ::= EOL",
5221 + /*  26 */ "eols ::=",
5222 + /*  27 */ "globalstart ::= GLOBAL",
5223 + /*  28 */ "global ::= globalstart LCURLY metalines RCURLY",
5224 + /*  29 */ "condlines ::= condlines eols ELSE condline",
5225 + /*  30 */ "condlines ::= condline",
5226 + /*  31 */ "condline ::= context LCURLY metalines RCURLY",
5227 + /*  32 */ "context ::= DOLLAR SRVVARNAME LBRACKET stringop RBRACKET cond expression",
5228 + /*  33 */ "cond ::= EQ",
5229 + /*  34 */ "cond ::= MATCH",
5230 + /*  35 */ "cond ::= NE",
5231 + /*  36 */ "cond ::= NOMATCH",
5232 + /*  37 */ "stringop ::= expression",
5233 + /*  38 */ "include ::= INCLUDE stringop",
5234 + /*  39 */ "include_shell ::= INCLUDE_SHELL stringop",
5235  };
5236  #endif /* NDEBUG */
5237  
5238 @@ -465,7 +450,7 @@
5239  #endif
5240  }
5241  
5242 -/* 
5243 +/*
5244  ** This function allocates a new parser.
5245  ** The only argument is a pointer to a function which works like
5246  ** malloc.
5247 @@ -496,7 +481,7 @@
5248      /* Here is inserted the actions which take place when a
5249      ** terminal or non-terminal is destroyed.  This can happen
5250      ** when the symbol is popped from the stack during a
5251 -    ** reduce or during error processing or when a parser is 
5252 +    ** reduce or during error processing or when a parser is
5253      ** being destroyed before it is finished parsing.
5254      **
5255      ** Note: during a reduce, the only symbols destroyed are those
5256 @@ -528,44 +513,44 @@
5257      case 23:
5258      case 24:
5259      case 25:
5260 -#line 160 "./configparser.y"
5261 +#line 143 "./configparser.y"
5262  { buffer_free((yypminor->yy0)); }
5263 -#line 533 "configparser.c"
5264 +#line 518 "configparser.c"
5265        break;
5266      case 35:
5267 -#line 151 "./configparser.y"
5268 +#line 134 "./configparser.y"
5269  { (yypminor->yy41)->free((yypminor->yy41)); }
5270 -#line 538 "configparser.c"
5271 +#line 523 "configparser.c"
5272        break;
5273      case 36:
5274 -#line 152 "./configparser.y"
5275 +#line 135 "./configparser.y"
5276  { (yypminor->yy41)->free((yypminor->yy41)); }
5277 -#line 543 "configparser.c"
5278 +#line 528 "configparser.c"
5279        break;
5280      case 37:
5281 -#line 153 "./configparser.y"
5282 +#line 136 "./configparser.y"
5283  { (yypminor->yy41)->free((yypminor->yy41)); }
5284 -#line 548 "configparser.c"
5285 +#line 533 "configparser.c"
5286        break;
5287      case 39:
5288 -#line 154 "./configparser.y"
5289 +#line 137 "./configparser.y"
5290  { array_free((yypminor->yy40)); }
5291 -#line 553 "configparser.c"
5292 +#line 538 "configparser.c"
5293        break;
5294      case 40:
5295 -#line 155 "./configparser.y"
5296 +#line 138 "./configparser.y"
5297  { array_free((yypminor->yy40)); }
5298 -#line 558 "configparser.c"
5299 +#line 543 "configparser.c"
5300        break;
5301      case 41:
5302 -#line 156 "./configparser.y"
5303 +#line 139 "./configparser.y"
5304  { buffer_free((yypminor->yy43)); }
5305 -#line 563 "configparser.c"
5306 +#line 548 "configparser.c"
5307        break;
5308      case 42:
5309 -#line 157 "./configparser.y"
5310 +#line 140 "./configparser.y"
5311  { buffer_free((yypminor->yy43)); }
5312 -#line 568 "configparser.c"
5313 +#line 553 "configparser.c"
5314        break;
5315      default:  break;   /* If no destructor action specified: do nothing */
5316    }
5317 @@ -597,7 +582,7 @@
5318    return yymajor;
5319  }
5320  
5321 -/* 
5322 +/*
5323  ** Deallocate and destroy a parser.  Destructors are all called for
5324  ** all stack elements before shutting the parser down.
5325  **
5326 @@ -633,7 +618,7 @@
5327  ){
5328    int i;
5329    int stateno = pParser->yystack[pParser->yyidx].stateno;
5330
5331 +
5332    /* if( pParser->yyidx<0 ) return YY_NO_ACTION;  */
5333    i = yy_shift_ofst[stateno];
5334    if( i==YY_SHIFT_USE_DFLT ){
5335 @@ -677,7 +662,7 @@
5336  ){
5337    int i;
5338    int stateno = pParser->yystack[pParser->yyidx].stateno;
5339
5340 +
5341    i = yy_reduce_ofst[stateno];
5342    if( i==YY_REDUCE_USE_DFLT ){
5343      return yy_default[stateno];
5344 @@ -759,6 +744,7 @@
5345    { 35, 1 },
5346    { 35, 1 },
5347    { 35, 1 },
5348 +  { 40, 2 },
5349    { 40, 3 },
5350    { 39, 3 },
5351    { 39, 2 },
5352 @@ -800,7 +786,7 @@
5353    configparserARG_FETCH;
5354    yymsp = &yypParser->yystack[yypParser->yyidx];
5355  #ifndef NDEBUG
5356 -  if( yyTraceFILE && yyruleno>=0 
5357 +  if( yyTraceFILE && yyruleno>=0
5358          && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
5359      fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
5360        yyRuleName[yyruleno]);
5361 @@ -832,9 +818,9 @@
5362          /* No destructor defined for global */
5363          break;
5364        case 5:
5365 -#line 134 "./configparser.y"
5366 +#line 116 "./configparser.y"
5367  { yymsp[-1].minor.yy78 = NULL; }
5368 -#line 837 "configparser.c"
5369 +#line 823 "configparser.c"
5370    yy_destructor(1,&yymsp[0].minor);
5371          break;
5372        case 6:
5373 @@ -847,10 +833,15 @@
5374    yy_destructor(1,&yymsp[0].minor);
5375          break;
5376        case 9:
5377 -#line 162 "./configparser.y"
5378 +#line 145 "./configparser.y"
5379  {
5380    buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5381 -  if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) {
5382 +  if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5383 +    fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
5384 +        ctx->current->context_ndx,
5385 +        ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5386 +    ctx->ok = 0;
5387 +  } else if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) {
5388      array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
5389      yymsp[0].minor.yy41 = NULL;
5390    } else {
5391 @@ -864,16 +855,21 @@
5392    buffer_free(yymsp[-2].minor.yy43);
5393    yymsp[-2].minor.yy43 = NULL;
5394  }
5395 -#line 867 "configparser.c"
5396 +#line 858 "configparser.c"
5397    yy_destructor(2,&yymsp[-1].minor);
5398          break;
5399        case 10:
5400 -#line 179 "./configparser.y"
5401 +#line 167 "./configparser.y"
5402  {
5403    array *vars = ctx->current->value;
5404    data_unset *du;
5405  
5406 -  if (NULL != (du = array_get_element(vars, yymsp[-2].minor.yy43->ptr))) {
5407 +  if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5408 +    fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
5409 +        ctx->current->context_ndx,
5410 +        ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5411 +    ctx->ok = 0;
5412 +  } else if (NULL != (du = array_get_element(vars, yymsp[-2].minor.yy43->ptr))) {
5413      /* exists in current block */
5414      du = configparser_merge_data(du, yymsp[0].minor.yy41);
5415      if (NULL == du) {
5416 @@ -883,6 +879,7 @@
5417        buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
5418        array_replace(vars, du);
5419      }
5420 +    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5421    } else if (NULL != (du = configparser_get_variable(ctx, yymsp[-2].minor.yy43))) {
5422      du = configparser_merge_data(du, yymsp[0].minor.yy41);
5423      if (NULL == du) {
5424 @@ -892,22 +889,20 @@
5425        buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
5426        array_insert_unique(ctx->current->value, du);
5427      }
5428 +    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5429    } else {
5430 -    fprintf(stderr, "Undefined config variable in conditional %d %s: %s\n", 
5431 -            ctx->current->context_ndx,
5432 -            ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5433 -    ctx->ok = 0;
5434 +    buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5435 +    array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
5436    }
5437    buffer_free(yymsp[-2].minor.yy43);
5438    yymsp[-2].minor.yy43 = NULL;
5439 -  yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5440    yymsp[0].minor.yy41 = NULL;
5441  }
5442 -#line 906 "configparser.c"
5443 +#line 901 "configparser.c"
5444    yy_destructor(3,&yymsp[-1].minor);
5445          break;
5446        case 11:
5447 -#line 214 "./configparser.y"
5448 +#line 206 "./configparser.y"
5449  {
5450    if (strchr(yymsp[0].minor.yy0->ptr, '.') == NULL) {
5451      yygotominor.yy43 = buffer_init_string("var.");
5452 @@ -919,10 +914,10 @@
5453      yymsp[0].minor.yy0 = NULL;
5454    }
5455  }
5456 -#line 922 "configparser.c"
5457 +#line 917 "configparser.c"
5458          break;
5459        case 12:
5460 -#line 226 "./configparser.y"
5461 +#line 218 "./configparser.y"
5462  {
5463    yygotominor.yy41 = configparser_merge_data(yymsp[-2].minor.yy41, yymsp[0].minor.yy41);
5464    if (NULL == yygotominor.yy41) {
5465 @@ -932,21 +927,38 @@
5466    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5467    yymsp[0].minor.yy41 = NULL;
5468  }
5469 -#line 935 "configparser.c"
5470 +#line 930 "configparser.c"
5471    yy_destructor(5,&yymsp[-1].minor);
5472          break;
5473        case 13:
5474 -#line 236 "./configparser.y"
5475 +#line 228 "./configparser.y"
5476  {
5477    yygotominor.yy41 = yymsp[0].minor.yy41;
5478    yymsp[0].minor.yy41 = NULL;
5479  }
5480 -#line 944 "configparser.c"
5481 +#line 939 "configparser.c"
5482          break;
5483        case 14:
5484 -#line 241 "./configparser.y"
5485 +#line 233 "./configparser.y"
5486  {
5487 -  yygotominor.yy41 = configparser_get_variable(ctx, yymsp[0].minor.yy43);
5488 +  if (strncmp(yymsp[0].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5489 +    char *env;
5490 +
5491 +    if (NULL != (env = getenv(yymsp[0].minor.yy43->ptr + 4))) {
5492 +      data_string *ds;
5493 +      ds = data_string_init();
5494 +      buffer_append_string(ds->value, env);
5495 +      yygotominor.yy41 = (data_unset *)ds;
5496 +    }
5497 +    else {
5498 +      yygotominor.yy41 = NULL;
5499 +      fprintf(stderr, "Undefined env variable: %s\n", yymsp[0].minor.yy43->ptr + 4);
5500 +      ctx->ok = 0;
5501 +    }
5502 +  } else if (NULL == (yygotominor.yy41 = configparser_get_variable(ctx, yymsp[0].minor.yy43))) {
5503 +    fprintf(stderr, "Undefined config variable: %s\n", yymsp[0].minor.yy43->ptr);
5504 +    ctx->ok = 0;
5505 +  }
5506    if (!yygotominor.yy41) {
5507      /* make a dummy so it won't crash */
5508      yygotominor.yy41 = (data_unset *)data_string_init();
5509 @@ -954,50 +966,59 @@
5510    buffer_free(yymsp[0].minor.yy43);
5511    yymsp[0].minor.yy43 = NULL;
5512  }
5513 -#line 957 "configparser.c"
5514 +#line 969 "configparser.c"
5515          break;
5516        case 15:
5517 -#line 251 "./configparser.y"
5518 +#line 260 "./configparser.y"
5519  {
5520    yygotominor.yy41 = (data_unset *)data_string_init();
5521    buffer_copy_string_buffer(((data_string *)(yygotominor.yy41))->value, yymsp[0].minor.yy0);
5522    buffer_free(yymsp[0].minor.yy0);
5523    yymsp[0].minor.yy0 = NULL;
5524  }
5525 -#line 967 "configparser.c"
5526 +#line 979 "configparser.c"
5527          break;
5528        case 16:
5529 -#line 258 "./configparser.y"
5530 +#line 267 "./configparser.y"
5531  {
5532    yygotominor.yy41 = (data_unset *)data_integer_init();
5533    ((data_integer *)(yygotominor.yy41))->value = strtol(yymsp[0].minor.yy0->ptr, NULL, 10);
5534    buffer_free(yymsp[0].minor.yy0);
5535    yymsp[0].minor.yy0 = NULL;
5536  }
5537 -#line 977 "configparser.c"
5538 +#line 989 "configparser.c"
5539          break;
5540        case 17:
5541 -#line 264 "./configparser.y"
5542 +#line 273 "./configparser.y"
5543  {
5544    yygotominor.yy41 = (data_unset *)data_array_init();
5545    array_free(((data_array *)(yygotominor.yy41))->value);
5546    ((data_array *)(yygotominor.yy41))->value = yymsp[0].minor.yy40;
5547    yymsp[0].minor.yy40 = NULL;
5548  }
5549 -#line 987 "configparser.c"
5550 +#line 999 "configparser.c"
5551          break;
5552        case 18:
5553 -#line 270 "./configparser.y"
5554 +#line 279 "./configparser.y"
5555 +{
5556 +  yygotominor.yy40 = array_init();
5557 +}
5558 +#line 1006 "configparser.c"
5559 +  yy_destructor(8,&yymsp[-1].minor);
5560 +  yy_destructor(9,&yymsp[0].minor);
5561 +        break;
5562 +      case 19:
5563 +#line 282 "./configparser.y"
5564  {
5565    yygotominor.yy40 = yymsp[-1].minor.yy40;
5566    yymsp[-1].minor.yy40 = NULL;
5567  }
5568 -#line 995 "configparser.c"
5569 +#line 1016 "configparser.c"
5570    yy_destructor(8,&yymsp[-2].minor);
5571    yy_destructor(9,&yymsp[0].minor);
5572          break;
5573 -      case 19:
5574 -#line 275 "./configparser.y"
5575 +      case 20:
5576 +#line 287 "./configparser.y"
5577  {
5578    if (buffer_is_empty(yymsp[0].minor.yy41->key) ||
5579        NULL == array_get_element(yymsp[-2].minor.yy40, yymsp[0].minor.yy41->key->ptr)) {
5580 @@ -1014,37 +1035,37 @@
5581    yygotominor.yy40 = yymsp[-2].minor.yy40;
5582    yymsp[-2].minor.yy40 = NULL;
5583  }
5584 -#line 1017 "configparser.c"
5585 +#line 1038 "configparser.c"
5586    yy_destructor(10,&yymsp[-1].minor);
5587          break;
5588 -      case 20:
5589 -#line 292 "./configparser.y"
5590 +      case 21:
5591 +#line 304 "./configparser.y"
5592  {
5593    yygotominor.yy40 = yymsp[-1].minor.yy40;
5594    yymsp[-1].minor.yy40 = NULL;
5595  }
5596 -#line 1026 "configparser.c"
5597 +#line 1047 "configparser.c"
5598    yy_destructor(10,&yymsp[0].minor);
5599          break;
5600 -      case 21:
5601 -#line 297 "./configparser.y"
5602 +      case 22:
5603 +#line 309 "./configparser.y"
5604  {
5605    yygotominor.yy40 = array_init();
5606    array_insert_unique(yygotominor.yy40, yymsp[0].minor.yy41);
5607    yymsp[0].minor.yy41 = NULL;
5608  }
5609 -#line 1036 "configparser.c"
5610 +#line 1057 "configparser.c"
5611          break;
5612 -      case 22:
5613 -#line 303 "./configparser.y"
5614 +      case 23:
5615 +#line 315 "./configparser.y"
5616  {
5617    yygotominor.yy41 = yymsp[0].minor.yy41;
5618    yymsp[0].minor.yy41 = NULL;
5619  }
5620 -#line 1044 "configparser.c"
5621 +#line 1065 "configparser.c"
5622          break;
5623 -      case 23:
5624 -#line 307 "./configparser.y"
5625 +      case 24:
5626 +#line 319 "./configparser.y"
5627  {
5628    buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5629    buffer_free(yymsp[-2].minor.yy43);
5630 @@ -1053,27 +1074,27 @@
5631    yygotominor.yy41 = yymsp[0].minor.yy41;
5632    yymsp[0].minor.yy41 = NULL;
5633  }
5634 -#line 1056 "configparser.c"
5635 +#line 1077 "configparser.c"
5636    yy_destructor(11,&yymsp[-1].minor);
5637          break;
5638 -      case 24:
5639 -  yy_destructor(1,&yymsp[0].minor);
5640 -        break;
5641        case 25:
5642 +  yy_destructor(1,&yymsp[0].minor);
5643          break;
5644        case 26:
5645 -#line 319 "./configparser.y"
5646 +        break;
5647 +      case 27:
5648 +#line 331 "./configparser.y"
5649  {
5650    data_config *dc;
5651    dc = (data_config *)array_get_element(ctx->srv->config_context, "global");
5652    assert(dc);
5653    configparser_push(ctx, dc, 0);
5654  }
5655 -#line 1072 "configparser.c"
5656 +#line 1093 "configparser.c"
5657    yy_destructor(12,&yymsp[0].minor);
5658          break;
5659 -      case 27:
5660 -#line 326 "./configparser.y"
5661 +      case 28:
5662 +#line 338 "./configparser.y"
5663  {
5664    data_config *cur;
5665    
5666 @@ -1082,16 +1103,16 @@
5667  
5668    assert(cur && ctx->current);
5669  
5670 -  yygotominor.yy0 = cur;
5671 +  yygotominor.yy78 = cur;
5672  }
5673 -#line 1087 "configparser.c"
5674 +#line 1108 "configparser.c"
5675          /* No destructor defined for globalstart */
5676    yy_destructor(13,&yymsp[-2].minor);
5677          /* No destructor defined for metalines */
5678    yy_destructor(14,&yymsp[0].minor);
5679          break;
5680 -      case 28:
5681 -#line 337 "./configparser.y"
5682 +      case 29:
5683 +#line 349 "./configparser.y"
5684  {
5685    assert(yymsp[-3].minor.yy78->context_ndx < yymsp[0].minor.yy78->context_ndx);
5686    yymsp[0].minor.yy78->prev = yymsp[-3].minor.yy78;
5687 @@ -1100,20 +1121,20 @@
5688    yymsp[-3].minor.yy78 = NULL;
5689    yymsp[0].minor.yy78 = NULL;
5690  }
5691 -#line 1103 "configparser.c"
5692 +#line 1124 "configparser.c"
5693          /* No destructor defined for eols */
5694    yy_destructor(15,&yymsp[-1].minor);
5695          break;
5696 -      case 29:
5697 -#line 346 "./configparser.y"
5698 +      case 30:
5699 +#line 358 "./configparser.y"
5700  {
5701    yygotominor.yy78 = yymsp[0].minor.yy78;
5702    yymsp[0].minor.yy78 = NULL;
5703  }
5704 -#line 1113 "configparser.c"
5705 +#line 1134 "configparser.c"
5706          break;
5707 -      case 30:
5708 -#line 351 "./configparser.y"
5709 +      case 31:
5710 +#line 363 "./configparser.y"
5711  {
5712    data_config *cur;
5713    
5714 @@ -1124,14 +1145,14 @@
5715  
5716    yygotominor.yy78 = cur;
5717  }
5718 -#line 1127 "configparser.c"
5719 +#line 1148 "configparser.c"
5720          /* No destructor defined for context */
5721    yy_destructor(13,&yymsp[-2].minor);
5722          /* No destructor defined for metalines */
5723    yy_destructor(14,&yymsp[0].minor);
5724          break;
5725 -      case 31:
5726 -#line 362 "./configparser.y"
5727 +      case 32:
5728 +#line 374 "./configparser.y"
5729  {
5730    data_config *dc;
5731    buffer *b, *rvalue, *op;
5732 @@ -1266,45 +1287,45 @@
5733    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5734    yymsp[0].minor.yy41 = NULL;
5735  }
5736 -#line 1269 "configparser.c"
5737 +#line 1290 "configparser.c"
5738    yy_destructor(16,&yymsp[-6].minor);
5739    yy_destructor(18,&yymsp[-4].minor);
5740    yy_destructor(19,&yymsp[-2].minor);
5741          break;
5742 -      case 32:
5743 -#line 496 "./configparser.y"
5744 +      case 33:
5745 +#line 508 "./configparser.y"
5746  {
5747    yygotominor.yy27 = CONFIG_COND_EQ;
5748  }
5749 -#line 1279 "configparser.c"
5750 +#line 1300 "configparser.c"
5751    yy_destructor(20,&yymsp[0].minor);
5752          break;
5753 -      case 33:
5754 -#line 499 "./configparser.y"
5755 +      case 34:
5756 +#line 511 "./configparser.y"
5757  {
5758    yygotominor.yy27 = CONFIG_COND_MATCH;
5759  }
5760 -#line 1287 "configparser.c"
5761 +#line 1308 "configparser.c"
5762    yy_destructor(21,&yymsp[0].minor);
5763          break;
5764 -      case 34:
5765 -#line 502 "./configparser.y"
5766 +      case 35:
5767 +#line 514 "./configparser.y"
5768  {
5769    yygotominor.yy27 = CONFIG_COND_NE;
5770  }
5771 -#line 1295 "configparser.c"
5772 +#line 1316 "configparser.c"
5773    yy_destructor(22,&yymsp[0].minor);
5774          break;
5775 -      case 35:
5776 -#line 505 "./configparser.y"
5777 +      case 36:
5778 +#line 517 "./configparser.y"
5779  {
5780    yygotominor.yy27 = CONFIG_COND_NOMATCH;
5781  }
5782 -#line 1303 "configparser.c"
5783 +#line 1324 "configparser.c"
5784    yy_destructor(23,&yymsp[0].minor);
5785          break;
5786 -      case 36:
5787 -#line 509 "./configparser.y"
5788 +      case 37:
5789 +#line 521 "./configparser.y"
5790  {
5791    yygotominor.yy43 = NULL;
5792    if (ctx->ok) {
5793 @@ -1321,10 +1342,10 @@
5794    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5795    yymsp[0].minor.yy41 = NULL;
5796  }
5797 -#line 1324 "configparser.c"
5798 +#line 1345 "configparser.c"
5799          break;
5800 -      case 37:
5801 -#line 526 "./configparser.y"
5802 +      case 38:
5803 +#line 538 "./configparser.y"
5804  {
5805    if (ctx->ok) {
5806      if (0 != config_parse_file(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
5807 @@ -1334,11 +1355,11 @@
5808      yymsp[0].minor.yy43 = NULL;
5809    }
5810  }
5811 -#line 1337 "configparser.c"
5812 +#line 1358 "configparser.c"
5813    yy_destructor(24,&yymsp[-1].minor);
5814          break;
5815 -      case 38:
5816 -#line 536 "./configparser.y"
5817 +      case 39:
5818 +#line 548 "./configparser.y"
5819  {
5820    if (ctx->ok) {
5821      if (0 != config_parse_cmd(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
5822 @@ -1348,7 +1369,7 @@
5823      yymsp[0].minor.yy43 = NULL;
5824    }
5825  }
5826 -#line 1351 "configparser.c"
5827 +#line 1372 "configparser.c"
5828    yy_destructor(25,&yymsp[-1].minor);
5829          break;
5830    };
5831 @@ -1378,11 +1399,11 @@
5832    while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
5833    /* Here code is inserted which will be executed whenever the
5834    ** parser fails */
5835 -#line 125 "./configparser.y"
5836 +#line 107 "./configparser.y"
5837  
5838    ctx->ok = 0;
5839  
5840 -#line 1385 "configparser.c"
5841 +#line 1406 "configparser.c"
5842    configparserARG_STORE; /* Suppress warning about unused %extra_argument variable */
5843  }
5844  
5845 @@ -1489,7 +1510,7 @@
5846  #ifdef YYERRORSYMBOL
5847        /* A syntax error has occurred.
5848        ** The response to an error depends upon whether or not the
5849 -      ** grammar defines an error token "ERROR".  
5850 +      ** grammar defines an error token "ERROR".
5851        **
5852        ** This is what we do if the grammar does define ERROR:
5853        **
5854 --- ../lighttpd-1.4.11/src/configparser.y       2006-01-26 18:46:25.000000000 +0200
5855 +++ lighttpd-1.4.12/src/configparser.y  2006-07-16 00:26:04.000000000 +0300
5856 @@ -21,52 +21,34 @@
5857      dc->parent = ctx->current;
5858      array_insert_unique(dc->parent->childs, (data_unset *)dc);
5859    }
5860 -  array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
5861 +  buffer_ptr_append(ctx->configs_stack, (void *)ctx->current);
5862    ctx->current = dc;
5863  }
5864  
5865  static data_config *configparser_pop(config_t *ctx) {
5866    data_config *old = ctx->current;
5867 -  ctx->current = (data_config *) array_pop(ctx->configs_stack);
5868 +  ctx->current = (data_config *) buffer_ptr_pop(ctx->configs_stack);
5869    return old;
5870  }
5871  
5872  /* return a copied variable */
5873  static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
5874 -  if (strncmp(key->ptr, "env.", sizeof("env.") - 1) == 0) {
5875 -    char *env;
5876 -
5877 -    if (NULL != (env = getenv(key->ptr + 4))) {
5878 -      data_string *ds;
5879 -      ds = data_string_init();
5880 -      buffer_append_string(ds->value, env);
5881 -      return (data_unset *)ds;
5882 -    }
5883 -
5884 -    fprintf(stderr, "Undefined env variable: %s\n", key->ptr + 4);
5885 -    ctx->ok = 0;
5886 -
5887 -    return NULL;
5888 -  } else {
5889 -    data_unset *du;
5890 -    data_config *dc;
5891 +  data_unset *du;
5892 +  data_config *dc;
5893  
5894  #if 0
5895 -    fprintf(stderr, "get var %s\n", key->ptr);
5896 +  fprintf(stderr, "get var %s\n", key->ptr);
5897  #endif
5898 -    for (dc = ctx->current; dc; dc = dc->parent) {
5899 +  for (dc = ctx->current; dc; dc = dc->parent) {
5900  #if 0
5901 -      fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
5902 -      array_print(dc->value, 0);
5903 +    fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
5904 +    array_print(dc->value, 0);
5905  #endif
5906 -      if (NULL != (du = array_get_element(dc->value, key->ptr))) {
5907 -        return du->copy(du);
5908 -      }
5909 +    if (NULL != (du = array_get_element(dc->value, key->ptr))) {
5910 +      return du->copy(du);
5911      }
5912 -    fprintf(stderr, "Undefined config variable: %s\n", key->ptr);
5913 -    ctx->ok = 0;
5914 -    return NULL;
5915    }
5916 +  return NULL;
5917  }
5918  
5919  /* op1 is to be eat/return by this function, op1->key is not cared
5920 @@ -141,6 +123,7 @@
5921  %type       aelement               {data_unset *}
5922  %type       condline               {data_config *}
5923  %type       condlines              {data_config *}
5924 +%type       global                 {data_config *}
5925  %type       aelements              {array *}
5926  %type       array                  {array *}
5927  %type       key                    {buffer *}
5928 @@ -161,7 +144,12 @@
5929  
5930  varline ::= key(A) ASSIGN expression(B). {
5931    buffer_copy_string_buffer(B->key, A);
5932 -  if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
5933 +  if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
5934 +    fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
5935 +        ctx->current->context_ndx,
5936 +        ctx->current->key->ptr, A->ptr);
5937 +    ctx->ok = 0;
5938 +  } else if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
5939      array_insert_unique(ctx->current->value, B);
5940      B = NULL;
5941    } else {
5942 @@ -180,7 +168,12 @@
5943    array *vars = ctx->current->value;
5944    data_unset *du;
5945  
5946 -  if (NULL != (du = array_get_element(vars, A->ptr))) {
5947 +  if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
5948 +    fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
5949 +        ctx->current->context_ndx,
5950 +        ctx->current->key->ptr, A->ptr);
5951 +    ctx->ok = 0;
5952 +  } else if (NULL != (du = array_get_element(vars, A->ptr))) {
5953      /* exists in current block */
5954      du = configparser_merge_data(du, B);
5955      if (NULL == du) {
5956 @@ -190,6 +183,7 @@
5957        buffer_copy_string_buffer(du->key, A);
5958        array_replace(vars, du);
5959      }
5960 +    B->free(B);
5961    } else if (NULL != (du = configparser_get_variable(ctx, A))) {
5962      du = configparser_merge_data(du, B);
5963      if (NULL == du) {
5964 @@ -199,15 +193,13 @@
5965        buffer_copy_string_buffer(du->key, A);
5966        array_insert_unique(ctx->current->value, du);
5967      }
5968 +    B->free(B);
5969    } else {
5970 -    fprintf(stderr, "Undefined config variable in conditional %d %s: %s\n", 
5971 -            ctx->current->context_ndx,
5972 -            ctx->current->key->ptr, A->ptr);
5973 -    ctx->ok = 0;
5974 +    buffer_copy_string_buffer(B->key, A);
5975 +    array_insert_unique(ctx->current->value, B);
5976    }
5977    buffer_free(A);
5978    A = NULL;
5979 -  B->free(B);
5980    B = NULL;
5981  }
5982  
5983 @@ -239,7 +231,24 @@
5984  }
5985  
5986  value(A) ::= key(B). {
5987 -  A = configparser_get_variable(ctx, B);
5988 +  if (strncmp(B->ptr, "env.", sizeof("env.") - 1) == 0) {
5989 +    char *env;
5990 +
5991 +    if (NULL != (env = getenv(B->ptr + 4))) {
5992 +      data_string *ds;
5993 +      ds = data_string_init();
5994 +      buffer_append_string(ds->value, env);
5995 +      A = (data_unset *)ds;
5996 +    }
5997 +    else {
5998 +      A = NULL;
5999 +      fprintf(stderr, "Undefined env variable: %s\n", B->ptr + 4);
6000 +      ctx->ok = 0;
6001 +    }
6002 +  } else if (NULL == (A = configparser_get_variable(ctx, B))) {
6003 +    fprintf(stderr, "Undefined config variable: %s\n", B->ptr);
6004 +    ctx->ok = 0;
6005 +  }
6006    if (!A) {
6007      /* make a dummy so it won't crash */
6008      A = (data_unset *)data_string_init();
6009 @@ -267,6 +276,9 @@
6010    ((data_array *)(A))->value = B;
6011    B = NULL;
6012  }
6013 +array(A) ::= LPARAN RPARAN. {
6014 +  A = array_init();
6015 +}
6016  array(A) ::= LPARAN aelements(B) RPARAN. {
6017    A = B;
6018    B = NULL;
6019 --- ../lighttpd-1.4.11/src/connections-glue.c   2005-09-12 10:04:23.000000000 +0300
6020 +++ lighttpd-1.4.12/src/connections-glue.c      2006-07-16 00:26:03.000000000 +0300
6021 @@ -13,7 +13,7 @@
6022         case CON_STATE_REQUEST_END: return "req-end";
6023         case CON_STATE_RESPONSE_START: return "resp-start";
6024         case CON_STATE_RESPONSE_END: return "resp-end";
6025 -       default: return "(unknown)";    
6026 +       default: return "(unknown)";
6027         }
6028  }
6029  
6030 @@ -30,15 +30,15 @@
6031         case CON_STATE_REQUEST_END: return "Q";
6032         case CON_STATE_RESPONSE_START: return "s";
6033         case CON_STATE_RESPONSE_END: return "S";
6034 -       default: return "x";    
6035 +       default: return "x";
6036         }
6037  }
6038  
6039  int connection_set_state(server *srv, connection *con, connection_state_t state) {
6040         UNUSED(srv);
6041 -       
6042 +
6043         con->state = state;
6044 -       
6045 +
6046         return 0;
6047  }
6048  
6049 --- ../lighttpd-1.4.11/src/connections.c        2006-03-05 22:14:53.000000000 +0200
6050 +++ lighttpd-1.4.12/src/connections.c   2006-07-18 13:03:40.000000000 +0300
6051 @@ -2,7 +2,6 @@
6052  
6053  #include <stdlib.h>
6054  #include <stdio.h>
6055 -#include <unistd.h>
6056  #include <errno.h>
6057  #include <string.h>
6058  #include <fcntl.h>
6059 @@ -26,8 +25,8 @@
6060  #include "inet_ntop_cache.h"
6061  
6062  #ifdef USE_OPENSSL
6063 -# include <openssl/ssl.h> 
6064 -# include <openssl/err.h> 
6065 +# include <openssl/ssl.h>
6066 +# include <openssl/err.h>
6067  #endif
6068  
6069  #ifdef HAVE_SYS_FILIO_H
6070 @@ -35,15 +34,16 @@
6071  #endif
6072  
6073  #include "sys-socket.h"
6074 +#include "sys-files.h"
6075  
6076  typedef struct {
6077 -               PLUGIN_DATA;
6078 +       PLUGIN_DATA;
6079  } plugin_data;
6080  
6081  static connection *connections_get_new_connection(server *srv) {
6082         connections *conns = srv->conns;
6083         size_t i;
6084 -       
6085 +
6086         if (conns->size == 0) {
6087                 conns->size = 128;
6088                 conns->ptr = NULL;
6089 @@ -54,21 +54,14 @@
6090         } else if (conns->size == conns->used) {
6091                 conns->size += 128;
6092                 conns->ptr = realloc(conns->ptr, sizeof(*conns->ptr) * conns->size);
6093 -               
6094 +
6095                 for (i = conns->used; i < conns->size; i++) {
6096                         conns->ptr[i] = connection_init(srv);
6097                 }
6098         }
6099  
6100         connection_reset(srv, conns->ptr[conns->used]);
6101 -#if 0  
6102 -       fprintf(stderr, "%s.%d: add: ", __FILE__, __LINE__);
6103 -       for (i = 0; i < conns->used + 1; i++) {
6104 -               fprintf(stderr, "%d ", conns->ptr[i]->fd);
6105 -       }
6106 -       fprintf(stderr, "\n");
6107 -#endif 
6108 -       
6109 +
6110         conns->ptr[conns->used]->ndx = conns->used;
6111         return conns->ptr[conns->used++];
6112  }
6113 @@ -77,263 +70,134 @@
6114         size_t i;
6115         connections *conns = srv->conns;
6116         connection *temp;
6117 -       
6118 +
6119         if (con == NULL) return -1;
6120 -       
6121 +
6122         if (-1 == con->ndx) return -1;
6123 -       
6124 +
6125         i = con->ndx;
6126 -       
6127 +
6128         /* not last element */
6129 -       
6130 +
6131         if (i != conns->used - 1) {
6132                 temp = conns->ptr[i];
6133                 conns->ptr[i] = conns->ptr[conns->used - 1];
6134                 conns->ptr[conns->used - 1] = temp;
6135 -               
6136 +
6137                 conns->ptr[i]->ndx = i;
6138                 conns->ptr[conns->used - 1]->ndx = -1;
6139         }
6140 -       
6141 +
6142         conns->used--;
6143 -       
6144 +
6145         con->ndx = -1;
6146 -#if 0
6147 -       fprintf(stderr, "%s.%d: del: (%d)", __FILE__, __LINE__, conns->used);
6148 -       for (i = 0; i < conns->used; i++) {
6149 -               fprintf(stderr, "%d ", conns->ptr[i]->fd);
6150 -       }
6151 -       fprintf(stderr, "\n");
6152 -#endif 
6153 +
6154         return 0;
6155  }
6156  
6157  int connection_close(server *srv, connection *con) {
6158  #ifdef USE_OPENSSL
6159         server_socket *srv_sock = con->srv_socket;
6160 -#endif
6161 -       
6162 -#ifdef USE_OPENSSL
6163 +
6164         if (srv_sock->is_ssl) {
6165 -               if (con->ssl) SSL_free(con->ssl);
6166 -               con->ssl = NULL;
6167 +               if (con->sock->ssl) SSL_free(con->sock->ssl);
6168 +               con->sock->ssl = NULL;
6169         }
6170  #endif
6171 -       
6172 -       fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
6173 -       fdevent_unregister(srv->ev, con->fd);
6174 -#ifdef __WIN32
6175 -       if (closesocket(con->fd)) {
6176 -               log_error_write(srv, __FILE__, __LINE__, "sds",
6177 -                               "(warning) close:", con->fd, strerror(errno));
6178 -       }
6179 -#else
6180 -       if (close(con->fd)) {
6181 +
6182 +       fdevent_event_del(srv->ev, con->sock);
6183 +       fdevent_unregister(srv->ev, con->sock);
6184 +
6185 +       if (closesocket(con->sock->fd)) {
6186                 log_error_write(srv, __FILE__, __LINE__, "sds",
6187 -                               "(warning) close:", con->fd, strerror(errno));
6188 +                               "(warning) close:", con->sock->fd, strerror(errno));
6189         }
6190 -#endif
6191 -       
6192 +
6193         srv->cur_fds--;
6194 -#if 0
6195 -       log_error_write(srv, __FILE__, __LINE__, "sd",
6196 -                       "closed()", con->fd);
6197 -#endif
6198 -       
6199 +
6200         connection_del(srv, con);
6201         connection_set_state(srv, con, CON_STATE_CONNECT);
6202 -       
6203 +
6204         return 0;
6205  }
6206  
6207  #if 0
6208  static void dump_packet(const unsigned char *data, size_t len) {
6209         size_t i, j;
6210 -       
6211 +
6212         if (len == 0) return;
6213 -       
6214 +
6215         for (i = 0; i < len; i++) {
6216                 if (i % 16 == 0) fprintf(stderr, "  ");
6217 -               
6218 +
6219                 fprintf(stderr, "%02x ", data[i]);
6220 -               
6221 +
6222                 if ((i + 1) % 16 == 0) {
6223                         fprintf(stderr, "  ");
6224                         for (j = 0; j <= i % 16; j++) {
6225                                 unsigned char c;
6226 -                               
6227 +
6228                                 if (i-15+j >= len) break;
6229 -                               
6230 +
6231                                 c = data[i-15+j];
6232 -                               
6233 +
6234                                 fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
6235                         }
6236 -                       
6237 +
6238                         fprintf(stderr, "\n");
6239                 }
6240         }
6241 -       
6242 +
6243         if (len % 16 != 0) {
6244                 for (j = i % 16; j < 16; j++) {
6245                         fprintf(stderr, "   ");
6246                 }
6247 -               
6248 +
6249                 fprintf(stderr, "  ");
6250                 for (j = i & ~0xf; j < len; j++) {
6251                         unsigned char c;
6252 -                       
6253 +
6254                         c = data[j];
6255                         fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
6256                 }
6257                 fprintf(stderr, "\n");
6258         }
6259  }
6260 -#endif 
6261 -
6262 -static int connection_handle_read(server *srv, connection *con) {
6263 -       int len;
6264 -       buffer *b;
6265 -       int toread;
6266 -#ifdef USE_OPENSSL
6267 -       server_socket *srv_sock = con->srv_socket;
6268  #endif
6269  
6270 -       b = chunkqueue_get_append_buffer(con->read_queue);
6271 -       buffer_prepare_copy(b, 4096);
6272 -
6273 -#ifdef USE_OPENSSL
6274 -       if (srv_sock->is_ssl) {
6275 -               len = SSL_read(con->ssl, b->ptr, b->size - 1);
6276 -       } else {
6277 -               if (ioctl(con->fd, FIONREAD, &toread)) {
6278 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
6279 -                                       "unexpected end-of-file:",
6280 -                                       con->fd);
6281 -                       return -1;
6282 -               }
6283 -               buffer_prepare_copy(b, toread);
6284 +static network_status_t connection_handle_read(server *srv, connection *con) {
6285 +       off_t oldlen, newlen;
6286  
6287 -               len = read(con->fd, b->ptr, b->size - 1);
6288 -       }
6289 -#elif defined(__WIN32)
6290 -       len = recv(con->fd, b->ptr, b->size - 1, 0);
6291 -#else
6292 -       if (ioctl(con->fd, FIONREAD, &toread)) {
6293 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
6294 -                               "unexpected end-of-file:",
6295 -                               con->fd);
6296 -               return -1;
6297 -       }
6298 -       buffer_prepare_copy(b, toread);
6299 +       oldlen = chunkqueue_length(con->read_queue);
6300  
6301 -       len = read(con->fd, b->ptr, b->size - 1);
6302 -#endif
6303 -       
6304 -       if (len < 0) {
6305 +       switch(network_read_chunkqueue(srv, con, con->read_queue)) {
6306 +       case NETWORK_STATUS_SUCCESS:
6307 +               break;
6308 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
6309 +               con->is_readable = 0;
6310 +               return NETWORK_STATUS_WAIT_FOR_EVENT;
6311 +       case NETWORK_STATUS_INTERRUPTED:
6312 +               con->is_readable = 1;
6313 +               return NETWORK_STATUS_WAIT_FOR_EVENT;
6314 +       case NETWORK_STATUS_CONNECTION_CLOSE:
6315 +               /* pipelining */
6316 +               con->is_readable = 0;
6317 +               return NETWORK_STATUS_CONNECTION_CLOSE;
6318 +       case NETWORK_STATUS_FATAL_ERROR:
6319                 con->is_readable = 0;
6320 -               
6321 -#ifdef USE_OPENSSL
6322 -               if (srv_sock->is_ssl) {
6323 -                       int r, ssl_err;
6324 -                       
6325 -                       switch ((r = SSL_get_error(con->ssl, len))) {
6326 -                       case SSL_ERROR_WANT_READ:
6327 -                               return 0;
6328 -                       case SSL_ERROR_SYSCALL:
6329 -                               /**
6330 -                                * man SSL_get_error()
6331 -                                * 
6332 -                                * SSL_ERROR_SYSCALL
6333 -                                *   Some I/O error occurred.  The OpenSSL error queue may contain more 
6334 -                                *   information on the error.  If the error queue is empty (i.e.
6335 -                                *   ERR_get_error() returns 0), ret can be used to find out more about 
6336 -                                *   the error: If ret == 0, an EOF was observed that violates the
6337 -                                *   protocol.  If ret == -1, the underlying BIO reported an I/O error 
6338 -                                *   (for socket I/O on Unix systems, consult errno for details).
6339 -                                *
6340 -                                */
6341 -                               while((ssl_err = ERR_get_error())) {
6342 -                                       /* get all errors from the error-queue */
6343 -                                       log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:", 
6344 -                                                       r, ERR_error_string(ssl_err, NULL));
6345 -                               }
6346  
6347 -                               switch(errno) {
6348 -                               default:
6349 -                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", 
6350 -                                                       len, r, errno,
6351 -                                                       strerror(errno));
6352 -                                       break;
6353 -                               }
6354 -                               
6355 -                               break;
6356 -                       case SSL_ERROR_ZERO_RETURN:
6357 -                               /* clean shutdown on the remote side */
6358 -                               
6359 -                               if (r == 0) {
6360 -                                       /* FIXME: later */
6361 -                               }
6362 -                               
6363 -                               /* fall thourgh */
6364 -                       default:
6365 -                               while((ssl_err = ERR_get_error())) {
6366 -                                       /* get all errors from the error-queue */
6367 -                                       log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:", 
6368 -                                                       r, ERR_error_string(ssl_err, NULL));
6369 -                               }
6370 -                               break;
6371 -                       }
6372 -               } else {
6373 -                       if (errno == EAGAIN) return 0;
6374 -                       if (errno == EINTR) {
6375 -                               /* we have been interrupted before we could read */
6376 -                               con->is_readable = 1;
6377 -                               return 0;
6378 -                       }
6379 -               
6380 -                       if (errno != ECONNRESET) {
6381 -                               /* expected for keep-alive */
6382 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
6383 -                       }
6384 -               }
6385 -#else
6386 -               if (errno == EAGAIN) return 0;
6387 -               if (errno == EINTR) {
6388 -                       /* we have been interrupted before we could read */
6389 -                       con->is_readable = 1;
6390 -                       return 0;
6391 -               }
6392 -               
6393 -               if (errno != ECONNRESET) {
6394 -                       /* expected for keep-alive */
6395 -                       log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
6396 -               }
6397 -#endif
6398                 connection_set_state(srv, con, CON_STATE_ERROR);
6399 -               
6400 -               return -1;
6401 -       } else if (len == 0) {
6402 -               con->is_readable = 0;
6403 -               /* the other end close the connection -> KEEP-ALIVE */
6404 +               return NETWORK_STATUS_FATAL_ERROR;
6405 +       default:
6406 +               SEGFAULT();
6407 +               break;
6408 +       }
6409  
6410 -               /* pipelining */
6411 +       newlen = chunkqueue_length(con->read_queue);
6412  
6413 -               return -2;
6414 -       } else if ((size_t)len < b->size - 1) {
6415 -               /* we got less then expected, wait for the next fd-event */
6416 -               
6417 -               con->is_readable = 0;
6418 -       }
6419 -       
6420 -       b->used = len;
6421 -       b->ptr[b->used++] = '\0';
6422 -       
6423 -       con->bytes_read += len;
6424 -#if 0
6425 -       dump_packet(b->ptr, len);
6426 -#endif
6427 -       
6428 -       return 0;
6429 +       con->bytes_read += (newlen - oldlen);
6430 +
6431 +       return NETWORK_STATUS_SUCCESS;
6432  }
6433  
6434  static int connection_handle_write_prepare(server *srv, connection *con) {
6435 @@ -343,6 +207,7 @@
6436                 case HTTP_METHOD_GET:
6437                 case HTTP_METHOD_POST:
6438                 case HTTP_METHOD_HEAD:
6439 +                       /* webdav */
6440                 case HTTP_METHOD_PUT:
6441                 case HTTP_METHOD_MKCOL:
6442                 case HTTP_METHOD_DELETE:
6443 @@ -350,12 +215,14 @@
6444                 case HTTP_METHOD_MOVE:
6445                 case HTTP_METHOD_PROPFIND:
6446                 case HTTP_METHOD_PROPPATCH:
6447 +               case HTTP_METHOD_LOCK:
6448 +               case HTTP_METHOD_UNLOCK:
6449                         break;
6450                 case HTTP_METHOD_OPTIONS:
6451                         /*
6452                          * 400 is coming from the request-parser BEFORE uri.path is set
6453 -                        * 403 is from the response handler when noone else catched it 
6454 -                        * 
6455 +                        * 403 is from the response handler when noone else catched it
6456 +                        *
6457                          * */
6458                         if (con->uri.path->used &&
6459                             con->uri.path->ptr[0] != '*') {
6460 @@ -381,55 +248,60 @@
6461                         break;
6462                 }
6463         }
6464 -       
6465 +
6466         if (con->http_status == 0) {
6467                 con->http_status = 403;
6468         }
6469 -       
6470 +
6471         switch(con->http_status) {
6472         case 400: /* class: header + custom body */
6473         case 401:
6474         case 403:
6475         case 404:
6476         case 408:
6477 +       case 409:
6478 +       case 410:
6479         case 411:
6480         case 416:
6481         case 423:
6482         case 500:
6483         case 501:
6484 +       case 502:
6485         case 503:
6486 -       case 505: 
6487 +       case 504:
6488 +       case 505:
6489 +       case 509:
6490                 if (con->mode != DIRECT) break;
6491 -               
6492 +
6493                 con->file_finished = 0;
6494 -               
6495 +
6496                 buffer_reset(con->physical.path);
6497 -                               
6498 +
6499                 /* try to send static errorfile */
6500                 if (!buffer_is_empty(con->conf.errorfile_prefix)) {
6501                         stat_cache_entry *sce = NULL;
6502 -                       
6503 +
6504                         buffer_copy_string_buffer(con->physical.path, con->conf.errorfile_prefix);
6505                         buffer_append_string(con->physical.path, get_http_status_body_name(con->http_status));
6506 -                       
6507 +
6508                         if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
6509                                 con->file_finished = 1;
6510 -                               
6511 +
6512                                 http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
6513                                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
6514                         }
6515                 }
6516 -               
6517 -               if (!con->file_finished) {                      
6518 +
6519 +               if (!con->file_finished) {
6520                         buffer *b;
6521 -                       
6522 +
6523                         buffer_reset(con->physical.path);
6524 -                       
6525 +
6526                         con->file_finished = 1;
6527                         b = chunkqueue_get_append_buffer(con->write_queue);
6528 -                               
6529 +
6530                         /* build default error-page */
6531 -                       buffer_copy_string(b, 
6532 +                       buffer_copy_string(b,
6533                                            "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
6534                                            "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
6535                                            "         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
6536 @@ -439,7 +311,7 @@
6537                         buffer_append_long(b, con->http_status);
6538                         buffer_append_string(b, " - ");
6539                         buffer_append_string(b, get_http_status_name(con->http_status));
6540 -                       
6541 +
6542                         buffer_append_string(b,
6543                                              "</title>\n"
6544                                              " </head>\n"
6545 @@ -448,12 +320,12 @@
6546                         buffer_append_long(b, con->http_status);
6547                         buffer_append_string(b, " - ");
6548                         buffer_append_string(b, get_http_status_name(con->http_status));
6549 -                       
6550 -                       buffer_append_string(b,"</h1>\n" 
6551 +
6552 +                       buffer_append_string(b,"</h1>\n"
6553                                              " </body>\n"
6554                                              "</html>\n"
6555                                              );
6556 -                       
6557 +
6558                         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
6559                 }
6560                 /* fall through */
6561 @@ -463,10 +335,10 @@
6562         case 301:
6563         case 302:
6564                 break;
6565 -               
6566 +
6567         case 206: /* write_queue is already prepared */
6568                 con->file_finished = 1;
6569 -               
6570 +
6571                 break;
6572         case 205: /* class: header only */
6573         case 304:
6574 @@ -474,19 +346,19 @@
6575                 /* disable chunked encoding again as we have no body */
6576                 con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
6577                 chunkqueue_reset(con->write_queue);
6578 -               
6579 +
6580                 con->file_finished = 1;
6581                 break;
6582         }
6583 -       
6584 +
6585  
6586         if (con->file_finished) {
6587 -               /* we have all the content and chunked encoding is not used, set a content-length */ 
6588 -               
6589 -               if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) && 
6590 +               /* we have all the content and chunked encoding is not used, set a content-length */
6591 +
6592 +               if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) &&
6593                     (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) {
6594                         buffer_copy_off_t(srv->tmp_buf, chunkqueue_length(con->write_queue));
6595 -               
6596 +
6597                         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf));
6598                 }
6599         } else {
6600 @@ -495,77 +367,79 @@
6601                     ((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0)) {
6602                         con->keep_alive = 0;
6603                 }
6604 -               
6605 +
6606                 if (0 == (con->parsed_response & HTTP_CONNECTION)) {
6607                         /* (f)cgi did'nt send Connection: header
6608 -                        *                          
6609 +                        *
6610                          * shall we ?
6611                          */
6612                         if (((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) &&
6613                             (con->parsed_response & HTTP_CONTENT_LENGTH) == 0) {
6614                                 /* without content_length, no keep-alive */
6615 -                               
6616 +
6617                                 con->keep_alive = 0;
6618                         }
6619                 } else {
6620                         /* a subrequest disable keep-alive although the client wanted it */
6621                         if (con->keep_alive && !con->response.keep_alive) {
6622                                 con->keep_alive = 0;
6623 -                               
6624 +
6625                                 /* FIXME: we have to drop the Connection: Header from the subrequest */
6626                         }
6627                 }
6628         }
6629 -       
6630 +
6631         if (con->request.http_method == HTTP_METHOD_HEAD) {
6632                 chunkqueue_reset(con->write_queue);
6633         }
6634  
6635         http_response_write_header(srv, con);
6636 -               
6637 +
6638         return 0;
6639  }
6640  
6641  static int connection_handle_write(server *srv, connection *con) {
6642         switch(network_write_chunkqueue(srv, con, con->write_queue)) {
6643 -       case 0:
6644 +       case NETWORK_STATUS_SUCCESS:
6645                 if (con->file_finished) {
6646                         connection_set_state(srv, con, CON_STATE_RESPONSE_END);
6647                         joblist_append(srv, con);
6648                 }
6649                 break;
6650 -       case -1: /* error on our side */
6651 +       case NETWORK_STATUS_FATAL_ERROR: /* error on our side */
6652                 log_error_write(srv, __FILE__, __LINE__, "sd",
6653 -                               "connection closed: write failed on fd", con->fd);
6654 +                               "connection closed: write failed on fd", con->sock->fd);
6655                 connection_set_state(srv, con, CON_STATE_ERROR);
6656                 joblist_append(srv, con);
6657                 break;
6658 -       case -2: /* remote close */
6659 +       case NETWORK_STATUS_CONNECTION_CLOSE: /* remote close */
6660                 connection_set_state(srv, con, CON_STATE_ERROR);
6661                 joblist_append(srv, con);
6662                 break;
6663 -       case 1:
6664 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
6665                 con->is_writable = 0;
6666 -               
6667 +
6668                 /* not finished yet -> WRITE */
6669                 break;
6670 +       case NETWORK_STATUS_INTERRUPTED:
6671 +               con->is_writable = 1;
6672 +               break;
6673 +       case NETWORK_STATUS_UNSET:
6674 +               break;
6675         }
6676 -       
6677 +
6678         return 0;
6679  }
6680  
6681 -
6682 -
6683  connection *connection_init(server *srv) {
6684         connection *con;
6685 -       
6686 +
6687         UNUSED(srv);
6688  
6689         con = calloc(1, sizeof(*con));
6690 -               
6691 -       con->fd = 0;
6692 +
6693 +       con->sock = iosocket_init();
6694         con->ndx = -1;
6695 -       con->fde_ndx = -1;
6696         con->bytes_written = 0;
6697         con->bytes_read = 0;
6698         con->bytes_header = 0;
6699 @@ -573,32 +447,32 @@
6700  
6701  #define CLEAN(x) \
6702         con->x = buffer_init();
6703 -       
6704 +
6705         CLEAN(request.uri);
6706         CLEAN(request.request_line);
6707         CLEAN(request.request);
6708         CLEAN(request.pathinfo);
6709 -       
6710 +
6711         CLEAN(request.orig_uri);
6712 -       
6713 +
6714         CLEAN(uri.scheme);
6715         CLEAN(uri.authority);
6716         CLEAN(uri.path);
6717         CLEAN(uri.path_raw);
6718         CLEAN(uri.query);
6719 -       
6720 +
6721         CLEAN(physical.doc_root);
6722         CLEAN(physical.path);
6723         CLEAN(physical.basedir);
6724         CLEAN(physical.rel_path);
6725         CLEAN(physical.etag);
6726         CLEAN(parse_request);
6727 -       
6728 +
6729         CLEAN(authed_user);
6730         CLEAN(server_name);
6731         CLEAN(error_handler);
6732         CLEAN(dst_addr_buf);
6733 -       
6734 +
6735  #undef CLEAN
6736         con->write_queue = chunkqueue_init();
6737         con->read_queue = chunkqueue_init();
6738 @@ -608,26 +482,27 @@
6739         con->request.headers      = array_init();
6740         con->response.headers     = array_init();
6741         con->environment     = array_init();
6742 -       
6743 +
6744         /* init plugin specific connection structures */
6745 -       
6746 +
6747         con->plugin_ctx = calloc(1, (srv->plugins.used + 1) * sizeof(void *));
6748 -       
6749 +
6750         con->cond_cache = calloc(srv->config_context->used, sizeof(cond_cache_t));
6751         config_setup_connection(srv, con);
6752 -       
6753 +
6754         return con;
6755  }
6756  
6757  void connections_free(server *srv) {
6758         connections *conns = srv->conns;
6759 -       size_t i;       
6760 -       
6761 +       size_t i;
6762 +
6763         for (i = 0; i < conns->size; i++) {
6764                 connection *con = conns->ptr[i];
6765 -               
6766 +
6767                 connection_reset(srv, con);
6768 -               
6769 +               iosocket_free(con->sock);
6770 +
6771                 chunkqueue_free(con->write_queue);
6772                 chunkqueue_free(con->read_queue);
6773                 chunkqueue_free(con->request_content_queue);
6774 @@ -637,27 +512,27 @@
6775  
6776  #define CLEAN(x) \
6777         buffer_free(con->x);
6778 -               
6779 +
6780                 CLEAN(request.uri);
6781                 CLEAN(request.request_line);
6782                 CLEAN(request.request);
6783                 CLEAN(request.pathinfo);
6784 -               
6785 +
6786                 CLEAN(request.orig_uri);
6787 -               
6788 +
6789                 CLEAN(uri.scheme);
6790                 CLEAN(uri.authority);
6791                 CLEAN(uri.path);
6792                 CLEAN(uri.path_raw);
6793                 CLEAN(uri.query);
6794 -               
6795 +
6796                 CLEAN(physical.doc_root);
6797                 CLEAN(physical.path);
6798                 CLEAN(physical.basedir);
6799                 CLEAN(physical.etag);
6800                 CLEAN(physical.rel_path);
6801                 CLEAN(parse_request);
6802 -               
6803 +
6804                 CLEAN(authed_user);
6805                 CLEAN(server_name);
6806                 CLEAN(error_handler);
6807 @@ -665,97 +540,97 @@
6808  #undef CLEAN
6809                 free(con->plugin_ctx);
6810                 free(con->cond_cache);
6811 -               
6812 +
6813                 free(con);
6814         }
6815 -       
6816 +
6817         free(conns->ptr);
6818  }
6819  
6820  
6821  int connection_reset(server *srv, connection *con) {
6822         size_t i;
6823 -       
6824 +
6825         plugins_call_connection_reset(srv, con);
6826 -       
6827 +
6828         con->is_readable = 1;
6829         con->is_writable = 1;
6830         con->http_status = 0;
6831         con->file_finished = 0;
6832         con->file_started = 0;
6833         con->got_response = 0;
6834 -       
6835 +
6836         con->parsed_response = 0;
6837 -       
6838 +
6839         con->bytes_written = 0;
6840         con->bytes_written_cur_second = 0;
6841         con->bytes_read = 0;
6842         con->bytes_header = 0;
6843         con->loops_per_request = 0;
6844 -       
6845 +
6846         con->request.http_method = HTTP_METHOD_UNSET;
6847         con->request.http_version = HTTP_VERSION_UNSET;
6848 -       
6849 +
6850         con->request.http_if_modified_since = NULL;
6851         con->request.http_if_none_match = NULL;
6852 -       
6853 +
6854         con->response.keep_alive = 0;
6855         con->response.content_length = -1;
6856         con->response.transfer_encoding = 0;
6857 -       
6858 +
6859         con->mode = DIRECT;
6860 -       
6861 +
6862  #define CLEAN(x) \
6863         if (con->x) buffer_reset(con->x);
6864 -       
6865 +
6866         CLEAN(request.uri);
6867         CLEAN(request.request_line);
6868         CLEAN(request.pathinfo);
6869         CLEAN(request.request);
6870 -       
6871 +
6872         CLEAN(request.orig_uri);
6873 -       
6874 +
6875         CLEAN(uri.scheme);
6876         CLEAN(uri.authority);
6877         CLEAN(uri.path);
6878         CLEAN(uri.path_raw);
6879         CLEAN(uri.query);
6880 -       
6881 +
6882         CLEAN(physical.doc_root);
6883         CLEAN(physical.path);
6884         CLEAN(physical.basedir);
6885         CLEAN(physical.rel_path);
6886         CLEAN(physical.etag);
6887 -       
6888 +
6889         CLEAN(parse_request);
6890 -       
6891 +
6892         CLEAN(authed_user);
6893         CLEAN(server_name);
6894         CLEAN(error_handler);
6895 -#undef CLEAN   
6896 -       
6897 +#undef CLEAN
6898 +
6899  #define CLEAN(x) \
6900 -       if (con->x) con->x->used = 0;   
6901 -       
6902 +       if (con->x) con->x->used = 0;
6903 +
6904  #undef CLEAN
6905 -       
6906 +
6907  #define CLEAN(x) \
6908                 con->request.x = NULL;
6909 -       
6910 +
6911         CLEAN(http_host);
6912         CLEAN(http_range);
6913         CLEAN(http_content_type);
6914  #undef CLEAN
6915         con->request.content_length = 0;
6916 -       
6917 +
6918         array_reset(con->request.headers);
6919         array_reset(con->response.headers);
6920         array_reset(con->environment);
6921 -       
6922 +
6923         chunkqueue_reset(con->write_queue);
6924         chunkqueue_reset(con->request_content_queue);
6925  
6926 -       /* the plugins should cleanup themself */       
6927 +       /* the plugins should cleanup themself */
6928         for (i = 0; i < srv->plugins.used; i++) {
6929                 plugin *p = ((plugin **)(srv->plugins.ptr))[i];
6930                 plugin_data *pd = p->data;
6931 @@ -768,7 +643,7 @@
6932  
6933                 con->plugin_ctx[pd->id] = NULL;
6934         }
6935 -       
6936 +
6937  #if COND_RESULT_UNSET
6938         for (i = srv->config_context->used - 1; i >= 0; i --) {
6939                 con->cond_cache[i].result = COND_RESULT_UNSET;
6940 @@ -777,56 +652,56 @@
6941  #else
6942         memset(con->cond_cache, 0, sizeof(cond_cache_t) * srv->config_context->used);
6943  #endif
6944 -       
6945 +
6946         con->header_len = 0;
6947         con->in_error_handler = 0;
6948 -       
6949 +
6950         config_setup_connection(srv, con);
6951 -       
6952 +
6953         return 0;
6954  }
6955  
6956  /**
6957 - * 
6958 - * search for \r\n\r\n 
6959 - * 
6960 + *
6961 + * search for \r\n\r\n
6962 + *
6963   * this is a special 32bit version which is using a sliding window for
6964 - * the comparisions 
6965 - * 
6966 + * the comparisions
6967 + *
6968   * how it works:
6969 - * 
6970 + *
6971   * b:      'abcdefg'
6972   * rnrn:   'cdef'
6973 - * 
6974 + *
6975   * cmpbuf: abcd != cdef
6976   * cmpbuf: bcde != cdef
6977   * cmpbuf: cdef == cdef -> return &c
6978 - * 
6979 - * cmpbuf and rnrn are treated as 32bit uint and bit-ops are used to 
6980 + *
6981 + * cmpbuf and rnrn are treated as 32bit uint and bit-ops are used to
6982   * maintain cmpbuf and rnrn
6983 - * 
6984 + *
6985   */
6986  
6987  char *buffer_search_rnrn(buffer *b) {
6988         uint32_t cmpbuf, rnrn;
6989         char *cp;
6990         size_t i;
6991 -       
6992 +
6993         if (b->used < 4) return NULL;
6994 -       
6995 +
6996         rnrn = ('\r' << 24) | ('\n' << 16) |
6997                 ('\r' << 8) | ('\n' << 0);
6998 -       
6999 +
7000         cmpbuf = (b->ptr[0] << 24) | (b->ptr[1] << 16) |
7001                 (b->ptr[2] << 8) | (b->ptr[3] << 0);
7002 -               
7003 +
7004         cp = b->ptr + 4;
7005         for (i = 0; i < b->used - 4; i++) {
7006                 if (cmpbuf == rnrn) return cp - 4;
7007 -                       
7008 +
7009                 cmpbuf = (cmpbuf << 8 | *(cp++)) & 0xffffffff;
7010         }
7011 -       
7012 +
7013         return NULL;
7014  }
7015  /**
7016 @@ -840,22 +715,25 @@
7017         chunk *c;
7018         chunkqueue *cq = con->read_queue;
7019         chunkqueue *dst_cq = con->request_content_queue;
7020 -       
7021 +
7022         if (con->is_readable) {
7023                 con->read_idle_ts = srv->cur_ts;
7024 -       
7025 +
7026                 switch(connection_handle_read(srv, con)) {
7027 -               case -1:
7028 +               case NETWORK_STATUS_FATAL_ERROR:
7029                         return -1;
7030 -               case -2:
7031 +               case NETWORK_STATUS_CONNECTION_CLOSE:
7032                         /* remote side closed the connection
7033                          * if we still have content, handle it, if not leave here */
7034  
7035                         if (cq->first == cq->last &&
7036 -                           cq->first->mem->used == 0) {
7037 +                           (NULL == cq->first ||
7038 +                           cq->first->mem->used == 0)) {
7039  
7040                                 /* conn-closed, leave here */
7041                                 connection_set_state(srv, con, CON_STATE_ERROR);
7042 +
7043 +                               return 0;
7044                         }
7045                 default:
7046                         break;
7047 @@ -891,14 +769,14 @@
7048                         /* the last node was empty */
7049                         if (c->next == NULL) {
7050                                 cq->last = c;
7051 -                       } 
7052 +                       }
7053  
7054                         c = c->next;
7055                 } else {
7056                         c = c->next;
7057                 }
7058         }
7059 -       
7060 +
7061         /* nothing to handle */
7062         if (cq->first == NULL) return 0;
7063  
7064 @@ -906,25 +784,26 @@
7065         case CON_STATE_READ:
7066                 /* prepare con->request.request */
7067                 c = cq->first;
7068 -               
7069 +
7070                 /* check if we need the full package */
7071                 if (con->request.request->used == 0) {
7072                         buffer b;
7073 -                       
7074 +
7075                         b.ptr = c->mem->ptr + c->offset;
7076                         b.used = c->mem->used - c->offset;
7077 -                       
7078 +
7079                         if (NULL != (h_term = buffer_search_rnrn(&b))) {
7080                                 /* \r\n\r\n found
7081                                  * - copy everything incl. the terminator to request.request
7082                                  */
7083 -                               
7084 -                               buffer_copy_string_len(con->request.request, 
7085 -                                                      b.ptr, 
7086 +
7087 +                               buffer_copy_string_len(con->request.request,
7088 +                                                      b.ptr,
7089                                                        h_term - b.ptr + 4);
7090 -                               
7091 +
7092                                 /* the buffer has been read up to the terminator */
7093                                 c->offset += h_term - b.ptr + 4;
7094 +
7095                         } else {
7096                                 /* not found, copy everything */
7097                                 buffer_copy_string_len(con->request.request, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
7098 @@ -932,14 +811,14 @@
7099                         }
7100                 } else {
7101                         /* have to take care of overlapping header terminators */
7102 -                       
7103 +
7104                         size_t l = con->request.request->used - 2;
7105                         char *s  = con->request.request->ptr;
7106                         buffer b;
7107 -                       
7108 +
7109                         b.ptr = c->mem->ptr + c->offset;
7110                         b.used = c->mem->used - c->offset;
7111 -                       
7112 +
7113                         if (con->request.request->used - 1 > 3 &&
7114                             c->mem->used > 1 &&
7115                             s[l-2] == '\r' &&
7116 @@ -948,7 +827,7 @@
7117                             c->mem->ptr[0] == '\n') {
7118                                 buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 1);
7119                                 c->offset += 1;
7120 -                               
7121 +
7122                                 h_term = con->request.request->ptr;
7123                         } else if (con->request.request->used - 1 > 2 &&
7124                                    c->mem->used > 2 &&
7125 @@ -958,7 +837,7 @@
7126                                    c->mem->ptr[1] == '\n') {
7127                                 buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 2);
7128                                 c->offset += 2;
7129 -                               
7130 +
7131                                 h_term = con->request.request->ptr;
7132                         } else if (con->request.request->used - 1 > 1 &&
7133                                    c->mem->used > 3 &&
7134 @@ -968,17 +847,17 @@
7135                                    c->mem->ptr[2] == '\n') {
7136                                 buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 3);
7137                                 c->offset += 3;
7138 -                               
7139 +
7140                                 h_term = con->request.request->ptr;
7141                         } else if (NULL != (h_term = buffer_search_string_len(&b, "\r\n\r\n", 4))) {
7142                                 /* \r\n\r\n found
7143                                  * - copy everything incl. the terminator to request.request
7144                                  */
7145 -                               
7146 -                               buffer_append_string_len(con->request.request, 
7147 -                                                      c->mem->ptr + c->offset, 
7148 +
7149 +                               buffer_append_string_len(con->request.request,
7150 +                                                      c->mem->ptr + c->offset,
7151                                                        c->offset + h_term - b.ptr + 4);
7152 -                               
7153 +
7154                                 /* the buffer has been read up to the terminator */
7155                                 c->offset += h_term - b.ptr + 4;
7156                         } else {
7157 @@ -999,16 +878,16 @@
7158                         connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7159                 }
7160                 break;
7161 -       case CON_STATE_READ_POST: 
7162 +       case CON_STATE_READ_POST:
7163                 for (c = cq->first; c && (dst_cq->bytes_in != (off_t)con->request.content_length); c = c->next) {
7164                         off_t weWant, weHave, toRead;
7165 -                       
7166 +
7167                         weWant = con->request.content_length - dst_cq->bytes_in;
7168 -                       
7169 +
7170                         assert(c->mem->used);
7171 -                       
7172 +
7173                         weHave = c->mem->used - c->offset - 1;
7174 -                               
7175 +
7176                         toRead = weHave > weWant ? weWant : weHave;
7177  
7178                         /* the new way, copy everything into a chunkqueue whcih might use tempfiles */
7179 @@ -1017,13 +896,13 @@
7180                                 /* copy everything to max 1Mb sized tempfiles */
7181  
7182                                 /*
7183 -                                * if the last chunk is 
7184 +                                * if the last chunk is
7185                                  * - smaller than 1Mb (size < 1Mb)
7186                                  * - not read yet (offset == 0)
7187                                  * -> append to it
7188                                  * otherwise
7189 -                                * -> create a new chunk 
7190 -                                * 
7191 +                                * -> create a new chunk
7192 +                                *
7193                                  * */
7194  
7195                                 if (dst_cq->last &&
7196 @@ -1056,14 +935,14 @@
7197                                 /* we have a chunk, let's write to it */
7198  
7199                                 if (dst_c->file.fd == -1) {
7200 -                                       /* we don't have file to write to, 
7201 +                                       /* we don't have file to write to,
7202                                          * EACCES might be one reason.
7203                                          *
7204                                          * Instead of sending 500 we send 413 and say the request is too large
7205                                          *  */
7206  
7207                                         log_error_write(srv, __FILE__, __LINE__, "sbs",
7208 -                                                       "denying upload as opening to temp-file for upload failed:", 
7209 +                                                       "denying upload as opening to temp-file for upload failed:",
7210                                                         dst_c->file.name, strerror(errno));
7211  
7212                                         con->http_status = 413; /* Request-Entity too large */
7213 @@ -1074,15 +953,15 @@
7214                                 }
7215  
7216                                 if (toRead != write(dst_c->file.fd, c->mem->ptr + c->offset, toRead)) {
7217 -                                       /* write failed for some reason ... disk full ? */ 
7218 +                                       /* write failed for some reason ... disk full ? */
7219                                         log_error_write(srv, __FILE__, __LINE__, "sbs",
7220 -                                                       "denying upload as writing to file failed:", 
7221 +                                                       "denying upload as writing to file failed:",
7222                                                         dst_c->file.name, strerror(errno));
7223 -                                       
7224 +
7225                                         con->http_status = 413; /* Request-Entity too large */
7226                                         con->keep_alive = 0;
7227                                         connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7228 -                               
7229 +
7230                                         close(dst_c->file.fd);
7231                                         dst_c->file.fd = -1;
7232  
7233 @@ -1090,7 +969,7 @@
7234                                 }
7235  
7236                                 dst_c->file.length += toRead;
7237 -                                       
7238 +
7239                                 if (dst_cq->bytes_in + toRead == (off_t)con->request.content_length) {
7240                                         /* we read everything, close the chunk */
7241                                         close(dst_c->file.fd);
7242 @@ -1102,7 +981,7 @@
7243                                 b = chunkqueue_get_append_buffer(dst_cq);
7244                                 buffer_copy_string_len(b, c->mem->ptr + c->offset, toRead);
7245                         }
7246 -                       
7247 +
7248                         c->offset += toRead;
7249                         dst_cq->bytes_in += toRead;
7250                 }
7251 @@ -1111,7 +990,7 @@
7252                 if (dst_cq->bytes_in == (off_t)con->request.content_length) {
7253                         connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7254                 }
7255 -                       
7256 +
7257                 break;
7258         }
7259  
7260 @@ -1123,100 +1002,104 @@
7261  handler_t connection_handle_fdevent(void *s, void *context, int revents) {
7262         server     *srv = (server *)s;
7263         connection *con = context;
7264 -       
7265 +
7266         joblist_append(srv, con);
7267 -       
7268 +
7269         if (revents & FDEVENT_IN) {
7270                 con->is_readable = 1;
7271 -#if 0
7272 -               log_error_write(srv, __FILE__, __LINE__, "sd", "read-wait - done", con->fd);
7273 -#endif
7274         }
7275         if (revents & FDEVENT_OUT) {
7276                 con->is_writable = 1;
7277                 /* we don't need the event twice */
7278         }
7279 -       
7280 -       
7281 +
7282 +
7283         if (revents & ~(FDEVENT_IN | FDEVENT_OUT)) {
7284                 /* looks like an error */
7285 -                                               
7286 +
7287                 /* FIXME: revents = 0x19 still means that we should read from the queue */
7288                 if (revents & FDEVENT_HUP) {
7289                         if (con->state == CON_STATE_CLOSE) {
7290                                 con->close_timeout_ts = 0;
7291                         } else {
7292                                 /* sigio reports the wrong event here
7293 -                                * 
7294 -                                * there was no HUP at all 
7295 +                                *
7296 +                                * there was no HUP at all
7297                                  */
7298  #ifdef USE_LINUX_SIGIO
7299                                 if (srv->ev->in_sigio == 1) {
7300                                         log_error_write(srv, __FILE__, __LINE__, "sd",
7301 -                                               "connection closed: poll() -> HUP", con->fd);
7302 +                                               "connection closed: poll() -> HUP", con->sock->fd);
7303                                 } else {
7304                                         connection_set_state(srv, con, CON_STATE_ERROR);
7305                                 }
7306  #else
7307                                 connection_set_state(srv, con, CON_STATE_ERROR);
7308  #endif
7309 -                               
7310 +
7311                         }
7312                 } else if (revents & FDEVENT_ERR) {
7313  #ifndef USE_LINUX_SIGIO
7314                         log_error_write(srv, __FILE__, __LINE__, "sd",
7315 -                                       "connection closed: poll() -> ERR", con->fd);
7316 -#endif 
7317 +                                       "connection closed: poll() -> ERR", con->sock->fd);
7318 +#endif
7319                         connection_set_state(srv, con, CON_STATE_ERROR);
7320                 } else {
7321                         log_error_write(srv, __FILE__, __LINE__, "sd",
7322                                         "connection closed: poll() -> ???", revents);
7323 -               } 
7324 +               }
7325         }
7326 -       
7327 +
7328         if (con->state == CON_STATE_READ ||
7329             con->state == CON_STATE_READ_POST) {
7330                 connection_handle_read_state(srv, con);
7331 +               /**
7332 +                * if SSL_read() is not readin in the full packet we won't get
7333 +                * a fdevent as the low-level has already fetched everything.
7334 +                *
7335 +                * we have to call the state-engine to read the rest of the packet
7336 +                */
7337 +               if (con->is_readable) joblist_append(srv, con);
7338         }
7339 -       
7340 +
7341         if (con->state == CON_STATE_WRITE &&
7342             !chunkqueue_is_empty(con->write_queue) &&
7343             con->is_writable) {
7344 -               
7345 +
7346                 if (-1 == connection_handle_write(srv, con)) {
7347                         connection_set_state(srv, con, CON_STATE_ERROR);
7348 -                       
7349 +
7350                         log_error_write(srv, __FILE__, __LINE__, "ds",
7351 -                                       con->fd,
7352 +                                       con->sock->fd,
7353                                         "handle write failed.");
7354                 } else if (con->state == CON_STATE_WRITE) {
7355                         con->write_request_ts = srv->cur_ts;
7356                 }
7357         }
7358 -       
7359 +
7360         if (con->state == CON_STATE_CLOSE) {
7361                 /* flush the read buffers */
7362                 int b;
7363 -               
7364 -               if (ioctl(con->fd, FIONREAD, &b)) {
7365 +
7366 +               if (ioctl(con->sock->fd, FIONREAD, &b)) {
7367                         log_error_write(srv, __FILE__, __LINE__, "ss",
7368                                         "ioctl() failed", strerror(errno));
7369                 }
7370 -               
7371 +
7372                 if (b > 0) {
7373                         char buf[1024];
7374                         log_error_write(srv, __FILE__, __LINE__, "sdd",
7375 -                                       "CLOSE-read()", con->fd, b);
7376 -                       
7377 +                                       "CLOSE-read()", con->sock->fd, b);
7378 +
7379                         /* */
7380 -                       read(con->fd, buf, sizeof(buf));
7381 +                       read(con->sock->fd, buf, sizeof(buf));
7382                 } else {
7383                         /* nothing to read */
7384 -                       
7385 +
7386                         con->close_timeout_ts = 0;
7387                 }
7388         }
7389 -       
7390 +
7391         return HANDLER_FINISHED;
7392  }
7393  
7394 @@ -1229,63 +1112,68 @@
7395         sock_addr cnt_addr;
7396         socklen_t cnt_len;
7397         /* accept it and register the fd */
7398 -       
7399 +
7400         cnt_len = sizeof(cnt_addr);
7401  
7402 -       if (-1 == (cnt = accept(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {
7403 +       if (-1 == (cnt = accept(srv_socket->sock->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {
7404 +#ifdef _WIN32
7405 +               errno = WSAGetLastError();
7406 +#endif
7407                 if ((errno != EAGAIN) &&
7408 +                   (errno != EWOULDBLOCK) &&
7409                     (errno != EINTR)) {
7410 -                       log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), errno);
7411 +                       log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), srv_socket->sock->fd);
7412                 }
7413                 return NULL;
7414         } else {
7415                 connection *con;
7416 -               
7417 +
7418                 srv->cur_fds++;
7419 -               
7420 +
7421                 /* ok, we have the connection, register it */
7422  #if 0
7423                 log_error_write(srv, __FILE__, __LINE__, "sd",
7424                                 "appected()", cnt);
7425  #endif
7426                 srv->con_opened++;
7427 -               
7428 +
7429                 con = connections_get_new_connection(srv);
7430 -               
7431 -               con->fd = cnt;
7432 -               con->fde_ndx = -1;
7433 -#if 0          
7434 +               con->sock->fd = cnt;
7435 +               con->sock->fde_ndx = -1;
7436 +#if 0
7437                 gettimeofday(&(con->start_tv), NULL);
7438 -#endif         
7439 -               fdevent_register(srv->ev, con->fd, connection_handle_fdevent, con);
7440 -               
7441 +#endif
7442 +               fdevent_register(srv->ev, con->sock, connection_handle_fdevent, con);
7443 +
7444                 connection_set_state(srv, con, CON_STATE_REQUEST_START);
7445 -               
7446 +
7447                 con->connection_start = srv->cur_ts;
7448                 con->dst_addr = cnt_addr;
7449                 buffer_copy_string(con->dst_addr_buf, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
7450                 con->srv_socket = srv_socket;
7451 -               
7452 -               if (-1 == (fdevent_fcntl_set(srv->ev, con->fd))) {
7453 +
7454 +               if (-1 == (fdevent_fcntl_set(srv->ev, con->sock))) {
7455                         log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
7456 +                       connection_close(srv, con);
7457                         return NULL;
7458                 }
7459  #ifdef USE_OPENSSL
7460                 /* connect FD to SSL */
7461                 if (srv_socket->is_ssl) {
7462 -                       if (NULL == (con->ssl = SSL_new(srv_socket->ssl_ctx))) {
7463 -                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
7464 +                       if (NULL == (con->sock->ssl = SSL_new(srv_socket->ssl_ctx))) {
7465 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7466                                                 ERR_error_string(ERR_get_error(), NULL));
7467 -                               
7468 +                               connection_close(srv, con);
7469                                 return NULL;
7470                         }
7471 -                       
7472 -                       SSL_set_accept_state(con->ssl);
7473 +
7474 +                       SSL_set_accept_state(con->sock->ssl);
7475                         con->conf.is_ssl=1;
7476 -                       
7477 -                       if (1 != (SSL_set_fd(con->ssl, cnt))) {
7478 -                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
7479 +
7480 +                       if (1 != (SSL_set_fd(con->sock->ssl, cnt))) {
7481 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7482                                                 ERR_error_string(ERR_get_error(), NULL));
7483 +                               connection_close(srv, con);
7484                                 return NULL;
7485                         }
7486                 }
7487 @@ -1300,102 +1188,102 @@
7488  #ifdef USE_OPENSSL
7489         server_socket *srv_sock = con->srv_socket;
7490  #endif
7491 -       
7492 +
7493         if (srv->srvconf.log_state_handling) {
7494 -               log_error_write(srv, __FILE__, __LINE__, "sds", 
7495 -                               "state at start", 
7496 -                               con->fd,
7497 +               log_error_write(srv, __FILE__, __LINE__, "sds",
7498 +                               "state at start",
7499 +                               con->sock->fd,
7500                                 connection_get_state(con->state));
7501         }
7502  
7503         while (done == 0) {
7504                 size_t ostate = con->state;
7505                 int b;
7506 -               
7507 +
7508                 switch (con->state) {
7509                 case CON_STATE_REQUEST_START: /* transient */
7510                         if (srv->srvconf.log_state_handling) {
7511 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7512 -                                               "state for fd", con->fd, connection_get_state(con->state));
7513 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7514 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7515                         }
7516 -                       
7517 +
7518                         con->request_start = srv->cur_ts;
7519                         con->read_idle_ts = srv->cur_ts;
7520 -                       
7521 +
7522                         con->request_count++;
7523                         con->loops_per_request = 0;
7524 -                       
7525 +
7526                         connection_set_state(srv, con, CON_STATE_READ);
7527 -                       
7528 +
7529                         break;
7530                 case CON_STATE_REQUEST_END: /* transient */
7531                         if (srv->srvconf.log_state_handling) {
7532 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7533 -                                               "state for fd", con->fd, connection_get_state(con->state));
7534 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7535 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7536                         }
7537 -                       
7538 +
7539                         if (http_request_parse(srv, con)) {
7540                                 /* we have to read some data from the POST request */
7541 -                               
7542 +
7543                                 connection_set_state(srv, con, CON_STATE_READ_POST);
7544  
7545                                 break;
7546                         }
7547 -                       
7548 +
7549                         connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7550 -                       
7551 +
7552                         break;
7553                 case CON_STATE_HANDLE_REQUEST:
7554 -                       /* 
7555 +                       /*
7556                          * the request is parsed
7557 -                        * 
7558 +                        *
7559                          * decided what to do with the request
7560 -                        * - 
7561 -                        * 
7562 -                        * 
7563 +                        * -
7564 +                        *
7565 +                        *
7566                          */
7567 -                       
7568 +
7569                         if (srv->srvconf.log_state_handling) {
7570 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7571 -                                               "state for fd", con->fd, connection_get_state(con->state));
7572 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7573 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7574                         }
7575 -                       
7576 +
7577                         switch (r = http_response_prepare(srv, con)) {
7578                         case HANDLER_FINISHED:
7579                                 if (con->http_status == 404 ||
7580                                     con->http_status == 403) {
7581                                         /* 404 error-handler */
7582 -                                       
7583 -                                       if (con->in_error_handler == 0 && 
7584 +
7585 +                                       if (con->in_error_handler == 0 &&
7586                                             (!buffer_is_empty(con->conf.error_handler) ||
7587                                              !buffer_is_empty(con->error_handler))) {
7588                                                 /* call error-handler */
7589 -                                               
7590 +
7591                                                 con->error_handler_saved_status = con->http_status;
7592                                                 con->http_status = 0;
7593 -                                               
7594 +
7595                                                 if (buffer_is_empty(con->error_handler)) {
7596                                                         buffer_copy_string_buffer(con->request.uri, con->conf.error_handler);
7597                                                 } else {
7598                                                         buffer_copy_string_buffer(con->request.uri, con->error_handler);
7599                                                 }
7600                                                 buffer_reset(con->physical.path);
7601 -                                               
7602 +
7603                                                 con->in_error_handler = 1;
7604 -                                               
7605 +
7606                                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7607 -                                               
7608 +
7609                                                 done = -1;
7610                                                 break;
7611                                         } else if (con->in_error_handler) {
7612                                                 /* error-handler is a 404 */
7613 -                                               
7614 +
7615                                                 /* continue as normal, status is the same */
7616 -                                               log_error_write(srv, __FILE__, __LINE__, "sb", 
7617 +                                               log_error_write(srv, __FILE__, __LINE__, "sb",
7618                                                                 "Warning: Either the error-handler returned status 404 or the error-handler itself was not found:", con->request.uri);
7619 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
7620 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
7621                                                                 "returning the original status", con->error_handler_saved_status);
7622 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
7623 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
7624                                                                 "If this is a rails app: check your production.log");
7625                                                 con->http_status = con->error_handler_saved_status;
7626                                         }
7627 @@ -1403,73 +1291,73 @@
7628                                         /* error-handler is back and has generated content */
7629                                         /* if Status: was set, take it otherwise use 200 */
7630                                 }
7631 -                               
7632 +
7633                                 if (con->http_status == 0) con->http_status = 200;
7634 -                               
7635 +
7636                                 /* we have something to send, go on */
7637                                 connection_set_state(srv, con, CON_STATE_RESPONSE_START);
7638                                 break;
7639                         case HANDLER_WAIT_FOR_FD:
7640                                 srv->want_fds++;
7641 -                               
7642 +
7643                                 fdwaitqueue_append(srv, con);
7644 -                               
7645 +
7646                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7647 -                               
7648 +
7649                                 break;
7650                         case HANDLER_COMEBACK:
7651                                 done = -1;
7652                         case HANDLER_WAIT_FOR_EVENT:
7653                                 /* come back here */
7654                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7655 -                               
7656 +
7657                                 break;
7658                         case HANDLER_ERROR:
7659                                 /* something went wrong */
7660                                 connection_set_state(srv, con, CON_STATE_ERROR);
7661                                 break;
7662                         default:
7663 -                               log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->fd, r);
7664 +                               log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->sock->fd, r);
7665                                 break;
7666                         }
7667 -                       
7668 +
7669                         break;
7670                 case CON_STATE_RESPONSE_START:
7671 -                       /* 
7672 +                       /*
7673                          * the decision is done
7674                          * - create the HTTP-Response-Header
7675 -                        * 
7676 +                        *
7677                          */
7678 -                       
7679 +
7680                         if (srv->srvconf.log_state_handling) {
7681 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7682 -                                               "state for fd", con->fd, connection_get_state(con->state));
7683 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7684 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7685                         }
7686 -                       
7687 +
7688                         if (-1 == connection_handle_write_prepare(srv, con)) {
7689                                 connection_set_state(srv, con, CON_STATE_ERROR);
7690 -                               
7691 +
7692                                 break;
7693                         }
7694 -                       
7695 +
7696                         connection_set_state(srv, con, CON_STATE_WRITE);
7697                         break;
7698                 case CON_STATE_RESPONSE_END: /* transient */
7699                         /* log the request */
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                         plugins_call_handle_request_done(srv, con);
7711 -                       
7712 +
7713                         srv->con_written++;
7714 -                       
7715 +
7716                         if (con->keep_alive) {
7717                                 connection_set_state(srv, con, CON_STATE_REQUEST_START);
7718 -                               
7719 -#if 0                                  
7720 +
7721 +#if 0
7722                                 con->request_start = srv->cur_ts;
7723                                 con->read_idle_ts = srv->cur_ts;
7724  #endif
7725 @@ -1482,103 +1370,103 @@
7726                                         log_error_write(srv, __FILE__, __LINE__, "sd", "unhandling return value", r);
7727                                         break;
7728                                 }
7729 -                               
7730 +
7731  #ifdef USE_OPENSSL
7732                                 if (srv_sock->is_ssl) {
7733 -                                       switch (SSL_shutdown(con->ssl)) {
7734 +                                       switch (SSL_shutdown(con->sock->ssl)) {
7735                                         case 1:
7736                                                 /* done */
7737                                                 break;
7738                                         case 0:
7739 -                                               /* wait for fd-event 
7740 -                                                * 
7741 +                                               /* wait for fd-event
7742 +                                                *
7743                                                  * FIXME: wait for fdevent and call SSL_shutdown again
7744 -                                                * 
7745 +                                                *
7746                                                  */
7747 -                                               
7748 +
7749                                                 break;
7750                                         default:
7751 -                                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
7752 +                                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7753                                                                 ERR_error_string(ERR_get_error(), NULL));
7754                                         }
7755                                 }
7756  #endif
7757                                 connection_close(srv, con);
7758 -                               
7759 +
7760                                 srv->con_closed++;
7761                         }
7762 -                       
7763 +
7764                         connection_reset(srv, con);
7765 -                       
7766 +
7767                         break;
7768                 case CON_STATE_CONNECT:
7769                         if (srv->srvconf.log_state_handling) {
7770 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7771 -                                               "state for fd", con->fd, connection_get_state(con->state));
7772 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7773 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7774                         }
7775 -                       
7776 +
7777                         chunkqueue_reset(con->read_queue);
7778 -                       
7779 +
7780                         con->request_count = 0;
7781 -                       
7782 +
7783                         break;
7784                 case CON_STATE_CLOSE:
7785                         if (srv->srvconf.log_state_handling) {
7786 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7787 -                                               "state for fd", con->fd, connection_get_state(con->state));
7788 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7789 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7790                         }
7791 -                       
7792 +
7793                         if (con->keep_alive) {
7794 -                               if (ioctl(con->fd, FIONREAD, &b)) {
7795 +                               if (ioctl(con->sock->fd, FIONREAD, &b)) {
7796                                         log_error_write(srv, __FILE__, __LINE__, "ss",
7797                                                         "ioctl() failed", strerror(errno));
7798                                 }
7799                                 if (b > 0) {
7800                                         char buf[1024];
7801                                         log_error_write(srv, __FILE__, __LINE__, "sdd",
7802 -                                                       "CLOSE-read()", con->fd, b);
7803 -                                       
7804 +                                                       "CLOSE-read()", con->sock->fd, b);
7805 +
7806                                         /* */
7807 -                                       read(con->fd, buf, sizeof(buf));
7808 +                                       read(con->sock->fd, buf, sizeof(buf));
7809                                 } else {
7810                                         /* nothing to read */
7811 -                                       
7812 +
7813                                         con->close_timeout_ts = 0;
7814                                 }
7815                         } else {
7816                                 con->close_timeout_ts = 0;
7817                         }
7818 -                       
7819 +
7820                         if (srv->cur_ts - con->close_timeout_ts > 1) {
7821                                 connection_close(srv, con);
7822 -                               
7823 +
7824                                 if (srv->srvconf.log_state_handling) {
7825 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
7826 -                                                       "connection closed for fd", con->fd);
7827 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
7828 +                                                       "connection closed for fd", con->sock->fd);
7829                                 }
7830                         }
7831 -                       
7832 +
7833                         break;
7834                 case CON_STATE_READ_POST:
7835                 case CON_STATE_READ:
7836                         if (srv->srvconf.log_state_handling) {
7837 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7838 -                                               "state for fd", con->fd, connection_get_state(con->state));
7839 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7840 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7841                         }
7842 -                       
7843 +
7844                         connection_handle_read_state(srv, con);
7845                         break;
7846                 case CON_STATE_WRITE:
7847                         if (srv->srvconf.log_state_handling) {
7848 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7849 -                                               "state for fd", con->fd, connection_get_state(con->state));
7850 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7851 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7852                         }
7853 -                       
7854 +
7855                         /* only try to write if we have something in the queue */
7856                         if (!chunkqueue_is_empty(con->write_queue)) {
7857  #if 0
7858                                 log_error_write(srv, __FILE__, __LINE__, "dsd",
7859 -                                               con->fd,
7860 +                                               con->sock->fd,
7861                                                 "packets to write:",
7862                                                 con->write_queue->used);
7863  #endif
7864 @@ -1586,17 +1474,17 @@
7865                         if (!chunkqueue_is_empty(con->write_queue) && con->is_writable) {
7866                                 if (-1 == connection_handle_write(srv, con)) {
7867                                         log_error_write(srv, __FILE__, __LINE__, "ds",
7868 -                                                       con->fd,
7869 +                                                       con->sock->fd,
7870                                                         "handle write failed.");
7871                                         connection_set_state(srv, con, CON_STATE_ERROR);
7872                                 } else if (con->state == CON_STATE_WRITE) {
7873                                         con->write_request_ts = srv->cur_ts;
7874                                 }
7875                         }
7876 -                       
7877 +
7878                         break;
7879                 case CON_STATE_ERROR: /* transient */
7880 -                       
7881 +
7882                         /* even if the connection was drop we still have to write it to the access log */
7883                         if (con->http_status) {
7884                                 plugins_call_handle_request_done(srv, con);
7885 @@ -1604,28 +1492,28 @@
7886  #ifdef USE_OPENSSL
7887                         if (srv_sock->is_ssl) {
7888                                 int ret;
7889 -                               switch ((ret = SSL_shutdown(con->ssl))) {
7890 +                               switch ((ret = SSL_shutdown(con->sock->ssl))) {
7891                                 case 1:
7892                                         /* ok */
7893                                         break;
7894                                 case 0:
7895 -                                       SSL_shutdown(con->ssl);
7896 +                                       SSL_shutdown(con->sock->ssl);
7897                                         break;
7898                                 default:
7899 -                                       log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:", 
7900 -                                                       SSL_get_error(con->ssl, ret), 
7901 +                                       log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
7902 +                                                       SSL_get_error(con->sock->ssl, ret),
7903                                                         ERR_error_string(ERR_get_error(), NULL));
7904                                         return -1;
7905                                 }
7906                         }
7907  #endif
7908 -                       
7909 +
7910                         switch(con->mode) {
7911                         case DIRECT:
7912  #if 0
7913 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
7914 -                                               "emergency exit: direct", 
7915 -                                               con->fd);
7916 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
7917 +                                               "emergency exit: direct",
7918 +                                               con->sock->fd);
7919  #endif
7920                                 break;
7921                         default:
7922 @@ -1639,35 +1527,35 @@
7923                                 }
7924                                 break;
7925                         }
7926 -                       
7927 +
7928                         connection_reset(srv, con);
7929 -                       
7930 +
7931                         /* close the connection */
7932                         if ((con->keep_alive == 1) &&
7933 -                           (0 == shutdown(con->fd, SHUT_WR))) {
7934 +                           (0 == shutdown(con->sock->fd, SHUT_WR))) {
7935                                 con->close_timeout_ts = srv->cur_ts;
7936                                 connection_set_state(srv, con, CON_STATE_CLOSE);
7937 -                               
7938 +
7939                                 if (srv->srvconf.log_state_handling) {
7940 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
7941 -                                                       "shutdown for fd", con->fd);
7942 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
7943 +                                                       "shutdown for fd", con->sock->fd);
7944                                 }
7945                         } else {
7946                                 connection_close(srv, con);
7947                         }
7948 -                       
7949 +
7950                         con->keep_alive = 0;
7951 -                       
7952 +
7953                         srv->con_closed++;
7954 -                       
7955 +
7956                         break;
7957                 default:
7958 -                       log_error_write(srv, __FILE__, __LINE__, "sdd", 
7959 -                                       "unknown state:", con->fd, con->state);
7960 -                       
7961 +                       log_error_write(srv, __FILE__, __LINE__, "sdd",
7962 +                                       "unknown state:", con->sock->fd, con->state);
7963 +
7964                         break;
7965                 }
7966 -               
7967 +
7968                 if (done == -1) {
7969                         done = 0;
7970                 } else if (ostate == con->state) {
7971 @@ -1676,33 +1564,33 @@
7972         }
7973  
7974         if (srv->srvconf.log_state_handling) {
7975 -               log_error_write(srv, __FILE__, __LINE__, "sds", 
7976 -                               "state at exit:", 
7977 -                               con->fd,
7978 +               log_error_write(srv, __FILE__, __LINE__, "sds",
7979 +                               "state at exit:",
7980 +                               con->sock->fd,
7981                                 connection_get_state(con->state));
7982         }
7983 -       
7984 +
7985         switch(con->state) {
7986         case CON_STATE_READ_POST:
7987         case CON_STATE_READ:
7988         case CON_STATE_CLOSE:
7989 -               fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_IN);
7990 +               fdevent_event_add(srv->ev, con->sock, FDEVENT_IN);
7991                 break;
7992         case CON_STATE_WRITE:
7993 -               /* request write-fdevent only if we really need it 
7994 +               /* request write-fdevent only if we really need it
7995                  * - if we have data to write
7996 -                * - if the socket is not writable yet 
7997 +                * - if the socket is not writable yet
7998                  */
7999 -               if (!chunkqueue_is_empty(con->write_queue) && 
8000 +               if (!chunkqueue_is_empty(con->write_queue) &&
8001                     (con->is_writable == 0) &&
8002                     (con->traffic_limit_reached == 0)) {
8003 -                       fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_OUT);
8004 +                       fdevent_event_add(srv->ev, con->sock, FDEVENT_OUT);
8005                 } else {
8006 -                       fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
8007 +                       fdevent_event_del(srv->ev, con->sock);
8008                 }
8009                 break;
8010         default:
8011 -               fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
8012 +               fdevent_event_del(srv->ev, con->sock);
8013                 break;
8014         }
8015  
8016 --- ../lighttpd-1.4.11/src/crc32.h      2005-09-30 20:18:59.000000000 +0300
8017 +++ lighttpd-1.4.12/src/crc32.h 2006-07-16 00:26:04.000000000 +0300
8018 @@ -6,6 +6,7 @@
8019  #endif
8020  
8021  #include <sys/types.h>
8022 +#include <stdlib.h>
8023  
8024  #if defined HAVE_STDINT_H
8025  #include <stdint.h>
8026 @@ -13,6 +14,10 @@
8027  #include <inttypes.h>
8028  #endif
8029  
8030 +#ifdef _WIN32
8031 +#define uint32_t unsigned __int32
8032 +#endif
8033 +
8034  uint32_t generate_crc32c(char *string, size_t length);
8035  
8036  #endif
8037 --- ../lighttpd-1.4.11/src/data_array.c 2005-08-23 17:36:12.000000000 +0300
8038 +++ lighttpd-1.4.12/src/data_array.c    2006-07-16 00:26:04.000000000 +0300
8039 @@ -17,16 +17,16 @@
8040  
8041  static void data_array_free(data_unset *d) {
8042         data_array *ds = (data_array *)d;
8043 -       
8044 +
8045         buffer_free(ds->key);
8046         array_free(ds->value);
8047 -       
8048 +
8049         free(d);
8050  }
8051  
8052  static void data_array_reset(data_unset *d) {
8053         data_array *ds = (data_array *)d;
8054 -       
8055 +
8056         /* reused array elements */
8057         buffer_reset(ds->key);
8058         array_reset(ds->value);
8059 @@ -36,7 +36,7 @@
8060         UNUSED(dst);
8061  
8062         src->free(src);
8063 -       
8064 +
8065         return 0;
8066  }
8067  
8068 @@ -48,18 +48,18 @@
8069  
8070  data_array *data_array_init(void) {
8071         data_array *ds;
8072 -       
8073 +
8074         ds = calloc(1, sizeof(*ds));
8075 -       
8076 +
8077         ds->key = buffer_init();
8078         ds->value = array_init();
8079 -       
8080 +
8081         ds->copy = data_array_copy;
8082         ds->free = data_array_free;
8083         ds->reset = data_array_reset;
8084         ds->insert_dup = data_array_insert_dup;
8085         ds->print = data_array_print;
8086         ds->type = TYPE_ARRAY;
8087 -       
8088 +
8089         return ds;
8090  }
8091 --- ../lighttpd-1.4.11/src/data_config.c        2005-08-17 12:53:19.000000000 +0300
8092 +++ lighttpd-1.4.12/src/data_config.c   2006-07-16 00:26:03.000000000 +0300
8093 @@ -17,26 +17,26 @@
8094  
8095  static void data_config_free(data_unset *d) {
8096         data_config *ds = (data_config *)d;
8097 -       
8098 +
8099         buffer_free(ds->key);
8100         buffer_free(ds->op);
8101         buffer_free(ds->comp_key);
8102 -       
8103 +
8104         array_free(ds->value);
8105         array_free(ds->childs);
8106 -       
8107 +
8108         if (ds->string) buffer_free(ds->string);
8109  #ifdef HAVE_PCRE_H
8110         if (ds->regex) pcre_free(ds->regex);
8111         if (ds->regex_study) pcre_free(ds->regex_study);
8112  #endif
8113 -       
8114 +
8115         free(d);
8116  }
8117  
8118  static void data_config_reset(data_unset *d) {
8119         data_config *ds = (data_config *)d;
8120 -       
8121 +
8122         /* reused array elements */
8123         buffer_reset(ds->key);
8124         buffer_reset(ds->comp_key);
8125 @@ -45,9 +45,9 @@
8126  
8127  static int data_config_insert_dup(data_unset *dst, data_unset *src) {
8128         UNUSED(dst);
8129 -       
8130 +
8131         src->free(src);
8132 -       
8133 +
8134         return 0;
8135  }
8136  
8137 @@ -56,7 +56,7 @@
8138         array *a = (array *)ds->value;
8139         size_t i;
8140         size_t maxlen;
8141 -       
8142 +
8143         if (0 == ds->context_ndx) {
8144                 fprintf(stderr, "config {\n");
8145         }
8146 @@ -117,22 +117,22 @@
8147  
8148  data_config *data_config_init(void) {
8149         data_config *ds;
8150 -       
8151 +
8152         ds = calloc(1, sizeof(*ds));
8153 -       
8154 +
8155         ds->key = buffer_init();
8156         ds->op = buffer_init();
8157         ds->comp_key = buffer_init();
8158         ds->value = array_init();
8159         ds->childs = array_init();
8160         ds->childs->is_weakref = 1;
8161 -       
8162 +
8163         ds->copy = data_config_copy;
8164         ds->free = data_config_free;
8165         ds->reset = data_config_reset;
8166         ds->insert_dup = data_config_insert_dup;
8167         ds->print = data_config_print;
8168         ds->type = TYPE_CONFIG;
8169 -       
8170 +
8171         return ds;
8172  }
8173 --- ../lighttpd-1.4.11/src/data_count.c 2005-08-23 17:36:12.000000000 +0300
8174 +++ lighttpd-1.4.12/src/data_count.c    2006-07-16 00:26:03.000000000 +0300
8175 @@ -16,53 +16,53 @@
8176  
8177  static void data_count_free(data_unset *d) {
8178         data_count *ds = (data_count *)d;
8179 -       
8180 +
8181         buffer_free(ds->key);
8182 -       
8183 +
8184         free(d);
8185  }
8186  
8187  static void data_count_reset(data_unset *d) {
8188         data_count *ds = (data_count *)d;
8189 -       
8190 +
8191         buffer_reset(ds->key);
8192 -       
8193 +
8194         ds->count = 0;
8195  }
8196  
8197  static int data_count_insert_dup(data_unset *dst, data_unset *src) {
8198         data_count *ds_dst = (data_count *)dst;
8199         data_count *ds_src = (data_count *)src;
8200 -       
8201 +
8202         ds_dst->count += ds_src->count;
8203 -       
8204 +
8205         src->free(src);
8206 -       
8207 +
8208         return 0;
8209  }
8210  
8211  static void data_count_print(const data_unset *d, int depth) {
8212         data_count *ds = (data_count *)d;
8213         UNUSED(depth);
8214 -       
8215 +
8216         fprintf(stderr, "count(%d)", ds->count);
8217  }
8218  
8219  
8220  data_count *data_count_init(void) {
8221         data_count *ds;
8222 -       
8223 +
8224         ds = calloc(1, sizeof(*ds));
8225 -       
8226 +
8227         ds->key = buffer_init();
8228         ds->count = 1;
8229 -       
8230 +
8231         ds->copy = data_count_copy;
8232         ds->free = data_count_free;
8233         ds->reset = data_count_reset;
8234         ds->insert_dup = data_count_insert_dup;
8235         ds->print = data_count_print;
8236         ds->type = TYPE_COUNT;
8237 -       
8238 +
8239         return ds;
8240  }
8241 --- ../lighttpd-1.4.11/src/data_fastcgi.c       2005-08-23 17:36:12.000000000 +0300
8242 +++ lighttpd-1.4.12/src/data_fastcgi.c  2006-07-16 00:26:04.000000000 +0300
8243 @@ -17,53 +17,53 @@
8244  
8245  static void data_fastcgi_free(data_unset *d) {
8246         data_fastcgi *ds = (data_fastcgi *)d;
8247 -       
8248 +
8249         buffer_free(ds->key);
8250         buffer_free(ds->host);
8251 -       
8252 +
8253         free(d);
8254  }
8255  
8256  static void data_fastcgi_reset(data_unset *d) {
8257         data_fastcgi *ds = (data_fastcgi *)d;
8258 -       
8259 +
8260         buffer_reset(ds->key);
8261         buffer_reset(ds->host);
8262 -       
8263 +
8264  }
8265  
8266  static int data_fastcgi_insert_dup(data_unset *dst, data_unset *src) {
8267         UNUSED(dst);
8268  
8269         src->free(src);
8270 -       
8271 +
8272         return 0;
8273  }
8274  
8275  static void data_fastcgi_print(const data_unset *d, int depth) {
8276         data_fastcgi *ds = (data_fastcgi *)d;
8277         UNUSED(depth);
8278 -       
8279 +
8280         fprintf(stderr, "fastcgi(%s)", ds->host->ptr);
8281  }
8282  
8283  
8284  data_fastcgi *data_fastcgi_init(void) {
8285         data_fastcgi *ds;
8286 -       
8287 +
8288         ds = calloc(1, sizeof(*ds));
8289 -       
8290 +
8291         ds->key = buffer_init();
8292         ds->host = buffer_init();
8293         ds->port = 0;
8294         ds->is_disabled = 0;
8295 -       
8296 +
8297         ds->copy = data_fastcgi_copy;
8298         ds->free = data_fastcgi_free;
8299         ds->reset = data_fastcgi_reset;
8300         ds->insert_dup = data_fastcgi_insert_dup;
8301         ds->print = data_fastcgi_print;
8302         ds->type = TYPE_FASTCGI;
8303 -       
8304 +
8305         return ds;
8306  }
8307 --- ../lighttpd-1.4.11/src/data_integer.c       2005-08-23 17:36:12.000000000 +0300
8308 +++ lighttpd-1.4.12/src/data_integer.c  2006-07-16 00:26:03.000000000 +0300
8309 @@ -16,15 +16,15 @@
8310  
8311  static void data_integer_free(data_unset *d) {
8312         data_integer *ds = (data_integer *)d;
8313 -       
8314 +
8315         buffer_free(ds->key);
8316 -       
8317 +
8318         free(d);
8319  }
8320  
8321  static void data_integer_reset(data_unset *d) {
8322         data_integer *ds = (data_integer *)d;
8323 -       
8324 +
8325         /* reused integer elements */
8326         buffer_reset(ds->key);
8327         ds->value = 0;
8328 @@ -32,9 +32,9 @@
8329  
8330  static int data_integer_insert_dup(data_unset *dst, data_unset *src) {
8331         UNUSED(dst);
8332 -       
8333 +
8334         src->free(src);
8335 -       
8336 +
8337         return 0;
8338  }
8339  
8340 @@ -48,18 +48,18 @@
8341  
8342  data_integer *data_integer_init(void) {
8343         data_integer *ds;
8344 -       
8345 +
8346         ds = calloc(1, sizeof(*ds));
8347 -       
8348 +
8349         ds->key = buffer_init();
8350         ds->value = 0;
8351 -       
8352 +
8353         ds->copy = data_integer_copy;
8354         ds->free = data_integer_free;
8355         ds->reset = data_integer_reset;
8356         ds->insert_dup = data_integer_insert_dup;
8357         ds->print = data_integer_print;
8358         ds->type = TYPE_INTEGER;
8359 -       
8360 +
8361         return ds;
8362  }
8363 --- ../lighttpd-1.4.11/src/data_string.c        2005-08-23 17:36:12.000000000 +0300
8364 +++ lighttpd-1.4.12/src/data_string.c   2006-07-16 00:26:04.000000000 +0300
8365 @@ -17,16 +17,16 @@
8366  
8367  static void data_string_free(data_unset *d) {
8368         data_string *ds = (data_string *)d;
8369 -       
8370 +
8371         buffer_free(ds->key);
8372         buffer_free(ds->value);
8373 -       
8374 +
8375         free(d);
8376  }
8377  
8378  static void data_string_reset(data_unset *d) {
8379         data_string *ds = (data_string *)d;
8380 -       
8381 +
8382         /* reused array elements */
8383         buffer_reset(ds->key);
8384         buffer_reset(ds->value);
8385 @@ -35,23 +35,23 @@
8386  static int data_string_insert_dup(data_unset *dst, data_unset *src) {
8387         data_string *ds_dst = (data_string *)dst;
8388         data_string *ds_src = (data_string *)src;
8389 -       
8390 +
8391         if (ds_dst->value->used) {
8392                 buffer_append_string(ds_dst->value, ", ");
8393                 buffer_append_string_buffer(ds_dst->value, ds_src->value);
8394         } else {
8395                 buffer_copy_string_buffer(ds_dst->value, ds_src->value);
8396         }
8397 -       
8398 +
8399         src->free(src);
8400 -       
8401 +
8402         return 0;
8403  }
8404  
8405  static int data_response_insert_dup(data_unset *dst, data_unset *src) {
8406         data_string *ds_dst = (data_string *)dst;
8407         data_string *ds_src = (data_string *)src;
8408 -       
8409 +
8410         if (ds_dst->value->used) {
8411                 buffer_append_string(ds_dst->value, "\r\n");
8412                 buffer_append_string_buffer(ds_dst->value, ds_dst->key);
8413 @@ -60,9 +60,9 @@
8414         } else {
8415                 buffer_copy_string_buffer(ds_dst->value, ds_src->value);
8416         }
8417 -       
8418 +
8419         src->free(src);
8420 -       
8421 +
8422         return 0;
8423  }
8424  
8425 @@ -77,28 +77,28 @@
8426  
8427  data_string *data_string_init(void) {
8428         data_string *ds;
8429 -       
8430 +
8431         ds = calloc(1, sizeof(*ds));
8432         assert(ds);
8433 -       
8434 +
8435         ds->key = buffer_init();
8436         ds->value = buffer_init();
8437 -       
8438 +
8439         ds->copy = data_string_copy;
8440         ds->free = data_string_free;
8441         ds->reset = data_string_reset;
8442         ds->insert_dup = data_string_insert_dup;
8443         ds->print = data_string_print;
8444         ds->type = TYPE_STRING;
8445 -       
8446 +
8447         return ds;
8448  }
8449  
8450  data_string *data_response_init(void) {
8451         data_string *ds;
8452 -       
8453 +
8454         ds = data_string_init();
8455         ds->insert_dup = data_response_insert_dup;
8456 -       
8457 +
8458         return ds;
8459  }
8460 --- ../lighttpd-1.4.11/src/etag.c       2005-08-11 01:26:40.000000000 +0300
8461 +++ lighttpd-1.4.12/src/etag.c  2006-07-18 13:03:40.000000000 +0300
8462 @@ -4,7 +4,7 @@
8463  #include "etag.h"
8464  
8465  int etag_is_equal(buffer *etag, const char *matches) {
8466 -       if (0 == strcmp(etag->ptr, matches)) return 1;
8467 +       if (buffer_is_equal_string(etag, matches, strlen(matches))) return 1;
8468         return 0;
8469  }
8470  
8471 @@ -14,19 +14,19 @@
8472         buffer_append_off_t(etag, st->st_size);
8473         buffer_append_string_len(etag, CONST_STR_LEN("-"));
8474         buffer_append_long(etag, st->st_mtime);
8475 -       
8476 +
8477         return 0;
8478  }
8479  
8480  int etag_mutate(buffer *mut, buffer *etag) {
8481         size_t h, i;
8482 -       
8483 +
8484         for (h=0, i=0; i < etag->used; ++i) h = (h<<5)^(h>>27)^(etag->ptr[i]);
8485 -       
8486 +
8487         buffer_reset(mut);
8488         buffer_copy_string_len(mut, CONST_STR_LEN("\""));
8489         buffer_append_long(mut, h);
8490         buffer_append_string_len(mut, CONST_STR_LEN("\""));
8491 -       
8492 +
8493         return 0;
8494  }
8495 --- ../lighttpd-1.4.11/src/etag.h       2005-08-11 01:26:40.000000000 +0300
8496 +++ lighttpd-1.4.12/src/etag.h  2006-07-16 00:26:03.000000000 +0300
8497 @@ -3,13 +3,12 @@
8498  
8499  #include <sys/types.h>
8500  #include <sys/stat.h>
8501 -#include <unistd.h>
8502  
8503  #include "buffer.h"
8504  
8505  int etag_is_equal(buffer *etag, const char *matches);
8506  int etag_create(buffer *etag, struct stat *st);
8507  int etag_mutate(buffer *mut, buffer *etag);
8508 -       
8509 +
8510  
8511  #endif
8512 --- ../lighttpd-1.4.11/src/fastcgi.h    2005-08-11 01:26:40.000000000 +0300
8513 +++ lighttpd-1.4.12/src/fastcgi.h       2006-07-16 00:26:03.000000000 +0300
8514 @@ -1,4 +1,4 @@
8515 -/* 
8516 +/*
8517   * fastcgi.h --
8518   *
8519   *     Defines for the FastCGI protocol.
8520 @@ -123,7 +123,7 @@
8521  
8522  
8523  typedef struct {
8524 -    unsigned char type;    
8525 +    unsigned char type;
8526      unsigned char reserved[7];
8527  } FCGI_UnknownTypeBody;
8528  
8529 --- ../lighttpd-1.4.11/src/fdevent.c    2005-11-15 10:51:05.000000000 +0200
8530 +++ lighttpd-1.4.12/src/fdevent.c       2006-07-18 13:03:40.000000000 +0300
8531 @@ -2,7 +2,6 @@
8532  
8533  #include "settings.h"
8534  
8535 -#include <unistd.h>
8536  #include <stdlib.h>
8537  #include <string.h>
8538  #include <errno.h>
8539 @@ -11,60 +10,116 @@
8540  
8541  #include "fdevent.h"
8542  #include "buffer.h"
8543 +#include "log.h"
8544 +
8545 +#include "sys-socket.h"
8546 +
8547 +fdevent_revent *fdevent_revent_init(void) {
8548 +       STRUCT_INIT(fdevent_revent, revent);
8549 +
8550 +       return revent;
8551 +}
8552 +
8553 +void fdevent_revent_free(fdevent_revent *revent) {
8554 +       if (!revent) return;
8555 +
8556 +       free(revent);
8557 +}
8558 +
8559 +fdevent_revents *fdevent_revents_init(void) {
8560 +       STRUCT_INIT(fdevent_revents, revents);
8561 +
8562 +       return revents;
8563 +}
8564 +
8565 +void fdevent_revents_reset(fdevent_revents *revents) {
8566 +       if (!revents) return;
8567 +
8568 +       revents->used = 0;
8569 +}
8570 +
8571 +void fdevent_revents_add(fdevent_revents *revents, int fd, int events) {
8572 +       fdevent_revent *revent;
8573 +
8574 +       if (revents->used == revents->size) {
8575 +               /* resize the events-array */
8576 +               revents->ptr = realloc(revents->ptr, (revents->size + 1) * sizeof(*(revents->ptr)));
8577 +               revents->ptr[revents->size++] = fdevent_revent_init();
8578 +       }
8579 +
8580 +       revent = revents->ptr[revents->used++];
8581 +       revent->fd = fd;
8582 +       revent->revents = events;
8583 +}
8584 +
8585 +void fdevent_revents_free(fdevent_revents *revents) {
8586 +       size_t i;
8587 +       
8588 +       if (!revents) return;
8589 +
8590 +       if (revents->size) {
8591 +               for (i = 0; i < revents->size; i++) {
8592 +                       fdevent_revent_free(revents->ptr[i]);
8593 +               }
8594 +
8595 +               free(revents->ptr);
8596 +       }
8597 +       free(revents);
8598 +}
8599  
8600  fdevents *fdevent_init(size_t maxfds, fdevent_handler_t type) {
8601         fdevents *ev;
8602 -       
8603 +
8604         ev = calloc(1, sizeof(*ev));
8605         ev->fdarray = calloc(maxfds, sizeof(*ev->fdarray));
8606         ev->maxfds = maxfds;
8607 -       
8608 +
8609         switch(type) {
8610         case FDEVENT_HANDLER_POLL:
8611                 if (0 != fdevent_poll_init(ev)) {
8612 -                       fprintf(stderr, "%s.%d: event-handler poll failed\n", 
8613 +                       fprintf(stderr, "%s.%d: event-handler poll failed\n",
8614                                 __FILE__, __LINE__);
8615 -                       
8616 +
8617                         return NULL;
8618                 }
8619                 break;
8620         case FDEVENT_HANDLER_SELECT:
8621                 if (0 != fdevent_select_init(ev)) {
8622 -                       fprintf(stderr, "%s.%d: event-handler select failed\n", 
8623 +                       fprintf(stderr, "%s.%d: event-handler select failed\n",
8624                                 __FILE__, __LINE__);
8625                         return NULL;
8626                 }
8627                 break;
8628         case FDEVENT_HANDLER_LINUX_RTSIG:
8629                 if (0 != fdevent_linux_rtsig_init(ev)) {
8630 -                       fprintf(stderr, "%s.%d: event-handler linux-rtsig failed, try to set server.event-handler = \"poll\" or \"select\"\n", 
8631 +                       fprintf(stderr, "%s.%d: event-handler linux-rtsig failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8632                                 __FILE__, __LINE__);
8633                         return NULL;
8634                 }
8635                 break;
8636         case FDEVENT_HANDLER_LINUX_SYSEPOLL:
8637                 if (0 != fdevent_linux_sysepoll_init(ev)) {
8638 -                       fprintf(stderr, "%s.%d: event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"\n", 
8639 +                       fprintf(stderr, "%s.%d: event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8640                                 __FILE__, __LINE__);
8641                         return NULL;
8642                 }
8643                 break;
8644         case FDEVENT_HANDLER_SOLARIS_DEVPOLL:
8645                 if (0 != fdevent_solaris_devpoll_init(ev)) {
8646 -                       fprintf(stderr, "%s.%d: event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"\n", 
8647 +                       fprintf(stderr, "%s.%d: event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8648                                 __FILE__, __LINE__);
8649                         return NULL;
8650                 }
8651                 break;
8652         case FDEVENT_HANDLER_FREEBSD_KQUEUE:
8653                 if (0 != fdevent_freebsd_kqueue_init(ev)) {
8654 -                       fprintf(stderr, "%s.%d: event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"\n", 
8655 +                       fprintf(stderr, "%s.%d: event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8656                                 __FILE__, __LINE__);
8657                         return NULL;
8658                 }
8659                 break;
8660         default:
8661 -               fprintf(stderr, "%s.%d: event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"\n", 
8662 +               fprintf(stderr, "%s.%d: event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"\n",
8663                         __FILE__, __LINE__);
8664                 return NULL;
8665         }
8666 @@ -75,28 +130,29 @@
8667  void fdevent_free(fdevents *ev) {
8668         size_t i;
8669         if (!ev) return;
8670 -       
8671 +
8672         if (ev->free) ev->free(ev);
8673 -       
8674 +
8675         for (i = 0; i < ev->maxfds; i++) {
8676                 if (ev->fdarray[i]) free(ev->fdarray[i]);
8677         }
8678 -       
8679 +
8680         free(ev->fdarray);
8681         free(ev);
8682  }
8683  
8684  int fdevent_reset(fdevents *ev) {
8685         if (ev->reset) return ev->reset(ev);
8686 -       
8687 +
8688         return 0;
8689  }
8690  
8691  fdnode *fdnode_init() {
8692         fdnode *fdn;
8693 -       
8694 +
8695         fdn = calloc(1, sizeof(*fdn));
8696         fdn->fd = -1;
8697 +
8698         return fdn;
8699  }
8700  
8701 @@ -104,48 +160,40 @@
8702         free(fdn);
8703  }
8704  
8705 -int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx) {
8706 +int fdevent_register(fdevents *ev, iosocket *sock, fdevent_handler handler, void *ctx) {
8707         fdnode *fdn;
8708 -       
8709 +
8710         fdn = fdnode_init();
8711         fdn->handler = handler;
8712 -       fdn->fd      = fd;
8713 +       fdn->fd      = sock->fd;
8714         fdn->ctx     = ctx;
8715 -       
8716 -       ev->fdarray[fd] = fdn;
8717 +
8718 +       ev->fdarray[sock->fd] = fdn;
8719  
8720         return 0;
8721  }
8722  
8723 -int fdevent_unregister(fdevents *ev, int fd) {
8724 +int fdevent_unregister(fdevents *ev, iosocket *sock) {
8725         fdnode *fdn;
8726          if (!ev) return 0;
8727 -       fdn = ev->fdarray[fd];
8728 -       
8729 +       fdn = ev->fdarray[sock->fd];
8730 +
8731         fdnode_free(fdn);
8732 -       
8733 -       ev->fdarray[fd] = NULL;
8734 -       
8735 +
8736 +       ev->fdarray[sock->fd] = NULL;
8737 +
8738         return 0;
8739  }
8740  
8741 -int fdevent_event_del(fdevents *ev, int *fde_ndx, int fd) {
8742 -       int fde = fde_ndx ? *fde_ndx : -1;
8743 -       
8744 -       if (ev->event_del) fde = ev->event_del(ev, fde, fd);
8745 -       
8746 -       if (fde_ndx) *fde_ndx = fde;
8747 -       
8748 +int fdevent_event_del(fdevents *ev, iosocket *sock) {
8749 +       if (ev->event_del) ev->event_del(ev, sock);
8750 +
8751         return 0;
8752  }
8753  
8754 -int fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int events) {
8755 -       int fde = fde_ndx ? *fde_ndx : -1;
8756 -       
8757 -       if (ev->event_add) fde = ev->event_add(ev, fde, fd, events);
8758 -       
8759 -       if (fde_ndx) *fde_ndx = fde;
8760 -       
8761 +int fdevent_event_add(fdevents *ev, iosocket *sock, int events) {
8762 +       if (ev->event_add) ev->event_add(ev, sock, events);
8763 +
8764         return 0;
8765  }
8766  
8767 @@ -154,49 +202,41 @@
8768         return ev->poll(ev, timeout_ms);
8769  }
8770  
8771 -int fdevent_event_get_revent(fdevents *ev, size_t ndx) {
8772 -       if (ev->event_get_revent == NULL) SEGFAULT();
8773 -       
8774 -       return ev->event_get_revent(ev, ndx);
8775 -}
8776 +int fdevent_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
8777 +       size_t i;
8778  
8779 -int fdevent_event_get_fd(fdevents *ev, size_t ndx) {
8780 -       if (ev->event_get_fd == NULL) SEGFAULT();
8781 -       
8782 -       return ev->event_get_fd(ev, ndx);
8783 -}
8784 +       if (ev->get_revents == NULL) SEGFAULT();
8785  
8786 -fdevent_handler fdevent_get_handler(fdevents *ev, int fd) {
8787 -       if (ev->fdarray[fd] == NULL) SEGFAULT();
8788 -       if (ev->fdarray[fd]->fd != fd) SEGFAULT();
8789 -       
8790 -       return ev->fdarray[fd]->handler;
8791 -}
8792 +       fdevent_revents_reset(revents);
8793  
8794 -void * fdevent_get_context(fdevents *ev, int fd) {
8795 -       if (ev->fdarray[fd] == NULL) SEGFAULT();
8796 -       if (ev->fdarray[fd]->fd != fd) SEGFAULT();
8797 -       
8798 -       return ev->fdarray[fd]->ctx;
8799 +       ev->get_revents(ev, event_count, revents);
8800 +
8801 +       /* patch the event handlers */
8802 +       for (i = 0; i < event_count; i++) {
8803 +               fdevent_revent *r = revents->ptr[i];
8804 +
8805 +               r->handler = ev->fdarray[r->fd]->handler;
8806 +               r->context = ev->fdarray[r->fd]->ctx;
8807 +       }
8808 +
8809 +       return 0;
8810  }
8811  
8812 -int fdevent_fcntl_set(fdevents *ev, int fd) {
8813 +int fdevent_fcntl_set(fdevents *ev, iosocket *sock) {
8814 +#ifdef _WIN32
8815 +       int i = 1;
8816 +#endif
8817  #ifdef FD_CLOEXEC
8818         /* close fd on exec (cgi) */
8819 -       fcntl(fd, F_SETFD, FD_CLOEXEC);
8820 +       fcntl(sock->fd, F_SETFD, FD_CLOEXEC);
8821  #endif
8822 -       if ((ev) && (ev->fcntl_set)) return ev->fcntl_set(ev, fd);
8823 -#ifdef O_NONBLOCK      
8824 -       return fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
8825 +       if ((ev) && (ev->fcntl_set)) return ev->fcntl_set(ev, sock->fd);
8826 +#ifdef O_NONBLOCK
8827 +       return fcntl(sock->fd, F_SETFL, O_NONBLOCK | O_RDWR);
8828 +#elif defined _WIN32
8829 +       return ioctlsocket(sock->fd, FIONBIO, &i);
8830  #else
8831         return 0;
8832  #endif
8833  }
8834  
8835 -
8836 -int fdevent_event_next_fdndx(fdevents *ev, int ndx) {
8837 -       if (ev->event_next_fdndx) return ev->event_next_fdndx(ev, ndx);
8838 -       
8839 -       return -1;
8840 -}
8841 -
8842 --- ../lighttpd-1.4.11/src/fdevent.h    2005-09-27 11:26:33.000000000 +0300
8843 +++ lighttpd-1.4.12/src/fdevent.h       2006-07-18 13:03:40.000000000 +0300
8844 @@ -7,6 +7,9 @@
8845  #include "settings.h"
8846  #include "bitset.h"
8847  
8848 +#include "iosocket.h"
8849 +#include "array-static.h"
8850 +
8851  /* select event-system */
8852  
8853  #if defined(HAVE_EPOLL_CTL) && defined(HAVE_SYS_EPOLL_H)
8854 @@ -17,13 +20,13 @@
8855  # include <sys/epoll.h>
8856  #endif
8857  
8858 -/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes 
8859 +/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes
8860   * under /usr/include/sys/ */
8861  #if defined HAVE_POLL && (defined(HAVE_SYS_POLL_H) || defined(HAVE_POLL_H))
8862  # define USE_POLL
8863  # ifdef HAVE_POLL_H
8864  #  include <poll.h>
8865 -# else 
8866 +# else
8867  #  include <sys/poll.h>
8868  # endif
8869  # if defined HAVE_SIGTIMEDWAIT && defined(__linux__)
8870 @@ -31,9 +34,11 @@
8871  #  include <signal.h>
8872  # endif
8873  #endif
8874 -
8875 +#ifdef _WIN32
8876 +# define HAVE_SELECT
8877 +#endif
8878  #if defined HAVE_SELECT
8879 -# ifdef __WIN32
8880 +# ifdef _WIN32
8881  #  include <winsock2.h>
8882  # endif
8883  # define USE_SELECT
8884 @@ -67,14 +72,14 @@
8885  #define FDEVENT_HUP    BV(4)
8886  #define FDEVENT_NVAL   BV(5)
8887  
8888 -typedef enum { FD_EVENT_TYPE_UNSET = -1, 
8889 -               FD_EVENT_TYPE_CONNECTION, 
8890 -               FD_EVENT_TYPE_FCGI_CONNECTION, 
8891 -               FD_EVENT_TYPE_DIRWATCH, 
8892 -               FD_EVENT_TYPE_CGI_CONNECTION 
8893 +typedef enum { FD_EVENT_TYPE_UNSET = -1,
8894 +               FD_EVENT_TYPE_CONNECTION,
8895 +               FD_EVENT_TYPE_FCGI_CONNECTION,
8896 +               FD_EVENT_TYPE_DIRWATCH,
8897 +               FD_EVENT_TYPE_CGI_CONNECTION
8898  } fd_event_t;
8899  
8900 -typedef enum { FDEVENT_HANDLER_UNSET, 
8901 +typedef enum { FDEVENT_HANDLER_UNSET,
8902                 FDEVENT_HANDLER_SELECT,
8903                 FDEVENT_HANDLER_POLL,
8904                 FDEVENT_HANDLER_LINUX_RTSIG,
8905 @@ -86,7 +91,7 @@
8906  
8907  /**
8908   * a mapping from fd to connection structure
8909 - * 
8910 + *
8911   */
8912  typedef struct {
8913         int fd;                  /**< the fd */
8914 @@ -96,43 +101,51 @@
8915         int revents;
8916  } fd_conn;
8917  
8918 +ARRAY_STATIC_DEF(fd_conn_buffer, fd_conn, );
8919 +
8920 +/**
8921 + * revents
8922 + */
8923  typedef struct {
8924 -       fd_conn *ptr;
8925 -       
8926 -       size_t size;
8927 -       size_t used;
8928 -} fd_conn_buffer;
8929 +       int fd;
8930 +       int revents;
8931 +
8932 +       fdevent_handler handler;
8933 +       void *context;
8934 +} fdevent_revent;
8935 +
8936 +ARRAY_STATIC_DEF(fdevent_revents, fdevent_revent, );
8937  
8938  /**
8939   * array of unused fd's
8940 - * 
8941 + *
8942   */
8943  
8944  typedef struct _fdnode {
8945 -       fdevent_handler handler;
8946 -       void *ctx;
8947 -       int fd;
8948 -       
8949 +       fdevent_handler handler; /* who handles the events for this fd */
8950 +       void *ctx;               /* opaque pointer which is passed as 3rd parameter to the handler */
8951 +       int fd;                  /* fd */
8952 +
8953         struct _fdnode *prev, *next;
8954  } fdnode;
8955  
8956  typedef struct {
8957         int *ptr;
8958 -       
8959 +
8960         size_t used;
8961         size_t size;
8962  } buffer_int;
8963  
8964  /**
8965   * fd-event handler for select(), poll() and rt-signals on Linux 2.4
8966 - * 
8967 + *
8968   */
8969  typedef struct fdevents {
8970         fdevent_handler_t type;
8971 -       
8972 -       fdnode **fdarray;
8973 +
8974 +       fdnode **fdarray; /* a list of fdnodes */
8975         size_t maxfds;
8976 -       
8977 +
8978  #ifdef USE_LINUX_SIGIO
8979         int in_sigio;
8980         int signum;
8981 @@ -146,21 +159,21 @@
8982  #endif
8983  #ifdef USE_POLL
8984         struct pollfd *pollfds;
8985 -       
8986 +
8987         size_t size;
8988         size_t used;
8989 -       
8990 +
8991         buffer_int unused;
8992  #endif
8993  #ifdef USE_SELECT
8994         fd_set select_read;
8995         fd_set select_write;
8996         fd_set select_error;
8997 -       
8998 +
8999         fd_set select_set_read;
9000         fd_set select_set_write;
9001         fd_set select_set_error;
9002 -       
9003 +
9004         int select_max_fd;
9005  #endif
9006  #ifdef USE_SOLARIS_DEVPOLL
9007 @@ -177,16 +190,13 @@
9008  #endif
9009         int (*reset)(struct fdevents *ev);
9010         void (*free)(struct fdevents *ev);
9011 -       
9012 -       int (*event_add)(struct fdevents *ev, int fde_ndx, int fd, int events);
9013 -       int (*event_del)(struct fdevents *ev, int fde_ndx, int fd);
9014 -       int (*event_get_revent)(struct fdevents *ev, size_t ndx);
9015 -       int (*event_get_fd)(struct fdevents *ev, size_t ndx);
9016 -       
9017 -       int (*event_next_fdndx)(struct fdevents *ev, int ndx);
9018 -       
9019 +
9020 +       int (*event_add)(struct fdevents *ev, iosocket *sock, int events);
9021 +       int (*event_del)(struct fdevents *ev, iosocket *sock);
9022 +       int (*get_revents)(struct fdevents *ev, size_t event_count, fdevent_revents *revents);
9023 +
9024         int (*poll)(struct fdevents *ev, int timeout_ms);
9025 -       
9026 +
9027         int (*fcntl_set)(struct fdevents *ev, int fd);
9028  } fdevents;
9029  
9030 @@ -194,22 +204,44 @@
9031  int fdevent_reset(fdevents *ev);
9032  void fdevent_free(fdevents *ev);
9033  
9034 -int fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int events);
9035 -int fdevent_event_del(fdevents *ev, int *fde_ndx, int fd);
9036 -int fdevent_event_get_revent(fdevents *ev, size_t ndx);
9037 -int fdevent_event_get_fd(fdevents *ev, size_t ndx);
9038 -fdevent_handler fdevent_get_handler(fdevents *ev, int fd);
9039 -void * fdevent_get_context(fdevents *ev, int fd);
9040 +/**
9041 + * call the plugin for the number of available events
9042 + */
9043 +int fdevent_poll(fdevents *ev, int timeout_ms);
9044 +/**
9045 + * get all available events
9046 + */
9047 +int fdevent_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents);
9048  
9049 -int fdevent_event_next_fdndx(fdevents *ev, int ndx);
9050 +/**
9051 + * add or remove a fd to the handled-pool
9052 + */
9053 +int fdevent_register(fdevents *ev, iosocket *sock, fdevent_handler handler, void *ctx);
9054 +int fdevent_unregister(fdevents *ev, iosocket *sock);
9055  
9056 -int fdevent_poll(fdevents *ev, int timeout_ms);
9057 +/**
9058 + * add a event to a registered fd
9059 + */
9060 +int fdevent_event_add(fdevents *ev, iosocket *sock, int events);
9061 +int fdevent_event_del(fdevents *ev, iosocket *sock);
9062 +
9063 +/**
9064 + * set non-blocking
9065 + */
9066 +int fdevent_fcntl_set(fdevents *ev, iosocket *sock);
9067 +
9068 +fdevent_revents *fdevent_revents_init(void);
9069 +void fdevent_revents_reset(fdevent_revents *revents);
9070 +void fdevent_revents_add(fdevent_revents *revents, int fd, int events);
9071 +void fdevent_revents_free(fdevent_revents *revents);
9072  
9073 -int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx);
9074 -int fdevent_unregister(fdevents *ev, int fd);
9075 +fdevent_revent *fdevent_revent_init(void);
9076 +void fdevent_revent_free(fdevent_revent *revent);
9077  
9078 -int fdevent_fcntl_set(fdevents *ev, int fd);
9079  
9080 +/**
9081 + * plugin init
9082 + */
9083  int fdevent_select_init(fdevents *ev);
9084  int fdevent_poll_init(fdevents *ev);
9085  int fdevent_linux_rtsig_init(fdevents *ev);
9086 --- ../lighttpd-1.4.11/src/fdevent_freebsd_kqueue.c     2005-09-01 10:46:24.000000000 +0300
9087 +++ lighttpd-1.4.12/src/fdevent_freebsd_kqueue.c        2006-07-16 00:26:03.000000000 +0300
9088 @@ -1,6 +1,5 @@
9089  #include <sys/types.h>
9090  
9091 -#include <unistd.h>
9092  #include <stdlib.h>
9093  #include <stdio.h>
9094  #include <string.h>
9095 @@ -48,7 +47,7 @@
9096  
9097                 return -1;
9098         }
9099 -       
9100 +
9101         return -1;
9102  }
9103  
9104 @@ -65,7 +64,7 @@
9105  
9106         ts.tv_sec  = 0;
9107         ts.tv_nsec = 0;
9108 -       
9109 +
9110         ret = kevent(ev->kq_fd,
9111                      &kev, 1,
9112                      NULL, 0,
9113 @@ -77,7 +76,7 @@
9114  
9115                 return -1;
9116         }
9117 -       
9118 +
9119         if (filter == EVFILT_READ) {
9120                 bitset_set_bit(ev->kq_bevents, fd);
9121         } else {
9122 @@ -124,7 +123,7 @@
9123         } else if (e == EVFILT_WRITE) {
9124                 events |= FDEVENT_OUT;
9125         }
9126 -       
9127 +
9128         e = ev->kq_results[ndx].flags;
9129  
9130         if (e & EV_EOF) {
9131 @@ -152,10 +151,10 @@
9132         if (-1 == (ev->kq_fd = kqueue())) {
9133                 fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9134                         __FILE__, __LINE__, strerror(errno));
9135 -               
9136 +
9137                 return -1;
9138         }
9139 -       
9140 +
9141         return 0;
9142  }
9143  
9144 @@ -186,7 +185,7 @@
9145         if (-1 == (ev->kq_fd = kqueue())) {
9146                 fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9147                         __FILE__, __LINE__, strerror(errno));
9148 -               
9149 +
9150                 return -1;
9151         }
9152  
9153 --- ../lighttpd-1.4.11/src/fdevent_linux_rtsig.c        2005-11-21 19:56:11.000000000 +0200
9154 +++ lighttpd-1.4.12/src/fdevent_linux_rtsig.c   2006-07-18 13:03:40.000000000 +0300
9155 @@ -1,6 +1,5 @@
9156  #include <sys/types.h>
9157  
9158 -#include <unistd.h>
9159  #include <stdlib.h>
9160  #include <stdio.h>
9161  #include <string.h>
9162 @@ -14,6 +13,8 @@
9163  #include "fdevent.h"
9164  #include "settings.h"
9165  #include "buffer.h"
9166 +#include "sys-process.h"
9167 +#include "log.h"
9168  
9169  #ifdef USE_LINUX_SIGIO
9170  static void fdevent_linux_rtsig_free(fdevents *ev) {
9171 @@ -24,21 +25,21 @@
9172  }
9173  
9174  
9175 -static int fdevent_linux_rtsig_event_del(fdevents *ev, int fde_ndx, int fd) {
9176 -       if (fde_ndx < 0) return -1;
9177 -       
9178 -       if ((size_t)fde_ndx >= ev->used) {
9179 -               fprintf(stderr, "%s.%d: del! out of range %d %zu\n", __FILE__, __LINE__, fde_ndx, ev->used);
9180 +static int fdevent_linux_rtsig_event_del(fdevents *ev, iosocket *sock) {
9181 +       if (sock->fde_ndx < 0) return -1;
9182 +
9183 +       if ((size_t)sock->fde_ndx >= ev->used) {
9184 +               TRACE("del! out of range %d %zu\n", sock->fde_ndx, ev->used);
9185                 SEGFAULT();
9186         }
9187 -       
9188 -       if (ev->pollfds[fde_ndx].fd == fd) {
9189 -               size_t k = fde_ndx;
9190 -               
9191 +
9192 +       if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9193 +               size_t k = sock->fde_ndx;
9194 +
9195                 ev->pollfds[k].fd = -1;
9196  
9197 -               bitset_clear_bit(ev->sigbset, fd);
9198 -               
9199 +               bitset_clear_bit(ev->sigbset, sock->fd);
9200 +
9201                 if (ev->unused.size == 0) {
9202                         ev->unused.size = 16;
9203                         ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size);
9204 @@ -46,53 +47,54 @@
9205                         ev->unused.size += 16;
9206                         ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
9207                 }
9208 -               
9209 +
9210                 ev->unused.ptr[ev->unused.used++] = k;
9211         } else {
9212 -               fprintf(stderr, "%s.%d: del! %d %d\n", __FILE__, __LINE__, ev->pollfds[fde_ndx].fd, fd);
9213 -               
9214 +               fprintf(stderr, "%s.%d: del! %d %d\n", __FILE__, __LINE__, ev->pollfds[sock->fde_ndx].fd, sock->fd);
9215 +
9216                 SEGFAULT();
9217         }
9218 -       
9219 -       return -1;
9220 +       sock->fde_ndx = -1;
9221 +
9222 +       return 0;
9223  }
9224  
9225  #if 0
9226  static int fdevent_linux_rtsig_event_compress(fdevents *ev) {
9227         size_t j;
9228 -       
9229 +
9230         if (ev->used == 0) return 0;
9231         if (ev->unused.used != 0) return 0;
9232 -       
9233 +
9234         for (j = ev->used - 1; j + 1 > 0; j--) {
9235                 if (ev->pollfds[j].fd == -1) ev->used--;
9236         }
9237 -       
9238 -       
9239 +
9240 +
9241         return 0;
9242  }
9243  #endif
9244  
9245 -static int fdevent_linux_rtsig_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9246 +static int fdevent_linux_rtsig_event_add(fdevents *ev, iosocket *sock, int events) {
9247         /* known index */
9248 -       if (fde_ndx != -1) {
9249 -               if (ev->pollfds[fde_ndx].fd == fd) {
9250 -                       ev->pollfds[fde_ndx].events = events;
9251 -                       
9252 -                       return fde_ndx;
9253 +       if (sock->fde_ndx != -1) {
9254 +               if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9255 +                       ev->pollfds[sock->fde_ndx].events = events;
9256 +
9257 +                       return sock->fde_ndx;
9258                 }
9259 -               fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, fde_ndx, ev->pollfds[fde_ndx].fd);
9260 +               fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, sock->fde_ndx, ev->pollfds[sock->fde_ndx].fd);
9261                 SEGFAULT();
9262         }
9263 -       
9264 +
9265         if (ev->unused.used > 0) {
9266                 int k = ev->unused.ptr[--ev->unused.used];
9267 -               
9268 -               ev->pollfds[k].fd = fd;
9269 +
9270 +               ev->pollfds[k].fd = sock->fd;
9271                 ev->pollfds[k].events = events;
9272  
9273 -               bitset_set_bit(ev->sigbset, fd);
9274 -               
9275 +               bitset_set_bit(ev->sigbset, sock->fd);
9276 +
9277                 return k;
9278         } else {
9279                 if (ev->size == 0) {
9280 @@ -102,12 +104,12 @@
9281                         ev->size += 16;
9282                         ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
9283                 }
9284 -               
9285 -               ev->pollfds[ev->used].fd = fd;
9286 +
9287 +               ev->pollfds[ev->used].fd = sock->fd;
9288                 ev->pollfds[ev->used].events = events;
9289  
9290 -               bitset_set_bit(ev->sigbset, fd);
9291 -       
9292 +               bitset_set_bit(ev->sigbset, sock->fd);
9293 +
9294                 return ev->used++;
9295         }
9296  }
9297 @@ -115,20 +117,20 @@
9298  static int fdevent_linux_rtsig_poll(fdevents *ev, int timeout_ms) {
9299         struct timespec ts;
9300         int r;
9301 -       
9302 +
9303  #if 0
9304         fdevent_linux_rtsig_event_compress(ev);
9305  #endif
9306 -       
9307 +
9308         ev->in_sigio = 1;
9309 -               
9310 +
9311         ts.tv_sec =  timeout_ms / 1000;
9312         ts.tv_nsec = (timeout_ms % 1000) * 1000000;
9313         r = sigtimedwait(&(ev->sigset), &(ev->siginfo), &(ts));
9314 -               
9315 -       if (r == -1) { 
9316 +
9317 +       if (r == -1) {
9318                 if (errno == EAGAIN) return 0;
9319 -               return r; 
9320 +               return r;
9321         } else if (r == SIGIO) {
9322                 struct sigaction act;
9323  
9324 @@ -140,7 +142,7 @@
9325                 /* re-enable the signal queue */
9326                 act.sa_handler = SIG_DFL;
9327                 sigaction(ev->signum, &act, NULL);
9328 -               
9329 +
9330                 ev->in_sigio = 0;
9331                 r = poll(ev->pollfds, ev->used, timeout_ms);
9332  
9333 @@ -156,97 +158,67 @@
9334         }
9335  }
9336  
9337 -static int fdevent_linux_rtsig_event_get_revent(fdevents *ev, size_t ndx) {
9338 +static int fdevent_linux_rtsig_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9339         if (ev->in_sigio == 1) {
9340 -#  if 0
9341 -               if (ev->siginfo.si_band == POLLERR) {
9342 -                       fprintf(stderr, "event: %d %02lx %02x %s\n", ev->siginfo.si_fd, ev->siginfo.si_band, errno, strerror(errno));
9343 -               }
9344 -#  endif               
9345 -               if (ndx != 0) {
9346 -                       fprintf(stderr, "+\n");
9347 -                       return 0;
9348 -               }
9349 -               
9350 -               return ev->siginfo.si_band & 0x3f;
9351 +               /* only one event */
9352 +
9353 +               fdevent_revents_add(revents, ev->siginfo.si_fd, ev->siginfo.si_band & 0x3f);
9354         } else {
9355 -               if (ndx >= ev->used) {
9356 -                       fprintf(stderr, "%s.%d: event: %zu %zu\n", __FILE__, __LINE__, ndx, ev->used);
9357 -                       return 0;
9358 +               size_t ndx;
9359 +
9360 +               for (ndx = 0; ndx < ev->used; ndx++) {
9361 +                       if (ev->pollfds[ndx].revents) {
9362 +                               fdevent_revents_add(revents, ev->pollfds[ndx].fd, ev->pollfds[ndx].revents);
9363 +                       }
9364                 }
9365 -               return ev->pollfds[ndx].revents;
9366         }
9367 -}
9368  
9369 -static int fdevent_linux_rtsig_event_get_fd(fdevents *ev, size_t ndx) {
9370 -       if (ev->in_sigio == 1) {
9371 -               return ev->siginfo.si_fd;
9372 -       } else {
9373 -               return ev->pollfds[ndx].fd;
9374 -       }
9375 +       return 0;
9376  }
9377  
9378  static int fdevent_linux_rtsig_fcntl_set(fdevents *ev, int fd) {
9379         static pid_t pid = 0;
9380 -       
9381 +
9382         if (pid == 0) pid = getpid();
9383 -       
9384 +
9385         if (-1 == fcntl(fd, F_SETSIG, ev->signum)) return -1;
9386 -       
9387 +
9388         if (-1 == fcntl(fd, F_SETOWN, (int) pid)) return -1;
9389 -       
9390 +
9391         return fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK | O_RDWR);
9392  }
9393  
9394  
9395 -static int fdevent_linux_rtsig_event_next_fdndx(fdevents *ev, int ndx) {
9396 -       if (ev->in_sigio == 1) {
9397 -               if (ndx < 0) return 0;
9398 -               return -1;
9399 -       } else {
9400 -               size_t i;
9401 -               
9402 -               i = (ndx < 0) ? 0 : ndx + 1;
9403 -               for (; i < ev->used; i++) {
9404 -                       if (ev->pollfds[i].revents) break;
9405 -               }
9406 -               
9407 -               return i;
9408 -       }
9409 -}
9410 -
9411  int fdevent_linux_rtsig_init(fdevents *ev) {
9412         ev->type = FDEVENT_HANDLER_LINUX_RTSIG;
9413  #define SET(x) \
9414         ev->x = fdevent_linux_rtsig_##x;
9415 -       
9416 +
9417         SET(free);
9418         SET(poll);
9419 -       
9420 +
9421         SET(event_del);
9422         SET(event_add);
9423 -       
9424 -       SET(event_next_fdndx);
9425 +
9426         SET(fcntl_set);
9427 -       SET(event_get_fd);
9428 -       SET(event_get_revent);
9429 -       
9430 +       SET(get_revents);
9431 +
9432         ev->signum = SIGRTMIN + 1;
9433 -       
9434 +
9435         sigemptyset(&(ev->sigset));
9436         sigaddset(&(ev->sigset), ev->signum);
9437         sigaddset(&(ev->sigset), SIGIO);
9438         if (-1 == sigprocmask(SIG_BLOCK, &(ev->sigset), NULL)) {
9439                 fprintf(stderr, "%s.%d: sigprocmask failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9440                         __FILE__, __LINE__, strerror(errno));
9441 -               
9442 +
9443                 return -1;
9444         }
9445 -       
9446 +
9447         ev->in_sigio = 1;
9448  
9449         ev->sigbset = bitset_init(ev->maxfds);
9450 -       
9451 +
9452         return 0;
9453  }
9454  #else
9455 --- ../lighttpd-1.4.11/src/fdevent_linux_sysepoll.c     2005-09-30 20:29:27.000000000 +0300
9456 +++ lighttpd-1.4.12/src/fdevent_linux_sysepoll.c        2006-07-18 13:03:40.000000000 +0300
9457 @@ -1,6 +1,5 @@
9458  #include <sys/types.h>
9459  
9460 -#include <unistd.h>
9461  #include <stdlib.h>
9462  #include <stdio.h>
9463  #include <string.h>
9464 @@ -11,6 +10,9 @@
9465  #include "fdevent.h"
9466  #include "settings.h"
9467  #include "buffer.h"
9468 +#include "log.h"
9469 +
9470 +#include "sys-files.h"
9471  
9472  #ifdef USE_LINUX_EPOLL
9473  static void fdevent_linux_sysepoll_free(fdevents *ev) {
9474 @@ -18,38 +20,40 @@
9475         free(ev->epoll_events);
9476  }
9477  
9478 -static int fdevent_linux_sysepoll_event_del(fdevents *ev, int fde_ndx, int fd) {
9479 +static int fdevent_linux_sysepoll_event_del(fdevents *ev, iosocket *sock) {
9480         struct epoll_event ep;
9481 -       
9482 -       if (fde_ndx < 0) return -1;
9483 -       
9484 +
9485 +       if (sock->fde_ndx < 0) return -1;
9486 +
9487         memset(&ep, 0, sizeof(ep));
9488 -       
9489 -       ep.data.fd = fd;
9490 +
9491 +       ep.data.fd = sock->fd;
9492         ep.data.ptr = NULL;
9493 -       
9494 -       if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fd, &ep)) {
9495 +
9496 +       if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, sock->fd, &ep)) {
9497                 fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n", __FILE__, __LINE__, strerror(errno));
9498 -               
9499 +
9500                 SEGFAULT();
9501 -               
9502 +
9503                 return 0;
9504         }
9505 -       
9506 -       
9507 -       return -1;
9508 +
9509 +       sock->fde_ndx = -1;
9510 +
9511 +       return 0;
9512  }
9513  
9514 -static int fdevent_linux_sysepoll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9515 +static int fdevent_linux_sysepoll_event_add(fdevents *ev, iosocket *sock, int events) {
9516         struct epoll_event ep;
9517         int add = 0;
9518 -       
9519 -       if (fde_ndx == -1) add = 1;
9520 -       
9521 +
9522 +       /* a new fd */
9523 +       if (sock->fde_ndx == -1) add = 1;
9524 +
9525         memset(&ep, 0, sizeof(ep));
9526 -       
9527 +
9528         ep.events = 0;
9529 -       
9530 +
9531         if (events & FDEVENT_IN)  ep.events |= EPOLLIN;
9532         if (events & FDEVENT_OUT) ep.events |= EPOLLOUT;
9533  
9534 @@ -60,73 +64,61 @@
9535          * sent.
9536          *
9537          */
9538 -       
9539 +
9540         ep.events |= EPOLLERR | EPOLLHUP /* | EPOLLET */;
9541 -       
9542 +
9543         ep.data.ptr = NULL;
9544 -       ep.data.fd = fd;
9545 -       
9546 -       if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, fd, &ep)) {
9547 +       ep.data.fd = sock->fd;
9548 +
9549 +       if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, sock->fd, &ep)) {
9550                 fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n", __FILE__, __LINE__, strerror(errno));
9551 -               
9552 +
9553                 SEGFAULT();
9554 -               
9555 +
9556                 return 0;
9557         }
9558 -       
9559 -       return fd;
9560 +
9561 +       sock->fde_ndx = sock->fd;
9562 +
9563 +       return 0;
9564  }
9565  
9566  static int fdevent_linux_sysepoll_poll(fdevents *ev, int timeout_ms) {
9567         return epoll_wait(ev->epoll_fd, ev->epoll_events, ev->maxfds, timeout_ms);
9568  }
9569  
9570 -static int fdevent_linux_sysepoll_event_get_revent(fdevents *ev, size_t ndx) {
9571 -       int events = 0, e;
9572 -       
9573 -       e = ev->epoll_events[ndx].events;
9574 -       if (e & EPOLLIN) events |= FDEVENT_IN;
9575 -       if (e & EPOLLOUT) events |= FDEVENT_OUT;
9576 -       if (e & EPOLLERR) events |= FDEVENT_ERR;
9577 -       if (e & EPOLLHUP) events |= FDEVENT_HUP;
9578 -       if (e & EPOLLPRI) events |= FDEVENT_PRI;
9579 -       
9580 -       return e;
9581 -}
9582 -
9583 -static int fdevent_linux_sysepoll_event_get_fd(fdevents *ev, size_t ndx) {
9584 -# if 0
9585 -       fprintf(stderr, "%s.%d: %d, %d\n", __FILE__, __LINE__, ndx, ev->epoll_events[ndx].data.fd);
9586 -# endif
9587 -       
9588 -       return ev->epoll_events[ndx].data.fd;
9589 -}
9590 -
9591 -static int fdevent_linux_sysepoll_event_next_fdndx(fdevents *ev, int ndx) {
9592 -       size_t i;
9593 -       
9594 -       UNUSED(ev);
9595 +static int fdevent_linux_sysepoll_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9596 +       size_t ndx;
9597 +
9598 +       for (ndx = 0; ndx < event_count; ndx++) {
9599 +               int events = 0, e;
9600 +
9601 +               e = ev->epoll_events[ndx].events;
9602 +               if (e & EPOLLIN) events |= FDEVENT_IN;
9603 +               if (e & EPOLLOUT) events |= FDEVENT_OUT;
9604 +               if (e & EPOLLERR) events |= FDEVENT_ERR;
9605 +               if (e & EPOLLHUP) events |= FDEVENT_HUP;
9606 +               if (e & EPOLLPRI) events |= FDEVENT_PRI;
9607  
9608 -       i = (ndx < 0) ? 0 : ndx + 1;
9609 -       
9610 -       return i;
9611 +               fdevent_revents_add(revents, ev->epoll_events[ndx].data.fd, e);
9612 +       }
9613 +
9614 +       return 0;
9615  }
9616  
9617  int fdevent_linux_sysepoll_init(fdevents *ev) {
9618         ev->type = FDEVENT_HANDLER_LINUX_SYSEPOLL;
9619  #define SET(x) \
9620         ev->x = fdevent_linux_sysepoll_##x;
9621 -       
9622 +
9623         SET(free);
9624         SET(poll);
9625 -       
9626 +
9627         SET(event_del);
9628         SET(event_add);
9629 -       
9630 -       SET(event_next_fdndx);
9631 -       SET(event_get_fd);
9632 -       SET(event_get_revent);
9633 -       
9634 +
9635 +       SET(get_revents);
9636 +
9637         if (-1 == (ev->epoll_fd = epoll_create(ev->maxfds))) {
9638                 fprintf(stderr, "%s.%d: epoll_create failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9639                         __FILE__, __LINE__, strerror(errno));
9640 @@ -154,7 +146,7 @@
9641  
9642         fprintf(stderr, "%s.%d: linux-sysepoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
9643                 __FILE__, __LINE__);
9644 -       
9645 +
9646         return -1;
9647  }
9648  #endif
9649 --- ../lighttpd-1.4.11/src/fdevent_poll.c       2005-11-18 13:59:16.000000000 +0200
9650 +++ lighttpd-1.4.12/src/fdevent_poll.c  2006-07-18 13:03:40.000000000 +0300
9651 @@ -1,6 +1,5 @@
9652  #include <sys/types.h>
9653  
9654 -#include <unistd.h>
9655  #include <stdlib.h>
9656  #include <stdio.h>
9657  #include <string.h>
9658 @@ -11,6 +10,7 @@
9659  #include "fdevent.h"
9660  #include "settings.h"
9661  #include "buffer.h"
9662 +#include "log.h"
9663  
9664  #ifdef USE_POLL
9665  static void fdevent_poll_free(fdevents *ev) {
9666 @@ -18,21 +18,21 @@
9667         if (ev->unused.ptr) free(ev->unused.ptr);
9668  }
9669  
9670 -static int fdevent_poll_event_del(fdevents *ev, int fde_ndx, int fd) {
9671 -       if (fde_ndx < 0) return -1;
9672 -       
9673 -       if ((size_t)fde_ndx >= ev->used) {
9674 -               fprintf(stderr, "%s.%d: del! out of range %d %zd\n", __FILE__, __LINE__, fde_ndx, ev->used);
9675 +static int fdevent_poll_event_del(fdevents *ev, iosocket *sock) {
9676 +       if (sock->fde_ndx < 0) return -1;
9677 +
9678 +       if ((size_t)sock->fde_ndx >= ev->used) {
9679 +               fprintf(stderr, "%s.%d: del! out of range %d %zd\n", __FILE__, __LINE__, sock->fde_ndx, ev->used);
9680                 SEGFAULT();
9681         }
9682 -       
9683 -       if (ev->pollfds[fde_ndx].fd == fd) {
9684 -               size_t k = fde_ndx;
9685 -               
9686 +
9687 +       if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9688 +               size_t k = sock->fde_ndx;
9689 +
9690                 ev->pollfds[k].fd = -1;
9691                 /* ev->pollfds[k].events = 0; */
9692                 /* ev->pollfds[k].revents = 0; */
9693 -               
9694 +
9695                 if (ev->unused.size == 0) {
9696                         ev->unused.size = 16;
9697                         ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size);
9698 @@ -40,48 +40,51 @@
9699                         ev->unused.size += 16;
9700                         ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
9701                 }
9702 -               
9703 +
9704                 ev->unused.ptr[ev->unused.used++] = k;
9705         } else {
9706                 SEGFAULT();
9707         }
9708 -       
9709 -       return -1;
9710 +
9711 +       sock->fde_ndx = -1;
9712 +
9713 +       return 0;
9714  }
9715  
9716  #if 0
9717  static int fdevent_poll_event_compress(fdevents *ev) {
9718         size_t j;
9719 -       
9720 +
9721         if (ev->used == 0) return 0;
9722         if (ev->unused.used != 0) return 0;
9723 -       
9724 +
9725         for (j = ev->used - 1; j + 1 > 0 && ev->pollfds[j].fd == -1; j--) ev->used--;
9726 -       
9727 +
9728         return 0;
9729  }
9730  #endif
9731  
9732 -static int fdevent_poll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9733 -       /* known index */
9734 -       
9735 -       if (fde_ndx != -1) {
9736 -               if (ev->pollfds[fde_ndx].fd == fd) {
9737 -                       ev->pollfds[fde_ndx].events = events;
9738 -                       
9739 -                       return fde_ndx;
9740 +static int fdevent_poll_event_add(fdevents *ev, iosocket *sock, int events) {
9741 +       if (sock->fde_ndx != -1) {
9742 +               /* this fd was already added, just change the requested events */
9743 +
9744 +               if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9745 +                       ev->pollfds[sock->fde_ndx].events = events;
9746 +
9747 +                       return sock->fde_ndx;
9748                 }
9749 -               fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, fde_ndx, ev->pollfds[fde_ndx].fd);
9750 +               fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, sock->fde_ndx, ev->pollfds[sock->fde_ndx].fd);
9751                 SEGFAULT();
9752         }
9753 -       
9754 +
9755         if (ev->unused.used > 0) {
9756                 int k = ev->unused.ptr[--ev->unused.used];
9757 -               
9758 -               ev->pollfds[k].fd = fd;
9759 +
9760 +               ev->pollfds[k].fd = sock->fd;
9761                 ev->pollfds[k].events = events;
9762 -               
9763 -               return k;
9764 +
9765 +               sock->fde_ndx = k;
9766 +
9767         } else {
9768                 if (ev->size == 0) {
9769                         ev->size = 16;
9770 @@ -90,12 +93,13 @@
9771                         ev->size += 16;
9772                         ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
9773                 }
9774 -               
9775 -               ev->pollfds[ev->used].fd = fd;
9776 +
9777 +               ev->pollfds[ev->used].fd = sock->fd;
9778                 ev->pollfds[ev->used].events = events;
9779 -               
9780 -               return ev->used++;
9781 +
9782 +               sock->fde_ndx = ev->used++;
9783         }
9784 +       return 0;
9785  }
9786  
9787  static int fdevent_poll_poll(fdevents *ev, int timeout_ms) {
9788 @@ -105,71 +109,38 @@
9789         return poll(ev->pollfds, ev->used, timeout_ms);
9790  }
9791  
9792 -static int fdevent_poll_event_get_revent(fdevents *ev, size_t ndx) {
9793 -       int r, poll_r;
9794 -       if (ndx >= ev->used) {
9795 -               fprintf(stderr, "%s.%d: dying because: event: %zd >= %zd\n", __FILE__, __LINE__, ndx, ev->used);
9796 -               
9797 -               SEGFAULT();
9798 -               
9799 -               return 0;
9800 -       }
9801 -       
9802 -       if (ev->pollfds[ndx].revents & POLLNVAL) {
9803 -               /* should never happen */
9804 -               SEGFAULT();
9805 -       }
9806 +static int fdevent_poll_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9807 +       size_t ndx;
9808  
9809 -       r = 0;
9810 -       poll_r = ev->pollfds[ndx].revents;
9811 +       for (ndx = 0; ndx < ev->used; ndx++) {
9812 +               if (ev->pollfds[ndx].revents) {
9813 +                       if (ev->pollfds[ndx].revents & POLLNVAL) {
9814 +                               /* should never happen */
9815 +                               SEGFAULT();
9816 +                       }
9817  
9818 -       /* map POLL* to FDEVEN_* */
9819 -
9820 -       if (poll_r & POLLIN) r |= FDEVENT_IN;
9821 -       if (poll_r & POLLOUT) r |= FDEVENT_OUT;
9822 -       if (poll_r & POLLERR) r |= FDEVENT_ERR;
9823 -       if (poll_r & POLLHUP) r |= FDEVENT_HUP;
9824 -       if (poll_r & POLLNVAL) r |= FDEVENT_NVAL;
9825 -       if (poll_r & POLLPRI) r |= FDEVENT_PRI;
9826 -       
9827 -       return ev->pollfds[ndx].revents;
9828 -}
9829 -
9830 -static int fdevent_poll_event_get_fd(fdevents *ev, size_t ndx) {
9831 -       return ev->pollfds[ndx].fd;
9832 -}
9833 -
9834 -static int fdevent_poll_event_next_fdndx(fdevents *ev, int ndx) {
9835 -       size_t i;
9836 -       
9837 -       i = (ndx < 0) ? 0 : ndx + 1;
9838 -       for (; i < ev->used; i++) {
9839 -               if (ev->pollfds[i].revents) break;
9840 +                       fdevent_revents_add(revents, ev->pollfds[ndx].fd, ev->pollfds[ndx].revents);
9841 +               }
9842         }
9843 -       
9844 -       return i;
9845 +
9846 +       return 0;
9847  }
9848  
9849  int fdevent_poll_init(fdevents *ev) {
9850         ev->type = FDEVENT_HANDLER_POLL;
9851  #define SET(x) \
9852         ev->x = fdevent_poll_##x;
9853 -       
9854 +
9855         SET(free);
9856         SET(poll);
9857 -       
9858 +
9859         SET(event_del);
9860         SET(event_add);
9861 -       
9862 -       SET(event_next_fdndx);
9863 -       SET(event_get_fd);
9864 -       SET(event_get_revent);
9865 -       
9866 -       return 0;
9867 -}
9868 -
9869  
9870 +       SET(get_revents);
9871  
9872 +       return 0;
9873 +}
9874  
9875  #else
9876  int fdevent_poll_init(fdevents *ev) {
9877 --- ../lighttpd-1.4.11/src/fdevent_select.c     2005-08-31 11:12:46.000000000 +0300
9878 +++ lighttpd-1.4.12/src/fdevent_select.c        2006-07-18 13:03:40.000000000 +0300
9879 @@ -1,18 +1,19 @@
9880 -#include <sys/time.h>
9881  #include <sys/types.h>
9882  
9883 -#include <unistd.h>
9884  #include <stdlib.h>
9885  #include <string.h>
9886  #include <errno.h>
9887  #include <signal.h>
9888  #include <fcntl.h>
9889  #include <assert.h>
9890 +#include <stdio.h>
9891  
9892  #include "fdevent.h"
9893  #include "settings.h"
9894  #include "buffer.h"
9895  
9896 +#include "sys-socket.h"
9897 +
9898  #ifdef USE_SELECT
9899  
9900  static int fdevent_select_reset(fdevents *ev) {
9901 @@ -24,101 +25,98 @@
9902         return 0;
9903  }
9904  
9905 -static int fdevent_select_event_del(fdevents *ev, int fde_ndx, int fd) {
9906 -       if (fde_ndx < 0) return -1;
9907 +static int fdevent_select_event_del(fdevents *ev, iosocket *sock) {
9908 +       if (sock->fde_ndx < 0) return -1;
9909  
9910 -       FD_CLR(fd, &(ev->select_set_read));
9911 -       FD_CLR(fd, &(ev->select_set_write));
9912 -       FD_CLR(fd, &(ev->select_set_error));
9913 +       FD_CLR(sock->fd, &(ev->select_set_read));
9914 +       FD_CLR(sock->fd, &(ev->select_set_write));
9915 +       FD_CLR(sock->fd, &(ev->select_set_error));
9916  
9917 -       return -1;
9918 -}
9919 +       /* mark the fdevent as deleted */
9920 +       sock->fde_ndx = -1;
9921  
9922 -static int fdevent_select_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9923 -       UNUSED(fde_ndx);
9924 +       return 0;
9925 +}
9926  
9927 +static int fdevent_select_event_add(fdevents *ev, iosocket *sock, int events) {
9928         /* we should be protected by max-fds, but you never know */
9929 -       assert(fd < FD_SETSIZE);
9930 +#ifndef _WIN32
9931 +       assert(sock->fd < FD_SETSIZE);
9932 +#endif
9933  
9934         if (events & FDEVENT_IN) {
9935 -               FD_SET(fd, &(ev->select_set_read));
9936 -               FD_CLR(fd, &(ev->select_set_write));
9937 +               FD_SET(sock->fd, &(ev->select_set_read));
9938 +               FD_CLR(sock->fd, &(ev->select_set_write));
9939         }
9940         if (events & FDEVENT_OUT) {
9941 -               FD_CLR(fd, &(ev->select_set_read));
9942 -               FD_SET(fd, &(ev->select_set_write));
9943 +               FD_CLR(sock->fd, &(ev->select_set_read));
9944 +               FD_SET(sock->fd, &(ev->select_set_write));
9945         }
9946 -       FD_SET(fd, &(ev->select_set_error));
9947 -       
9948 -       if (fd > ev->select_max_fd) ev->select_max_fd = fd;
9949 -       
9950 -       return fd;
9951 +       FD_SET(sock->fd, &(ev->select_set_error));
9952 +
9953 +       /* we need this for the poll */
9954 +       if (sock->fd > ev->select_max_fd) ev->select_max_fd = sock->fd;
9955 +
9956 +       /* mark fd as added */
9957 +       sock->fde_ndx = sock->fd;
9958 +
9959 +       return 0;
9960  }
9961  
9962  static int fdevent_select_poll(fdevents *ev, int timeout_ms) {
9963         struct timeval tv;
9964 -       
9965 +
9966         tv.tv_sec =  timeout_ms / 1000;
9967         tv.tv_usec = (timeout_ms % 1000) * 1000;
9968 -       
9969 +
9970         ev->select_read = ev->select_set_read;
9971         ev->select_write = ev->select_set_write;
9972         ev->select_error = ev->select_set_error;
9973 -       
9974 +
9975         return select(ev->select_max_fd + 1, &(ev->select_read), &(ev->select_write), &(ev->select_error), &tv);
9976  }
9977  
9978 -static int fdevent_select_event_get_revent(fdevents *ev, size_t ndx) {
9979 -       int revents = 0;
9980 -       
9981 -       if (FD_ISSET(ndx, &(ev->select_read))) {
9982 -               revents |= FDEVENT_IN;
9983 +/**
9984 + * scan the fdset for events 
9985 + */
9986 +static int fdevent_select_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9987 +
9988 +       int ndx = 0;
9989 +
9990 +       for (ndx = 0; ndx < ev->select_max_fd; ndx++) {
9991 +               int events = 0;
9992 +
9993 +               if (FD_ISSET(ndx, &(ev->select_read))) {
9994 +                       events |= FDEVENT_IN;
9995 +               }
9996 +               if (FD_ISSET(ndx, &(ev->select_write))) {
9997 +                       events |= FDEVENT_OUT;
9998 +               }
9999 +               if (FD_ISSET(ndx, &(ev->select_error))) {
10000 +                       events |= FDEVENT_ERR;
10001 +               }
10002 +
10003 +               if (events) {
10004 +                       fdevent_revents_add(revents, ndx, events);
10005 +               }
10006         }
10007 -       if (FD_ISSET(ndx, &(ev->select_write))) {
10008 -               revents |= FDEVENT_OUT;
10009 -       }
10010 -       if (FD_ISSET(ndx, &(ev->select_error))) {
10011 -               revents |= FDEVENT_ERR;
10012 -       }
10013 -       
10014 -       return revents;
10015 -}
10016 -
10017 -static int fdevent_select_event_get_fd(fdevents *ev, size_t ndx) {
10018 -       UNUSED(ev);
10019 -
10020 -       return ndx;
10021 -}
10022  
10023 -static int fdevent_select_event_next_fdndx(fdevents *ev, int ndx) {
10024 -       int i;
10025 -       
10026 -       i = (ndx < 0) ? 0 : ndx + 1;
10027 -       
10028 -       for (; i < ev->select_max_fd + 1; i++) {
10029 -               if (FD_ISSET(i, &(ev->select_read))) break;
10030 -               if (FD_ISSET(i, &(ev->select_write))) break;
10031 -               if (FD_ISSET(i, &(ev->select_error))) break;
10032 -       }
10033 -       
10034 -       return i;
10035 +       return 0;
10036  }
10037  
10038  int fdevent_select_init(fdevents *ev) {
10039         ev->type = FDEVENT_HANDLER_SELECT;
10040  #define SET(x) \
10041         ev->x = fdevent_select_##x;
10042 -       
10043 +
10044         SET(reset);
10045         SET(poll);
10046 -       
10047 +
10048         SET(event_del);
10049         SET(event_add);
10050 -       
10051 -       SET(event_next_fdndx);
10052 -       SET(event_get_fd);
10053 -       SET(event_get_revent);
10054 -       
10055 +
10056 +       SET(get_revents);
10057 +
10058         return 0;
10059  }
10060  
10061 --- ../lighttpd-1.4.11/src/fdevent_solaris_devpoll.c    2005-09-01 10:45:26.000000000 +0300
10062 +++ lighttpd-1.4.12/src/fdevent_solaris_devpoll.c       2006-07-16 00:26:03.000000000 +0300
10063 @@ -1,6 +1,5 @@
10064  #include <sys/types.h>
10065  
10066 -#include <unistd.h>
10067  #include <stdlib.h>
10068  #include <stdio.h>
10069  #include <string.h>
10070 @@ -23,55 +22,55 @@
10071  
10072  static int fdevent_solaris_devpoll_event_del(fdevents *ev, int fde_ndx, int fd) {
10073         struct pollfd pfd;
10074 -               
10075 +
10076         if (fde_ndx < 0) return -1;
10077 -       
10078 +
10079         pfd.fd = fd;
10080         pfd.events = POLLREMOVE;
10081         pfd.revents = 0;
10082 -       
10083 +
10084         if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
10085 -               fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n", 
10086 -                       __FILE__, __LINE__, 
10087 +               fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
10088 +                       __FILE__, __LINE__,
10089                         fd, strerror(errno));
10090 -               
10091 +
10092                 return -1;
10093         }
10094 -       
10095 +
10096         return -1;
10097  }
10098  
10099  static int fdevent_solaris_devpoll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
10100         struct pollfd pfd;
10101         int add = 0;
10102 -               
10103 +
10104         if (fde_ndx == -1) add = 1;
10105 -       
10106 +
10107         pfd.fd = fd;
10108         pfd.events = events;
10109         pfd.revents = 0;
10110 -       
10111 +
10112         if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
10113 -               fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n", 
10114 -                       __FILE__, __LINE__, 
10115 +               fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
10116 +                       __FILE__, __LINE__,
10117                         fd, strerror(errno));
10118 -               
10119 +
10120                 return -1;
10121         }
10122 -       
10123 +
10124         return fd;
10125  }
10126  
10127  static int fdevent_solaris_devpoll_poll(fdevents *ev, int timeout_ms) {
10128         struct dvpoll dopoll;
10129         int ret;
10130 -       
10131 +
10132         dopoll.dp_timeout = timeout_ms;
10133         dopoll.dp_nfds = ev->maxfds;
10134         dopoll.dp_fds = ev->devpollfds;
10135 -       
10136 +
10137         ret = ioctl(ev->devpoll_fd, DP_POLL, &dopoll);
10138 -       
10139 +
10140         return ret;
10141  }
10142  
10143 @@ -85,11 +84,11 @@
10144  
10145  static int fdevent_solaris_devpoll_event_next_fdndx(fdevents *ev, int last_ndx) {
10146         size_t i;
10147 -       
10148 +
10149         UNUSED(ev);
10150  
10151         i = (last_ndx < 0) ? 0 : last_ndx + 1;
10152 -       
10153 +
10154         return i;
10155  }
10156  
10157 @@ -117,20 +116,20 @@
10158         ev->type = FDEVENT_HANDLER_SOLARIS_DEVPOLL;
10159  #define SET(x) \
10160         ev->x = fdevent_solaris_devpoll_##x;
10161 -       
10162 +
10163         SET(free);
10164         SET(poll);
10165         SET(reset);
10166 -       
10167 +
10168         SET(event_del);
10169         SET(event_add);
10170 -       
10171 +
10172         SET(event_next_fdndx);
10173         SET(event_get_fd);
10174         SET(event_get_revent);
10175 -       
10176 +
10177         ev->devpollfds = malloc(sizeof(*ev->devpollfds) * ev->maxfds);
10178 -       
10179 +
10180         if ((ev->devpoll_fd = open("/dev/poll", O_RDWR)) < 0) {
10181                 fprintf(stderr, "%s.%d: opening /dev/poll failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
10182                         __FILE__, __LINE__, strerror(errno));
10183 @@ -152,7 +151,7 @@
10184  
10185         fprintf(stderr, "%s.%d: solaris-devpoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
10186                         __FILE__, __LINE__);
10187 -       
10188 +
10189         return -1;
10190  }
10191  #endif
10192 --- ../lighttpd-1.4.11/src/http-header-glue.c   2006-02-08 15:31:36.000000000 +0200
10193 +++ lighttpd-1.4.12/src/http-header-glue.c      2006-07-18 13:03:40.000000000 +0300
10194 @@ -45,20 +45,20 @@
10195  #   ifdef HAVE_STRUCT_SOCKADDR_STORAGE
10196  static size_t get_sa_len(const struct sockaddr *addr) {
10197         switch (addr->sa_family) {
10198 -               
10199 +
10200  #    ifdef AF_INET
10201         case AF_INET:
10202                 return (sizeof (struct sockaddr_in));
10203  #    endif
10204 -               
10205 +
10206  #    ifdef AF_INET6
10207         case AF_INET6:
10208                 return (sizeof (struct sockaddr_in6));
10209  #    endif
10210 -               
10211 +
10212         default:
10213                 return (sizeof (struct sockaddr));
10214 -               
10215 +
10216         }
10217  }
10218  #    define SA_LEN(addr)   (get_sa_len(addr))
10219 @@ -74,7 +74,7 @@
10220  
10221  int response_header_insert(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
10222         data_string *ds;
10223 -       
10224 +
10225         UNUSED(srv);
10226  
10227         if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
10228 @@ -82,32 +82,32 @@
10229         }
10230         buffer_copy_string_len(ds->key, key, keylen);
10231         buffer_copy_string_len(ds->value, value, vallen);
10232 -       
10233 +
10234         array_insert_unique(con->response.headers, (data_unset *)ds);
10235 -       
10236 +
10237         return 0;
10238  }
10239  
10240  int response_header_overwrite(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
10241         data_string *ds;
10242 -       
10243 +
10244         UNUSED(srv);
10245  
10246         /* if there already is a key by this name overwrite the value */
10247         if (NULL != (ds = (data_string *)array_get_element(con->response.headers, key))) {
10248                 buffer_copy_string(ds->value, value);
10249 -               
10250 +
10251                 return 0;
10252         }
10253 -       
10254 +
10255         return response_header_insert(srv, con, key, keylen, value, vallen);
10256  }
10257  
10258  int http_response_redirect_to_directory(server *srv, connection *con) {
10259         buffer *o;
10260 -       
10261 +
10262         o = buffer_init();
10263 -       
10264 +
10265         if (con->conf.is_ssl) {
10266                 buffer_copy_string(o, "https://");
10267         } else {
10268 @@ -123,36 +123,36 @@
10269  #endif
10270                 sock_addr our_addr;
10271                 socklen_t our_addr_len;
10272 -               
10273 +
10274                 our_addr_len = sizeof(our_addr);
10275 -               
10276 -               if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
10277 +
10278 +               if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
10279                         con->http_status = 500;
10280 -                       
10281 +
10282                         log_error_write(srv, __FILE__, __LINE__, "ss",
10283                                         "can't get sockname", strerror(errno));
10284 -                       
10285 +
10286                         buffer_free(o);
10287                         return 0;
10288                 }
10289 -               
10290 -               
10291 +
10292 +
10293                 /* Lookup name: secondly try to get hostname for bind address */
10294                 switch(our_addr.plain.sa_family) {
10295  #ifdef HAVE_IPV6
10296                 case AF_INET6:
10297 -                       if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6), 
10298 -                                            SA_LEN((const struct sockaddr *)&our_addr.ipv6), 
10299 +                       if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6),
10300 +                                            SA_LEN((const struct sockaddr *)&our_addr.ipv6),
10301                                              hbuf, sizeof(hbuf), NULL, 0, 0)) {
10302 -                               
10303 +
10304                                 char dst[INET6_ADDRSTRLEN];
10305 -                               
10306 +
10307                                 log_error_write(srv, __FILE__, __LINE__,
10308                                                 "SSSS", "NOTICE: getnameinfo failed: ",
10309                                                 strerror(errno), ", using ip-address instead");
10310 -                               
10311 -                               buffer_append_string(o, 
10312 -                                                    inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr, 
10313 +
10314 +                               buffer_append_string(o,
10315 +                                                    inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr,
10316                                                                dst, sizeof(dst)));
10317                         } else {
10318                                 buffer_append_string(o, hbuf);
10319 @@ -164,7 +164,7 @@
10320                                 log_error_write(srv, __FILE__, __LINE__,
10321                                                 "SdSS", "NOTICE: gethostbyaddr failed: ",
10322                                                 h_errno, ", using ip-address instead");
10323 -                               
10324 +
10325                                 buffer_append_string(o, inet_ntoa(our_addr.ipv4.sin_addr));
10326                         } else {
10327                                 buffer_append_string(o, he->h_name);
10328 @@ -173,12 +173,12 @@
10329                 default:
10330                         log_error_write(srv, __FILE__, __LINE__,
10331                                         "S", "ERROR: unsupported address-type");
10332 -                       
10333 +
10334                         buffer_free(o);
10335                         return -1;
10336                 }
10337 -               
10338 -               if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) || 
10339 +
10340 +               if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) ||
10341                       (con->conf.is_ssl == 1 && srv->srvconf.port == 443))) {
10342                         buffer_append_string(o, ":");
10343                         buffer_append_long(o, srv->srvconf.port);
10344 @@ -190,41 +190,41 @@
10345                 buffer_append_string(o, "?");
10346                 buffer_append_string_buffer(o, con->uri.query);
10347         }
10348 -       
10349 +
10350         response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(o));
10351 -       
10352 +
10353         con->http_status = 301;
10354         con->file_finished = 1;
10355 -       
10356 +
10357         buffer_free(o);
10358 -       
10359 +
10360         return 0;
10361  }
10362  
10363  buffer * strftime_cache_get(server *srv, time_t last_mod) {
10364         struct tm *tm;
10365         size_t i;
10366 -               
10367 +
10368         for (i = 0; i < FILE_CACHE_MAX; i++) {
10369                 /* found cache-entry */
10370                 if (srv->mtime_cache[i].mtime == last_mod) return srv->mtime_cache[i].str;
10371 -                               
10372 +
10373                 /* found empty slot */
10374                 if (srv->mtime_cache[i].mtime == 0) break;
10375         }
10376 -       
10377 +
10378         if (i == FILE_CACHE_MAX) {
10379                 i = 0;
10380         }
10381 -               
10382 +
10383         srv->mtime_cache[i].mtime = last_mod;
10384         buffer_prepare_copy(srv->mtime_cache[i].str, 1024);
10385         tm = gmtime(&(srv->mtime_cache[i].mtime));
10386 -       srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr, 
10387 +       srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr,
10388                                                  srv->mtime_cache[i].str->size - 1,
10389                                                  "%a, %d %b %Y %H:%M:%S GMT", tm);
10390         srv->mtime_cache[i].str->used++;
10391 -       
10392 +
10393         return srv->mtime_cache[i].str;
10394  }
10395  
10396 @@ -239,56 +239,60 @@
10397          *    request. That is, if no entity tags match, then the server MUST NOT
10398          *    return a 304 (Not Modified) response.
10399          */
10400 -       
10401 +
10402         /* last-modified handling */
10403         if (con->request.http_if_none_match) {
10404                 if (etag_is_equal(con->physical.etag, con->request.http_if_none_match)) {
10405 -                       if (con->request.http_method == HTTP_METHOD_GET || 
10406 +                       if (con->request.http_method == HTTP_METHOD_GET ||
10407                             con->request.http_method == HTTP_METHOD_HEAD) {
10408 -                               
10409 +
10410                                 /* check if etag + last-modified */
10411                                 if (con->request.http_if_modified_since) {
10412                                         size_t used_len;
10413                                         char *semicolon;
10414 -                                       
10415 +
10416                                         if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
10417                                                 used_len = strlen(con->request.http_if_modified_since);
10418                                         } else {
10419                                                 used_len = semicolon - con->request.http_if_modified_since;
10420                                         }
10421 -                                       
10422 +
10423                                         if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
10424                                                 con->http_status = 304;
10425                                                 return HANDLER_FINISHED;
10426                                         } else {
10427 +#ifdef HAVE_STRPTIME
10428                                                 char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
10429 +                                               time_t t_header, t_file;
10430 +                                               struct tm tm;
10431  
10432 -                                               /* convert to timestamp */
10433 -                                               if (used_len < sizeof(buf)) {
10434 -                                                       time_t t_header, t_file;
10435 -                                                       struct tm tm;
10436 -                                                       
10437 -                                                       strncpy(buf, con->request.http_if_modified_since, used_len);
10438 -                                                       buf[used_len] = '\0';
10439 -                                                       
10440 -                                                       strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10441 -                                                       t_header = mktime(&tm);
10442 -                                                       
10443 -                                                       strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10444 -                                                       t_file = mktime(&tm);
10445 -
10446 -                                                       if (t_file > t_header) {
10447 -                                                               con->http_status = 304;
10448 -                                                               return HANDLER_FINISHED;
10449 -                                                       }
10450 -                                               } else {
10451 -                                                       log_error_write(srv, __FILE__, __LINE__, "ssdd", 
10452 -                                                                       "DEBUG: Last-Modified check failed as the received timestamp was too long:", 
10453 +                                               /* check if we can safely copy the string */
10454 +                                               if (used_len >= sizeof(buf)) {
10455 +                                                       log_error_write(srv, __FILE__, __LINE__, "ssdd",
10456 +                                                                       "DEBUG: Last-Modified check failed as the received timestamp was too long:",
10457                                                                         con->request.http_if_modified_since, used_len, sizeof(buf) - 1);
10458 -                                                       
10459 +
10460                                                         con->http_status = 412;
10461                                                         return HANDLER_FINISHED;
10462                                                 }
10463 +
10464 +
10465 +                                               strncpy(buf, con->request.http_if_modified_since, used_len);
10466 +                                               buf[used_len] = '\0';
10467 +
10468 +                                               strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10469 +                                               t_header = mktime(&tm);
10470 +
10471 +                                               strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10472 +                                               t_file = mktime(&tm);
10473 +
10474 +                                               if (t_file > t_header) return HANDLER_GO_ON;
10475 +
10476 +                                               con->http_status = 304;
10477 +                                               return HANDLER_FINISHED;
10478 +#else
10479 +                        return HANDLER_GO_ON;
10480 +#endif
10481                                         }
10482                                 } else {
10483                                         con->http_status = 304;
10484 @@ -302,16 +306,41 @@
10485         } else if (con->request.http_if_modified_since) {
10486                 size_t used_len;
10487                 char *semicolon;
10488 -               
10489 +
10490                 if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
10491                         used_len = strlen(con->request.http_if_modified_since);
10492                 } else {
10493                         used_len = semicolon - con->request.http_if_modified_since;
10494                 }
10495 -               
10496 +
10497                 if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
10498                         con->http_status = 304;
10499                         return HANDLER_FINISHED;
10500 +               } else {
10501 +#ifdef HAVE_STRPTIME
10502 +                       char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
10503 +                       time_t t_header, t_file;
10504 +                       struct tm tm;
10505 +
10506 +                       /* convert to timestamp */
10507 +                       if (used_len >= sizeof(buf)) return HANDLER_GO_ON;
10508 +
10509 +                       strncpy(buf, con->request.http_if_modified_since, used_len);
10510 +                       buf[used_len] = '\0';
10511 +
10512 +                       strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10513 +                       t_header = mktime(&tm);
10514 +
10515 +                       strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10516 +                       t_file = mktime(&tm);
10517 +
10518 +                       if (t_file > t_header) return HANDLER_GO_ON;
10519 +
10520 +                       con->http_status = 304;
10521 +                       return HANDLER_FINISHED;
10522 +#else
10523 +            return HANDLER_GO_ON;
10524 +#endif
10525                 }
10526         }
10527  
10528 --- ../lighttpd-1.4.11/src/http_auth.c  2006-02-01 13:02:52.000000000 +0200
10529 +++ lighttpd-1.4.12/src/http_auth.c     2006-07-18 13:03:40.000000000 +0300
10530 @@ -22,7 +22,6 @@
10531  #include <string.h>
10532  #include <time.h>
10533  #include <errno.h>
10534 -#include <unistd.h>
10535  #include <ctype.h>
10536  
10537  #include "server.h"
10538 @@ -31,23 +30,14 @@
10539  #include "http_auth_digest.h"
10540  #include "stream.h"
10541  
10542 +#include "sys-strings.h"
10543 +
10544  #ifdef USE_OPENSSL
10545  # include <openssl/md5.h>
10546  #else
10547  # include "md5.h"
10548  #endif
10549  
10550 -
10551 -#ifdef USE_PAM
10552 -#include <security/pam_appl.h>
10553 -#include <security/pam_misc.h>
10554 -
10555 -static struct pam_conv conv = {
10556 -       misc_conv,
10557 -               NULL
10558 -};
10559 -#endif
10560 -
10561  handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s);
10562  
10563  static const char base64_pad = '=';
10564 @@ -75,25 +65,25 @@
10565         unsigned char *result;
10566         int ch, j = 0, k;
10567         size_t i;
10568 -       
10569 +
10570         size_t in_len = strlen(in);
10571 -       
10572 +
10573         buffer_prepare_copy(out, in_len);
10574 -       
10575 +
10576         result = (unsigned char *)out->ptr;
10577 -       
10578 +
10579         ch = in[0];
10580         /* run through the whole string, converting as we go */
10581         for (i = 0; i < in_len; i++) {
10582                 ch = in[i];
10583 -               
10584 +
10585                 if (ch == '\0') break;
10586 -               
10587 +
10588                 if (ch == base64_pad) break;
10589 -               
10590 +
10591                 ch = base64_reverse_table[ch];
10592                 if (ch < 0) continue;
10593 -               
10594 +
10595                 switch(i % 4) {
10596                 case 0:
10597                         result[j] = ch << 2;
10598 @@ -125,168 +115,168 @@
10599                 }
10600         }
10601         result[k] = '\0';
10602 -       
10603 +
10604         out->used = k;
10605 -       
10606 +
10607         return result;
10608  }
10609  
10610  static int http_auth_get_password(server *srv, mod_auth_plugin_data *p, buffer *username, buffer *realm, buffer *password) {
10611         int ret = -1;
10612 -       
10613 +
10614         if (!username->used|| !realm->used) return -1;
10615 -       
10616 +
10617         if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
10618                 stream f;
10619                 char * f_line;
10620 -               
10621 +
10622                 if (buffer_is_empty(p->conf.auth_htdigest_userfile)) return -1;
10623 -               
10624 +
10625                 if (0 != stream_open(&f, p->conf.auth_htdigest_userfile)) {
10626                         log_error_write(srv, __FILE__, __LINE__, "sbss", "opening digest-userfile", p->conf.auth_htdigest_userfile, "failed:", strerror(errno));
10627 -                       
10628 +
10629                         return -1;
10630                 }
10631 -               
10632 +
10633                 f_line = f.start;
10634 -               
10635 +
10636                 while (f_line - f.start != f.size) {
10637                         char *f_user, *f_pwd, *e, *f_realm;
10638                         size_t u_len, pwd_len, r_len;
10639 -                       
10640 +
10641                         f_user = f_line;
10642 -                       
10643 -                       /* 
10644 +
10645 +                       /*
10646                          * htdigest format
10647 -                        * 
10648 -                        * user:realm:md5(user:realm:password) 
10649 +                        *
10650 +                        * user:realm:md5(user:realm:password)
10651                          */
10652 -                       
10653 +
10654                         if (NULL == (f_realm = memchr(f_user, ':', f.size - (f_user - f.start) ))) {
10655 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
10656 -                                               "parsed error in", p->conf.auth_htdigest_userfile, 
10657 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
10658 +                                               "parsed error in", p->conf.auth_htdigest_userfile,
10659                                                 "expected 'username:realm:hashed password'");
10660 -                               
10661 +
10662                                 stream_close(&f);
10663 -                               
10664 +
10665                                 return -1;
10666                         }
10667 -                       
10668 +
10669                         if (NULL == (f_pwd = memchr(f_realm + 1, ':', f.size - (f_realm + 1 - f.start)))) {
10670 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
10671 -                                               "parsed error in", p->conf.auth_plain_userfile, 
10672 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
10673 +                                               "parsed error in", p->conf.auth_plain_userfile,
10674                                                 "expected 'username:realm:hashed password'");
10675 -                               
10676 +
10677                                 stream_close(&f);
10678 -                               
10679 +
10680                                 return -1;
10681                         }
10682 -                       
10683 +
10684                         /* get pointers to the fields */
10685 -                       u_len = f_realm - f_user; 
10686 +                       u_len = f_realm - f_user;
10687                         f_realm++;
10688                         r_len = f_pwd - f_realm;
10689                         f_pwd++;
10690 -                       
10691 +
10692                         if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
10693                                 pwd_len = e - f_pwd;
10694                         } else {
10695                                 pwd_len = f.size - (f_pwd - f.start);
10696                         }
10697 -                       
10698 +
10699                         if (username->used - 1 == u_len &&
10700                             (realm->used - 1 == r_len) &&
10701                             (0 == strncmp(username->ptr, f_user, u_len)) &&
10702                             (0 == strncmp(realm->ptr, f_realm, r_len))) {
10703                                 /* found */
10704 -                               
10705 +
10706                                 buffer_copy_string_len(password, f_pwd, pwd_len);
10707 -                               
10708 +
10709                                 ret = 0;
10710                                 break;
10711                         }
10712 -                       
10713 +
10714                         /* EOL */
10715                         if (!e) break;
10716 -                       
10717 +
10718                         f_line = e + 1;
10719                 }
10720 -               
10721 +
10722                 stream_close(&f);
10723         } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD ||
10724                    p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
10725                 stream f;
10726                 char * f_line;
10727                 buffer *auth_fn;
10728 -               
10729 +
10730                 auth_fn = (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) ? p->conf.auth_htpasswd_userfile : p->conf.auth_plain_userfile;
10731 -               
10732 +
10733                 if (buffer_is_empty(auth_fn)) return -1;
10734 -               
10735 +
10736                 if (0 != stream_open(&f, auth_fn)) {
10737 -                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
10738 +                       log_error_write(srv, __FILE__, __LINE__, "sbss",
10739                                         "opening plain-userfile", auth_fn, "failed:", strerror(errno));
10740 -                       
10741 +
10742                         return -1;
10743                 }
10744 -               
10745 +
10746                 f_line = f.start;
10747 -               
10748 +
10749                 while (f_line - f.start != f.size) {
10750                         char *f_user, *f_pwd, *e;
10751                         size_t u_len, pwd_len;
10752 -                       
10753 +
10754                         f_user = f_line;
10755 -                       
10756 -                       /* 
10757 +
10758 +                       /*
10759                          * htpasswd format
10760 -                        * 
10761 +                        *
10762                          * user:crypted passwd
10763                          */
10764 -                       
10765 +
10766                         if (NULL == (f_pwd = memchr(f_user, ':', f.size - (f_user - f.start) ))) {
10767 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
10768 -                                               "parsed error in", auth_fn, 
10769 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
10770 +                                               "parsed error in", auth_fn,
10771                                                 "expected 'username:hashed password'");
10772 -                               
10773 +
10774                                 stream_close(&f);
10775 -                               
10776 +
10777                                 return -1;
10778                         }
10779 -                       
10780 +
10781                         /* get pointers to the fields */
10782 -                       u_len = f_pwd - f_user; 
10783 +                       u_len = f_pwd - f_user;
10784                         f_pwd++;
10785 -                       
10786 +
10787                         if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
10788                                 pwd_len = e - f_pwd;
10789                         } else {
10790                                 pwd_len = f.size - (f_pwd - f.start);
10791                         }
10792 -                       
10793 +
10794                         if (username->used - 1 == u_len &&
10795                             (0 == strncmp(username->ptr, f_user, u_len))) {
10796                                 /* found */
10797 -                               
10798 +
10799                                 buffer_copy_string_len(password, f_pwd, pwd_len);
10800 -                               
10801 +
10802                                 ret = 0;
10803                                 break;
10804                         }
10805 -                       
10806 +
10807                         /* EOL */
10808                         if (!e) break;
10809 -                       
10810 +
10811                         f_line = e + 1;
10812                 }
10813 -               
10814 +
10815                 stream_close(&f);
10816         } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
10817                 ret = 0;
10818         } else {
10819                 return -1;
10820         }
10821 -       
10822 +
10823         return ret;
10824  }
10825  
10826 @@ -296,7 +286,7 @@
10827         int username_len;
10828         data_string *require;
10829         array *req;
10830 -       
10831 +
10832         UNUSED(group);
10833         UNUSED(host);
10834  
10835 @@ -304,12 +294,12 @@
10836         /* search auth-directives for path */
10837         for (i = 0; i < p->conf.auth_require->used; i++) {
10838                 if (p->conf.auth_require->data[i]->key->used == 0) continue;
10839 -               
10840 +
10841                 if (0 == strncmp(url, p->conf.auth_require->data[i]->key->ptr, p->conf.auth_require->data[i]->key->used - 1)) {
10842                         break;
10843                 }
10844         }
10845 -       
10846 +
10847         if (i == p->conf.auth_require->used) {
10848                 return -1;
10849         }
10850 @@ -317,72 +307,72 @@
10851         req = ((data_array *)(p->conf.auth_require->data[i]))->value;
10852  
10853         require = (data_string *)array_get_element(req, "require");
10854 -       
10855 +
10856         /* if we get here, the user we got a authed user */
10857 -       if (0 == strcmp(require->value->ptr, "valid-user")) {
10858 +       if (buffer_is_equal_string(require->value, CONST_STR_LEN("valid-user"))) {
10859                 return 0;
10860         }
10861 -       
10862 +
10863         /* user=name1|group=name3|host=name4 */
10864 -       
10865 +
10866         /* seperate the string by | */
10867  #if 0
10868         log_error_write(srv, __FILE__, __LINE__, "sb", "rules", require->value);
10869 -#endif 
10870 -       
10871 +#endif
10872 +
10873         username_len = username ? strlen(username) : 0;
10874 -       
10875 +
10876         r = rules = require->value->ptr;
10877 -       
10878 +
10879         while (1) {
10880                 const char *eq;
10881                 const char *k, *v, *e;
10882                 int k_len, v_len, r_len;
10883 -               
10884 +
10885                 e = strchr(r, '|');
10886 -               
10887 +
10888                 if (e) {
10889                         r_len = e - r;
10890                 } else {
10891                         r_len = strlen(rules) - (r - rules);
10892                 }
10893 -               
10894 +
10895                 /* from r to r + r_len is a rule */
10896 -               
10897 +
10898                 if (0 == strncmp(r, "valid-user", r_len)) {
10899 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
10900 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
10901                                         "parsing the 'require' section in 'auth.require' failed: valid-user cannot be combined with other require rules",
10902                                         require->value);
10903                         return -1;
10904                 }
10905 -               
10906 +
10907                 /* search for = in the rules */
10908                 if (NULL == (eq = strchr(r, '='))) {
10909 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
10910 -                                       "parsing the 'require' section in 'auth.require' failed: a = is missing", 
10911 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
10912 +                                       "parsing the 'require' section in 'auth.require' failed: a = is missing",
10913                                         require->value);
10914                         return -1;
10915                 }
10916 -               
10917 +
10918                 /* = out of range */
10919                 if (eq > r + r_len) {
10920 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
10921 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
10922                                         "parsing the 'require' section in 'auth.require' failed: = out of range",
10923                                         require->value);
10924 -                       
10925 +
10926                         return -1;
10927                 }
10928 -               
10929 +
10930                 /* the part before the = is user|group|host */
10931 -               
10932 +
10933                 k = r;
10934                 k_len = eq - r;
10935                 v = eq + 1;
10936                 v_len = r_len - k_len - 1;
10937 -               
10938 +
10939                 if (k_len == 4) {
10940                         if (0 == strncmp(k, "user", k_len)) {
10941 -                               if (username && 
10942 +                               if (username &&
10943                                     username_len == v_len &&
10944                                     0 == strncmp(username, v, v_len)) {
10945                                         return 0;
10946 @@ -404,19 +394,19 @@
10947                         log_error_write(srv, __FILE__, __LINE__, "s", "unknown  key");
10948                         return -1;
10949                 }
10950 -               
10951 +
10952                 if (!e) break;
10953                 r = e + 1;
10954         }
10955 -       
10956 +
10957         log_error_write(srv, __FILE__, __LINE__, "s", "nothing matched");
10958 -       
10959 +
10960         return -1;
10961  }
10962  
10963  /**
10964 - * 
10965 - * 
10966 + *
10967 + *
10968   * @param password password-string from the auth-backend
10969   * @param pw       password-string from the client
10970   */
10971 @@ -426,16 +416,16 @@
10972         UNUSED(req);
10973  
10974         if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
10975 -               /* 
10976 +               /*
10977                  * htdigest format
10978 -                * 
10979 -                * user:realm:md5(user:realm:password) 
10980 +                *
10981 +                * user:realm:md5(user:realm:password)
10982                  */
10983 -               
10984 +
10985                 MD5_CTX Md5Ctx;
10986                 HASH HA1;
10987                 char a1[256];
10988 -               
10989 +
10990                 MD5_Init(&Md5Ctx);
10991                 MD5_Update(&Md5Ctx, (unsigned char *)username->ptr, username->used - 1);
10992                 MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
10993 @@ -443,24 +433,24 @@
10994                 MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
10995                 MD5_Update(&Md5Ctx, (unsigned char *)pw, strlen(pw));
10996                 MD5_Final(HA1, &Md5Ctx);
10997 -               
10998 +
10999                 CvtHex(HA1, a1);
11000 -               
11001 -               if (0 == strcmp(password->ptr, a1)) {
11002 +
11003 +               if (buffer_is_equal_string(password, a1, strlen(a1))) {
11004                         return 0;
11005                 }
11006 -       } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) { 
11007 -#ifdef HAVE_CRYPT      
11008 +       } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) {
11009 +#ifdef HAVE_CRYPT
11010                 char salt[32];
11011                 char *crypted;
11012                 size_t salt_len = 0;
11013 -               /* 
11014 +               /*
11015                  * htpasswd format
11016 -                * 
11017 +                *
11018                  * user:crypted password
11019                  */
11020  
11021 -               /* 
11022 +               /*
11023                  *  Algorithm      Salt
11024                  *  CRYPT_STD_DES   2-character (Default)
11025                  *  CRYPT_EXT_DES   9-character
11026 @@ -478,7 +468,7 @@
11027                         salt_len = 2;
11028                 } else if (password->ptr[0] == '$' && password->ptr[2] == '$') {
11029                         char *dollar = NULL;
11030 -               
11031 +
11032                         if (NULL == (dollar = strchr(password->ptr + 3, '$'))) {
11033                                 fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
11034                                 return -1;
11035 @@ -495,48 +485,21 @@
11036                 strncpy(salt, password->ptr, salt_len);
11037  
11038                 salt[salt_len] = '\0';
11039 -               
11040 +
11041                 crypted = crypt(pw, salt);
11042  
11043 -               if (0 == strcmp(password->ptr, crypted)) {
11044 +               if (buffer_is_equal_string(password, crypted, strlen(crypted))) {
11045                         return 0;
11046                 } else {
11047                         fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
11048                 }
11049 -       
11050 -#endif 
11051 -       } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) { 
11052 -               if (0 == strcmp(password->ptr, pw)) {
11053 -                       return 0;
11054 -               }
11055 -       } else if (p->conf.auth_backend == AUTH_BACKEND_PAM) { 
11056 -#ifdef USE_PAM
11057 -               pam_handle_t *pamh=NULL;
11058 -               int retval;
11059 -               
11060 -               retval = pam_start("lighttpd", username->ptr, &conv, &pamh);
11061 -               
11062 -               if (retval == PAM_SUCCESS)
11063 -                       retval = pam_authenticate(pamh, 0);    /* is user really user? */
11064 -               
11065 -               if (retval == PAM_SUCCESS)
11066 -                       retval = pam_acct_mgmt(pamh, 0);       /* permitted access? */
11067 -               
11068 -               /* This is where we have been authorized or not. */
11069 -               
11070 -               if (pam_end(pamh,retval) != PAM_SUCCESS) {     /* close Linux-PAM */
11071 -                       pamh = NULL;
11072 -                       log_error_write(srv, __FILE__, __LINE__, "s", "failed to release authenticator");
11073 -               }
11074 -               
11075 -               if (retval == PAM_SUCCESS) {
11076 -                       log_error_write(srv, __FILE__, __LINE__, "s", "Authenticated");
11077 +
11078 +#endif
11079 +       } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
11080 +               if (buffer_is_equal_string(password, pw, strlen(pw))) {
11081                         return 0;
11082 -               } else {
11083 -                       log_error_write(srv, __FILE__, __LINE__, "s", "Not Authenticated");
11084                 }
11085 -#endif
11086 -       } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) { 
11087 +       } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
11088  #ifdef USE_LDAP
11089                 LDAP *ldap;
11090                 LDAPMessage *lm, *first;
11091 @@ -544,45 +507,45 @@
11092                 int ret;
11093                 char *attrs[] = { LDAP_NO_ATTRS, NULL };
11094                 size_t i;
11095 -               
11096 +
11097                 /* for now we stay synchronous */
11098 -               
11099 -               /* 
11100 +
11101 +               /*
11102                  * 1. connect anonymously (done in plugin init)
11103                  * 2. get DN for uid = username
11104                  * 3. auth against ldap server
11105                  * 4. (optional) check a field
11106                  * 5. disconnect
11107 -                * 
11108 +                *
11109                  */
11110 -               
11111 +
11112                 /* check username
11113 -                * 
11114 +                *
11115                  * we have to protect us againt username which modifies out filter in
11116                  * a unpleasant way
11117                  */
11118 -               
11119 +
11120                 for (i = 0; i < username->used - 1; i++) {
11121                         char c = username->ptr[i];
11122 -                       
11123 +
11124                         if (!isalpha(c) &&
11125                             !isdigit(c)) {
11126 -                               
11127 -                               log_error_write(srv, __FILE__, __LINE__, "sbd", 
11128 +
11129 +                               log_error_write(srv, __FILE__, __LINE__, "sbd",
11130                                         "ldap: invalid character (a-zA-Z0-9 allowed) in username:", username, i);
11131 -                               
11132 +
11133                                 return -1;
11134                         }
11135                 }
11136 -               
11137 -               
11138 -               
11139 +
11140 +
11141 +
11142                 /* build filter */
11143                 buffer_copy_string_buffer(p->ldap_filter, p->conf.ldap_filter_pre);
11144                 buffer_append_string_buffer(p->ldap_filter, username);
11145                 buffer_append_string_buffer(p->ldap_filter, p->conf.ldap_filter_post);
11146 -               
11147 -               
11148 +
11149 +
11150                 /* 2. */
11151                 if (p->conf.ldap == NULL ||
11152                     LDAP_SUCCESS != (ret = ldap_search_s(p->conf.ldap, p->conf.auth_ldap_basedn->ptr, LDAP_SCOPE_SUBTREE, p->ldap_filter->ptr, attrs, 0, &lm))) {
11153 @@ -590,71 +553,71 @@
11154                                 return -1;
11155                         if (LDAP_SUCCESS != (ret = ldap_search_s(p->conf.ldap, p->conf.auth_ldap_basedn->ptr, LDAP_SCOPE_SUBTREE, p->ldap_filter->ptr, attrs, 0, &lm))) {
11156  
11157 -                       log_error_write(srv, __FILE__, __LINE__, "sssb", 
11158 +                       log_error_write(srv, __FILE__, __LINE__, "sssb",
11159                                         "ldap:", ldap_err2string(ret), "filter:", p->ldap_filter);
11160 -                       
11161 +
11162                         return -1;
11163                         }
11164                 }
11165 -               
11166 +
11167                 if (NULL == (first = ldap_first_entry(p->conf.ldap, lm))) {
11168                         log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
11169 -                       
11170 +
11171                         ldap_msgfree(lm);
11172 -                       
11173 +
11174                         return -1;
11175                 }
11176 -               
11177 +
11178                 if (NULL == (dn = ldap_get_dn(p->conf.ldap, first))) {
11179                         log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
11180 -                       
11181 +
11182                         ldap_msgfree(lm);
11183 -                       
11184 +
11185                         return -1;
11186                 }
11187 -               
11188 +
11189                 ldap_msgfree(lm);
11190 -               
11191 -               
11192 +
11193 +
11194                 /* 3. */
11195                 if (NULL == (ldap = ldap_init(p->conf.auth_ldap_hostname->ptr, LDAP_PORT))) {
11196                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno));
11197                         return -1;
11198                 }
11199 -               
11200 +
11201                 ret = LDAP_VERSION3;
11202                 if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) {
11203                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
11204 -                       
11205 +
11206                         ldap_unbind_s(ldap);
11207 -                       
11208 +
11209                         return -1;
11210                 }
11211 -               
11212 +
11213                 if (p->conf.auth_ldap_starttls == 1) {
11214                         if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(ldap, NULL,  NULL))) {
11215                                 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
11216 -               
11217 +
11218                                 ldap_unbind_s(ldap);
11219 -                               
11220 +
11221                                 return -1;
11222                         }
11223                 }
11224  
11225 -               
11226 +
11227                 if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(ldap, dn, pw))) {
11228                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
11229 -                       
11230 +
11231                         ldap_unbind_s(ldap);
11232 -                       
11233 +
11234                         return -1;
11235                 }
11236 -               
11237 +
11238                 /* 5. */
11239                 ldap_unbind_s(ldap);
11240 -               
11241 +
11242                 /* everything worked, good, access granted */
11243 -               
11244 +
11245                 return 0;
11246  #endif
11247         }
11248 @@ -664,65 +627,65 @@
11249  int http_auth_basic_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) {
11250         buffer *username, *password;
11251         char *pw;
11252 -       
11253 +
11254         data_string *realm;
11255 -       
11256 +
11257         realm = (data_string *)array_get_element(req, "realm");
11258 -       
11259 +
11260         username = buffer_init();
11261         password = buffer_init();
11262 -       
11263 +
11264         base64_decode(username, realm_str);
11265 -       
11266 +
11267         /* r2 == user:password */
11268         if (NULL == (pw = strchr(username->ptr, ':'))) {
11269                 buffer_free(username);
11270 -               
11271 +
11272                 log_error_write(srv, __FILE__, __LINE__, "sb", ": is missing in", username);
11273 -               
11274 +
11275                 return 0;
11276         }
11277 -       
11278 +
11279         *pw++ = '\0';
11280 -       
11281 +
11282         username->used = pw - username->ptr;
11283 -       
11284 +
11285         /* copy password to r1 */
11286         if (http_auth_get_password(srv, p, username, realm->value, password)) {
11287                 buffer_free(username);
11288                 buffer_free(password);
11289 -               
11290 +
11291                 log_error_write(srv, __FILE__, __LINE__, "s", "get_password failed");
11292 -               
11293 +
11294                 return 0;
11295         }
11296 -       
11297 +
11298         /* password doesn't match */
11299         if (http_auth_basic_password_compare(srv, p, req, username, realm->value, password, pw)) {
11300                 log_error_write(srv, __FILE__, __LINE__, "sbb", "password doesn't match for", con->uri.path, username);
11301 -               
11302 +
11303                 buffer_free(username);
11304                 buffer_free(password);
11305 -               
11306 +
11307                 return 0;
11308         }
11309 -       
11310 +
11311         /* value is our allow-rules */
11312         if (http_auth_match_rules(srv, p, url->ptr, username->ptr, NULL, NULL)) {
11313                 buffer_free(username);
11314                 buffer_free(password);
11315 -               
11316 +
11317                 log_error_write(srv, __FILE__, __LINE__, "s", "rules didn't match");
11318 -               
11319 +
11320                 return 0;
11321         }
11322 -       
11323 +
11324         /* remember the username */
11325         buffer_copy_string_buffer(p->auth_user, username);
11326 -       
11327 +
11328         buffer_free(username);
11329         buffer_free(password);
11330 -       
11331 +
11332         return 1;
11333  }
11334  
11335 @@ -735,7 +698,7 @@
11336  int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) {
11337         char a1[256];
11338         char a2[256];
11339 -       
11340 +
11341         char *username;
11342         char *realm;
11343         char *nonce;
11344 @@ -745,18 +708,18 @@
11345         char *cnonce;
11346         char *nc;
11347         char *respons;
11348 -       
11349 +
11350         char *e, *c;
11351         const char *m = NULL;
11352         int i;
11353         buffer *password, *b, *username_buf, *realm_buf;
11354 -       
11355 +
11356         MD5_CTX Md5Ctx;
11357         HASH HA1;
11358         HASH HA2;
11359         HASH RespHash;
11360         HASHHEX HA2Hex;
11361 -       
11362 +
11363  
11364         /* init pointers */
11365  #define S(x) \
11366 @@ -771,11 +734,11 @@
11367                 { S("cnonce=") },
11368                 { S("nc=") },
11369                 { S("response=") },
11370 -               
11371 +
11372                 { NULL, 0, NULL }
11373         };
11374  #undef S
11375 -       
11376 +
11377         dkv[0].ptr = &username;
11378         dkv[1].ptr = &realm;
11379         dkv[2].ptr = &nonce;
11380 @@ -786,24 +749,24 @@
11381         dkv[7].ptr = &nc;
11382         dkv[8].ptr = &respons;
11383         dkv[9].ptr = NULL;
11384 -       
11385 +
11386         UNUSED(req);
11387 -       
11388 +
11389         for (i = 0; dkv[i].key; i++) {
11390                 *(dkv[i].ptr) = NULL;
11391         }
11392 -       
11393 -       
11394 +
11395 +
11396         if (p->conf.auth_backend != AUTH_BACKEND_HTDIGEST &&
11397             p->conf.auth_backend != AUTH_BACKEND_PLAIN) {
11398 -               log_error_write(srv, __FILE__, __LINE__, "s", 
11399 +               log_error_write(srv, __FILE__, __LINE__, "s",
11400                                 "digest: unsupported backend (only htdigest or plain)");
11401 -               
11402 +
11403                 return -1;
11404         }
11405 -       
11406 +
11407         b = buffer_init_string(realm_str);
11408 -       
11409 +
11410         /* parse credentials from client */
11411         for (c = b->ptr; *c; c++) {
11412                 /* skip whitespaces */
11413 @@ -812,18 +775,18 @@
11414  
11415                 for (i = 0; dkv[i].key; i++) {
11416                         if ((0 == strncmp(c, dkv[i].key, dkv[i].key_len))) {
11417 -                               if ((c[dkv[i].key_len] == '"') && 
11418 +                               if ((c[dkv[i].key_len] == '"') &&
11419                                     (NULL != (e = strchr(c + dkv[i].key_len + 1, '"')))) {
11420                                         /* value with "..." */
11421                                         *(dkv[i].ptr) = c + dkv[i].key_len + 1;
11422                                         c = e;
11423 -       
11424 +
11425                                         *e = '\0';
11426                                 } else if (NULL != (e = strchr(c + dkv[i].key_len, ','))) {
11427                                         /* value without "...", terminated by ',' */
11428                                         *(dkv[i].ptr) = c + dkv[i].key_len;
11429                                         c = e;
11430 -                                       
11431 +
11432                                         *e = '\0';
11433                                 } else {
11434                                         /* value without "...", terminated by EOL */
11435 @@ -833,7 +796,7 @@
11436                         }
11437                 }
11438         }
11439 -       
11440 +
11441         if (p->conf.auth_debug > 1) {
11442                 log_error_write(srv, __FILE__, __LINE__, "ss", "username", username);
11443                 log_error_write(srv, __FILE__, __LINE__, "ss", "realm", realm);
11444 @@ -845,22 +808,22 @@
11445                 log_error_write(srv, __FILE__, __LINE__, "ss", "nc", nc);
11446                 log_error_write(srv, __FILE__, __LINE__, "ss", "response", respons);
11447         }
11448 -       
11449 +
11450         /* check if everything is transmitted */
11451 -       if (!username || 
11452 +       if (!username ||
11453             !realm ||
11454             !nonce ||
11455             !uri ||
11456             (qop && (!nc || !cnonce)) ||
11457             !respons ) {
11458                 /* missing field */
11459 -               
11460 -               log_error_write(srv, __FILE__, __LINE__, "s", 
11461 +
11462 +               log_error_write(srv, __FILE__, __LINE__, "s",
11463                                 "digest: missing field");
11464                 return -1;
11465         }
11466  
11467 -       m = get_http_method_name(con->request.http_method);     
11468 +       m = get_http_method_name(con->request.http_method);
11469  
11470         /* password-string == HA1 */
11471         password = buffer_init();
11472 @@ -873,10 +836,10 @@
11473                 buffer_free(realm_buf);
11474                 return 0;
11475         }
11476 -       
11477 +
11478         buffer_free(username_buf);
11479         buffer_free(realm_buf);
11480 -       
11481 +
11482         if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
11483                 /* generate password from plain-text */
11484                 MD5_Init(&Md5Ctx);
11485 @@ -890,16 +853,16 @@
11486                 /* HA1 */
11487                 /* transform the 32-byte-hex-md5 to a 16-byte-md5 */
11488                 for (i = 0; i < HASHLEN; i++) {
11489 -                       HA1[i] = hex2int(password->ptr[i*2]) << 4; 
11490 -                       HA1[i] |= hex2int(password->ptr[i*2+1]); 
11491 +                       HA1[i] = hex2int(password->ptr[i*2]) << 4;
11492 +                       HA1[i] |= hex2int(password->ptr[i*2+1]);
11493                 }
11494         } else {
11495                 /* we already check that above */
11496                 SEGFAULT();
11497         }
11498 -       
11499 +
11500         buffer_free(password);
11501 -       
11502 +
11503         if (algorithm &&
11504             strcasecmp(algorithm, "md5-sess") == 0) {
11505                 MD5_Init(&Md5Ctx);
11506 @@ -910,9 +873,9 @@
11507                 MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce));
11508                 MD5_Final(HA1, &Md5Ctx);
11509         }
11510 -       
11511 +
11512         CvtHex(HA1, a1);
11513 -       
11514 +
11515         /* calculate H(A2) */
11516         MD5_Init(&Md5Ctx);
11517         MD5_Update(&Md5Ctx, (unsigned char *)m, strlen(m));
11518 @@ -924,7 +887,7 @@
11519         }
11520         MD5_Final(HA2, &Md5Ctx);
11521         CvtHex(HA2, HA2Hex);
11522 -       
11523 +
11524         /* calculate response */
11525         MD5_Init(&Md5Ctx);
11526         MD5_Update(&Md5Ctx, (unsigned char *)a1, HASHHEXLEN);
11527 @@ -942,39 +905,39 @@
11528         MD5_Update(&Md5Ctx, (unsigned char *)HA2Hex, HASHHEXLEN);
11529         MD5_Final(RespHash, &Md5Ctx);
11530         CvtHex(RespHash, a2);
11531 -       
11532 +
11533         if (0 != strcmp(a2, respons)) {
11534                 /* digest not ok */
11535 -               
11536 +
11537                 if (p->conf.auth_debug) {
11538 -                       log_error_write(srv, __FILE__, __LINE__, "sss", 
11539 +                       log_error_write(srv, __FILE__, __LINE__, "sss",
11540                                 "digest: digest mismatch", a2, respons);
11541                 }
11542 -               
11543 -               log_error_write(srv, __FILE__, __LINE__, "sss", 
11544 +
11545 +               log_error_write(srv, __FILE__, __LINE__, "sss",
11546                                 "digest: auth failed for", username, "wrong password");
11547 -               
11548 +
11549                 buffer_free(b);
11550                 return 0;
11551         }
11552 -       
11553 +
11554         /* value is our allow-rules */
11555         if (http_auth_match_rules(srv, p, url->ptr, username, NULL, NULL)) {
11556                 buffer_free(b);
11557 -               
11558 -               log_error_write(srv, __FILE__, __LINE__, "s", 
11559 +
11560 +               log_error_write(srv, __FILE__, __LINE__, "s",
11561                                 "digest: rules did match");
11562 -               
11563 +
11564                 return 0;
11565         }
11566 -       
11567 +
11568         /* remember the username */
11569         buffer_copy_string(p->auth_user, username);
11570 -       
11571 +
11572         buffer_free(b);
11573 -       
11574 +
11575         if (p->conf.auth_debug) {
11576 -               log_error_write(srv, __FILE__, __LINE__, "s", 
11577 +               log_error_write(srv, __FILE__, __LINE__, "s",
11578                                 "digest: auth ok");
11579         }
11580         return 1;
11581 @@ -985,23 +948,23 @@
11582         HASH h;
11583         MD5_CTX Md5Ctx;
11584         char hh[32];
11585 -       
11586 +
11587         UNUSED(p);
11588  
11589         /* generate shared-secret */
11590         MD5_Init(&Md5Ctx);
11591         MD5_Update(&Md5Ctx, (unsigned char *)fn->ptr, fn->used - 1);
11592         MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
11593 -       
11594 +
11595         /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
11596         ltostr(hh, srv->cur_ts);
11597         MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
11598         ltostr(hh, rand());
11599         MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
11600 -       
11601 +
11602         MD5_Final(h, &Md5Ctx);
11603 -       
11604 +
11605         CvtHex(h, out);
11606 -       
11607 +
11608         return 0;
11609  }
11610 --- ../lighttpd-1.4.11/src/http_auth.h  2005-08-14 17:12:31.000000000 +0300
11611 +++ lighttpd-1.4.12/src/http_auth.h     2006-07-16 00:26:04.000000000 +0300
11612 @@ -9,22 +9,26 @@
11613  # include <ldap.h>
11614  #endif
11615  
11616 -typedef enum { AUTH_BACKEND_UNSET, AUTH_BACKEND_PLAIN, 
11617 -               AUTH_BACKEND_LDAP, AUTH_BACKEND_HTPASSWD, 
11618 -               AUTH_BACKEND_HTDIGEST, AUTH_BACKEND_PAM } auth_backend_t;
11619 +typedef enum {
11620 +       AUTH_BACKEND_UNSET,
11621 +       AUTH_BACKEND_PLAIN,
11622 +       AUTH_BACKEND_LDAP,
11623 +       AUTH_BACKEND_HTPASSWD,
11624 +       AUTH_BACKEND_HTDIGEST
11625 +} auth_backend_t;
11626  
11627  typedef struct {
11628         /* auth */
11629         array  *auth_require;
11630 -       
11631 +
11632         buffer *auth_plain_groupfile;
11633         buffer *auth_plain_userfile;
11634 -       
11635 +
11636         buffer *auth_htdigest_userfile;
11637         buffer *auth_htpasswd_userfile;
11638 -       
11639 +
11640         buffer *auth_backend_conf;
11641 -       
11642 +
11643         buffer *auth_ldap_hostname;
11644         buffer *auth_ldap_basedn;
11645         buffer *auth_ldap_binddn;
11646 @@ -32,15 +36,15 @@
11647         buffer *auth_ldap_filter;
11648         buffer *auth_ldap_cafile;
11649         unsigned short auth_ldap_starttls;
11650 -       
11651 +
11652         unsigned short auth_debug;
11653 -       
11654 +
11655         /* generated */
11656         auth_backend_t auth_backend;
11657 -       
11658 +
11659  #ifdef USE_LDAP
11660         LDAP *ldap;
11661 -       
11662 +
11663         buffer *ldap_filter_pre;
11664         buffer *ldap_filter_post;
11665  #endif
11666 @@ -49,15 +53,15 @@
11667  typedef struct {
11668         PLUGIN_DATA;
11669         buffer *tmp_buf;
11670 -       
11671 +
11672         buffer *auth_user;
11673  
11674  #ifdef USE_LDAP
11675         buffer *ldap_filter;
11676  #endif
11677 -       
11678 +
11679         mod_auth_plugin_config **config_storage;
11680 -       
11681 +
11682         mod_auth_plugin_config conf; /* this is only used as long as no handler_ctx is setup */
11683  } mod_auth_plugin_data;
11684  
11685 --- ../lighttpd-1.4.11/src/http_auth_digest.h   2006-01-05 00:54:01.000000000 +0200
11686 +++ lighttpd-1.4.12/src/http_auth_digest.h      2006-07-16 00:26:04.000000000 +0300
11687 @@ -12,7 +12,7 @@
11688  #ifdef USE_OPENSSL
11689  #define IN const
11690  #else
11691 -#define IN 
11692 +#define IN
11693  #endif
11694  #define OUT
11695  
11696 --- ../lighttpd-1.4.11/src/http_chunk.c 2005-08-11 01:26:50.000000000 +0300
11697 +++ lighttpd-1.4.12/src/http_chunk.c    2006-07-16 00:26:04.000000000 +0300
11698 @@ -1,7 +1,7 @@
11699  /**
11700   * the HTTP chunk-API
11701 - * 
11702 - * 
11703 + *
11704 + *
11705   */
11706  
11707  #include <sys/types.h>
11708 @@ -9,7 +9,6 @@
11709  
11710  #include <stdlib.h>
11711  #include <fcntl.h>
11712 -#include <unistd.h>
11713  
11714  #include <stdio.h>
11715  #include <errno.h>
11716 @@ -23,19 +22,19 @@
11717  static int http_chunk_append_len(server *srv, connection *con, size_t len) {
11718         size_t i, olen = len, j;
11719         buffer *b;
11720 -       
11721 +
11722         b = srv->tmp_chunk_len;
11723 -       
11724 +
11725         if (len == 0) {
11726                 buffer_copy_string(b, "0");
11727         } else {
11728                 for (i = 0; i < 8 && len; i++) {
11729                         len >>= 4;
11730                 }
11731 -               
11732 +
11733                 /* i is the number of hex digits we have */
11734                 buffer_prepare_copy(b, i + 1);
11735 -               
11736 +
11737                 for (j = i-1, len = olen; j+1 > 0; j--) {
11738                         b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10);
11739                         len >>= 4;
11740 @@ -43,61 +42,61 @@
11741                 b->used = i;
11742                 b->ptr[b->used++] = '\0';
11743         }
11744 -               
11745 +
11746         buffer_append_string(b, "\r\n");
11747         chunkqueue_append_buffer(con->write_queue, b);
11748 -       
11749 +
11750         return 0;
11751  }
11752  
11753  
11754  int http_chunk_append_file(server *srv, connection *con, buffer *fn, off_t offset, off_t len) {
11755         chunkqueue *cq;
11756 -       
11757 +
11758         if (!con) return -1;
11759 -       
11760 +
11761         cq = con->write_queue;
11762 -       
11763 +
11764         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11765                 http_chunk_append_len(srv, con, len);
11766         }
11767 -       
11768 +
11769         chunkqueue_append_file(cq, fn, offset, len);
11770 -       
11771 +
11772         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && len > 0) {
11773                 chunkqueue_append_mem(cq, "\r\n", 2 + 1);
11774         }
11775 -       
11776 +
11777         return 0;
11778  }
11779  
11780  int http_chunk_append_buffer(server *srv, connection *con, buffer *mem) {
11781         chunkqueue *cq;
11782 -       
11783 +
11784         if (!con) return -1;
11785 -       
11786 +
11787         cq = con->write_queue;
11788 -       
11789 +
11790         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11791                 http_chunk_append_len(srv, con, mem->used - 1);
11792         }
11793 -       
11794 +
11795         chunkqueue_append_buffer(cq, mem);
11796 -       
11797 +
11798         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && mem->used > 0) {
11799                 chunkqueue_append_mem(cq, "\r\n", 2 + 1);
11800         }
11801 -       
11802 +
11803         return 0;
11804  }
11805  
11806  int http_chunk_append_mem(server *srv, connection *con, const char * mem, size_t len) {
11807         chunkqueue *cq;
11808 -       
11809 +
11810         if (!con) return -1;
11811 -       
11812 +
11813         cq = con->write_queue;
11814 -       
11815 +
11816         if (len == 0) {
11817                 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11818                         http_chunk_append_len(srv, con, 0);
11819 @@ -107,17 +106,17 @@
11820                 }
11821                 return 0;
11822         }
11823 -       
11824 +
11825         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11826                 http_chunk_append_len(srv, con, len - 1);
11827         }
11828 -       
11829 +
11830         chunkqueue_append_mem(cq, mem, len);
11831 -       
11832 +
11833         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11834                 chunkqueue_append_mem(cq, "\r\n", 2 + 1);
11835         }
11836 -       
11837 +
11838         return 0;
11839  }
11840  
11841 @@ -125,9 +124,9 @@
11842  off_t http_chunkqueue_length(server *srv, connection *con) {
11843         if (!con) {
11844                 log_error_write(srv, __FILE__, __LINE__, "s", "connection is NULL!!");
11845 -               
11846 +
11847                 return 0;
11848         }
11849 -       
11850 +
11851         return chunkqueue_length(con->write_queue);
11852  }
11853 --- ../lighttpd-1.4.11/src/http_resp.c  1970-01-01 03:00:00.000000000 +0300
11854 +++ lighttpd-1.4.12/src/http_resp.c     2006-07-18 13:03:40.000000000 +0300
11855 @@ -0,0 +1,277 @@
11856 +#include <string.h>
11857 +#include <stdlib.h>
11858 +#include <stdio.h>
11859 +#include <assert.h>
11860 +
11861 +#include "log.h"
11862 +#include "http_resp.h"
11863 +#include "http_resp_parser.h"
11864 +
11865 +/* declare prototypes for the parser */
11866 +void *http_resp_parserAlloc(void *(*mallocProc)(size_t));
11867 +void http_resp_parserFree(void *p,  void (*freeProc)(void*));
11868 +void http_resp_parserTrace(FILE *TraceFILE, char *zTracePrompt);
11869 +void http_resp_parser(void *, int, buffer *, http_resp_ctx_t *);
11870 +
11871 +typedef struct {
11872 +       chunkqueue *cq;
11873 +
11874 +       chunk *c; /* current chunk in the chunkqueue */
11875 +       size_t offset; /* current offset in current chunk */
11876 +
11877 +       chunk *lookup_c;
11878 +       size_t lookup_offset;
11879 +
11880 +       int is_key;
11881 +       int is_statusline;
11882 +} http_resp_tokenizer_t;
11883 +
11884 +http_resp *http_response_init(void) {
11885 +       http_resp *resp = calloc(1, sizeof(*resp));
11886 +
11887 +       resp->reason = buffer_init();
11888 +       resp->headers = array_init();
11889 +
11890 +       return resp;
11891 +}
11892 +
11893 +void http_response_reset(http_resp *resp) {
11894 +       if (!resp) return;
11895 +
11896 +       buffer_reset(resp->reason);
11897 +       array_reset(resp->headers);
11898 +
11899 +}
11900 +
11901 +void http_response_free(http_resp *resp) {
11902 +       if (!resp) return;
11903 +
11904 +       buffer_free(resp->reason);
11905 +       array_free(resp->headers);
11906 +
11907 +       free(resp);
11908 +}
11909 +
11910 +static int http_resp_get_next_char(http_resp_tokenizer_t *t, unsigned char *c) {
11911 +       if (t->offset == t->c->mem->used - 1) {
11912 +               /* end of chunk, open next chunk */
11913 +
11914 +               if (!t->c->next) return -1;
11915 +
11916 +               t->c = t->c->next;
11917 +               t->offset = 0;
11918 +       }
11919 +
11920 +       *c = t->c->mem->ptr[t->offset++];
11921 +
11922 +       t->lookup_offset = t->offset;
11923 +       t->lookup_c = t->c;
11924 +
11925 +#if 0
11926 +       fprintf(stderr, "%s.%d: get: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->offset - 1);
11927 +#endif
11928 +
11929 +       return 0;
11930 +}
11931 +
11932 +static int http_resp_lookup_next_char(http_resp_tokenizer_t *t, unsigned char *c) {
11933 +       if (t->lookup_offset == t->lookup_c->mem->used - 1) {
11934 +               /* end of chunk, open next chunk */
11935 +
11936 +               if (!t->lookup_c->next) return -1;
11937 +
11938 +               t->lookup_c = t->lookup_c->next;
11939 +               t->lookup_offset = 0;
11940 +       }
11941 +
11942 +       *c = t->lookup_c->mem->ptr[t->lookup_offset++];
11943 +#if 0
11944 +       fprintf(stderr, "%s.%d: lookup: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->lookup_offset - 1);
11945 +#endif
11946 +
11947 +       return 0;
11948 +}
11949 +
11950 +
11951 +static int http_resp_tokenizer(
11952 +       http_resp_tokenizer_t *t,
11953 +       int *token_id,
11954 +       buffer *token
11955 +) {
11956 +       unsigned char c;
11957 +       int tid = 0;
11958 +
11959 +       /* push the token to the parser */
11960 +
11961 +       while (tid == 0 && 0 == http_resp_get_next_char(t, &c)) {
11962 +               switch (c) {
11963 +               case ':':
11964 +                       tid = TK_COLON;
11965 +
11966 +                       t->is_key = 0;
11967 +
11968 +                       break;
11969 +               case ' ':
11970 +               case '\t':
11971 +                       /* ignore WS */
11972 +
11973 +                       break;
11974 +               case '\r':
11975 +                       if (0 != http_resp_lookup_next_char(t, &c)) return -1;
11976 +
11977 +                       if (c == '\n') {
11978 +                               tid = TK_CRLF;
11979 +
11980 +                               t->c = t->lookup_c;
11981 +                               t->offset = t->lookup_offset;
11982 +
11983 +                               t->is_statusline = 0;
11984 +                               t->is_key = 1;
11985 +                       } else {
11986 +                               fprintf(stderr, "%s.%d: CR with out LF\r\n", __FILE__, __LINE__);
11987 +                               return -1;
11988 +                       }
11989 +                       break;
11990 +               case '\n':
11991 +                       tid = TK_CRLF;
11992 +
11993 +                       t->is_statusline = 0;
11994 +                       t->is_key = 1;
11995 +
11996 +                       break;
11997 +               default:
11998 +                       while (c >= 32 && c != 127 && c != 255) {
11999 +                               if (t->is_statusline) {
12000 +                                       if (c == ':') { t->is_statusline = 0; break; } /* this is not a status line by a real header */
12001 +                                       if (c == 32) break; /* the space is a splitter in the statusline */
12002 +                               } else {
12003 +                                       if (t->is_key) {
12004 +                                               if (c == ':') break; /* the : is the splitter between key and value */
12005 +                                       }
12006 +                               }
12007 +                               if (0 != http_resp_lookup_next_char(t, &c)) return -1;
12008 +                       }
12009 +
12010 +                       if (t->c == t->lookup_c &&
12011 +                               t->offset == t->lookup_offset + 1) {
12012 +
12013 +                               fprintf(stderr, "%s.%d: invalid char in string\n", __FILE__, __LINE__);
12014 +                               return -1;
12015 +                       }
12016 +
12017 +                       tid = TK_STRING;
12018 +
12019 +                       /* the lookup points to the first invalid char */
12020 +                       t->lookup_offset--;
12021 +
12022 +                       /* no overlapping string */
12023 +                       if (t->c == t->lookup_c) {
12024 +                               buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->lookup_offset - t->offset + 1);
12025 +                       } else {
12026 +                               /* first chunk */
12027 +                               buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->c->mem->used - t->offset);
12028 +
12029 +                               /* chunks in the middle */
12030 +                               for (t->c = t->c->next; t->c != t->lookup_c; t->c = t->c->next) {
12031 +                                       buffer_append_string_buffer(token, t->c->mem);
12032 +                                       t->offset = t->c->mem->used - 1;
12033 +                               }
12034 +
12035 +                               /* last chunk */
12036 +                               buffer_append_string_len(token, t->c->mem->ptr, t->lookup_offset);
12037 +                       }
12038 +
12039 +                       t->offset = t->lookup_offset;
12040 +
12041 +                       break;
12042 +               }
12043 +       }
12044 +
12045 +       if (tid) {
12046 +               *token_id = tid;
12047 +
12048 +               return 1;
12049 +       }
12050 +
12051 +       return -1;
12052 +}
12053 +
12054 +parse_status_t http_response_parse_cq(chunkqueue *cq, http_resp *resp) {
12055 +       http_resp_tokenizer_t t;
12056 +       void *pParser = NULL;
12057 +       int token_id = 0;
12058 +       buffer *token = NULL;
12059 +       http_resp_ctx_t context;
12060 +       parse_status_t ret = PARSE_UNSET;
12061 +       int last_token_id = 0;
12062 +
12063 +       t.cq = cq;
12064 +       t.c = cq->first;
12065 +       t.offset = t.c->offset;
12066 +       t.is_key = 0;
12067 +       t.is_statusline = 1;
12068 +
12069 +       context.ok = 1;
12070 +       context.errmsg = buffer_init();
12071 +       context.resp = resp;
12072 +
12073 +       pParser = http_resp_parserAlloc( malloc );
12074 +       token = buffer_init();
12075 +#if 0
12076 +       http_resp_parserTrace(stderr, "http-response: "); 
12077 +#endif
12078 +
12079 +       while((1 == http_resp_tokenizer(&t, &token_id, token)) && context.ok) {
12080 +               http_resp_parser(pParser, token_id, token, &context);
12081 +
12082 +               token = buffer_init();
12083 +
12084 +               /* CRLF CRLF ... the header end sequence */
12085 +               if (last_token_id == TK_CRLF &&
12086 +                   token_id == TK_CRLF) break;
12087 +
12088 +               last_token_id = token_id;
12089 +       }
12090 +
12091 +       /* oops, the parser failed */
12092 +       if (context.ok == 0) {
12093 +               ret = PARSE_ERROR;
12094 +
12095 +               if (!buffer_is_empty(context.errmsg)) {
12096 +                       TRACE("parsing failed: %s", BUF_STR(context.errmsg));
12097 +               } else {
12098 +                       TRACE("%s", "parsing failed ...");
12099 +               }
12100 +       }
12101 +
12102 +       http_resp_parser(pParser, 0, token, &context);
12103 +       http_resp_parserFree(pParser, free);
12104 +
12105 +       if (context.ok == 0) {
12106 +               /* we are missing the some tokens */
12107 +
12108 +               if (!buffer_is_empty(context.errmsg)) {
12109 +                       TRACE("parsing failed: %s", BUF_STR(context.errmsg));
12110 +               }
12111 +
12112 +               if (ret == PARSE_UNSET) {
12113 +                       ret = buffer_is_empty(context.errmsg) ? PARSE_NEED_MORE : PARSE_ERROR;
12114 +               }
12115 +       } else {
12116 +               chunk *c;
12117 +
12118 +               for (c = cq->first; c != t.c; c = c->next) {
12119 +                       c->offset = c->mem->used - 1;
12120 +               }
12121 +
12122 +               c->offset = t.offset;
12123 +
12124 +               ret = PARSE_SUCCESS;
12125 +       }
12126 +
12127 +       buffer_free(token);
12128 +       buffer_free(context.errmsg);
12129 +
12130 +       return ret;
12131 +}
12132 +
12133 --- ../lighttpd-1.4.11/src/http_resp.h  1970-01-01 03:00:00.000000000 +0300
12134 +++ lighttpd-1.4.12/src/http_resp.h     2006-07-16 00:26:04.000000000 +0300
12135 @@ -0,0 +1,34 @@
12136 +#ifndef _HTTP_RESP_H_
12137 +#define _HTTP_RESP_H_
12138 +
12139 +#include "array.h"
12140 +#include "chunk.h"
12141 +
12142 +typedef enum {
12143 +    PARSE_UNSET,
12144 +    PARSE_SUCCESS,
12145 +    PARSE_ERROR,
12146 +    PARSE_NEED_MORE
12147 +} parse_status_t;
12148 +
12149 +typedef struct {
12150 +    int protocol;   /* http/1.0, http/1.1 */
12151 +    int status;     /* e.g. 200 */
12152 +    buffer *reason; /* e.g. Ok */
12153 +    array *headers;
12154 +} http_resp;
12155 +
12156 +typedef struct {
12157 +       int     ok;
12158 +    buffer *errmsg;
12159 +
12160 +    http_resp *resp;
12161 +} http_resp_ctx_t;
12162 +
12163 +http_resp *http_response_init(void);
12164 +void http_response_free(http_resp *resp);
12165 +void http_response_reset(http_resp *resp);
12166 +
12167 +parse_status_t http_response_parse_cq(chunkqueue *cq, http_resp *http_response);
12168 +
12169 +#endif
12170 --- ../lighttpd-1.4.11/src/http_resp_parser.c   1970-01-01 03:00:00.000000000 +0300
12171 +++ lighttpd-1.4.12/src/http_resp_parser.c      2006-07-18 13:03:52.000000000 +0300
12172 @@ -0,0 +1,901 @@
12173 +/* Driver template for the LEMON parser generator.
12174 +** The author disclaims copyright to this source code.
12175 +*/
12176 +/* First off, code is include which follows the "include" declaration
12177 +** in the input file. */
12178 +#include <stdio.h>
12179 +#line 6 "./http_resp_parser.y"
12180 +
12181 +#include <assert.h>
12182 +#include <string.h>
12183 +#include "http_resp.h"
12184 +#include "keyvalue.h"
12185 +#include "array.h"
12186 +#include "log.h"
12187 +
12188 +#line 17 "http_resp_parser.c"
12189 +/* Next is all token values, in a form suitable for use by makeheaders.
12190 +** This section will be null unless lemon is run with the -m switch.
12191 +*/
12192 +/*
12193 +** These constants (all generated automatically by the parser generator)
12194 +** specify the various kinds of tokens (terminals) that the parser
12195 +** understands.
12196 +**
12197 +** Each symbol here is a terminal symbol in the grammar.
12198 +*/
12199 +/* Make sure the INTERFACE macro is defined.
12200 +*/
12201 +#ifndef INTERFACE
12202 +# define INTERFACE 1
12203 +#endif
12204 +/* The next thing included is series of defines which control
12205 +** various aspects of the generated parser.
12206 +**    YYCODETYPE         is the data type used for storing terminal
12207 +**                       and nonterminal numbers.  "unsigned char" is
12208 +**                       used if there are fewer than 250 terminals
12209 +**                       and nonterminals.  "int" is used otherwise.
12210 +**    YYNOCODE           is a number of type YYCODETYPE which corresponds
12211 +**                       to no legal terminal or nonterminal number.  This
12212 +**                       number is used to fill in empty slots of the hash
12213 +**                       table.
12214 +**    YYFALLBACK         If defined, this indicates that one or more tokens
12215 +**                       have fall-back values which should be used if the
12216 +**                       original value of the token will not parse.
12217 +**    YYACTIONTYPE       is the data type used for storing terminal
12218 +**                       and nonterminal numbers.  "unsigned char" is
12219 +**                       used if there are fewer than 250 rules and
12220 +**                       states combined.  "int" is used otherwise.
12221 +**    http_resp_parserTOKENTYPE     is the data type used for minor tokens given
12222 +**                       directly to the parser from the tokenizer.
12223 +**    YYMINORTYPE        is the data type used for all minor tokens.
12224 +**                       This is typically a union of many types, one of
12225 +**                       which is http_resp_parserTOKENTYPE.  The entry in the union
12226 +**                       for base tokens is called "yy0".
12227 +**    YYSTACKDEPTH       is the maximum depth of the parser's stack.
12228 +**    http_resp_parserARG_SDECL     A static variable declaration for the %extra_argument
12229 +**    http_resp_parserARG_PDECL     A parameter declaration for the %extra_argument
12230 +**    http_resp_parserARG_STORE     Code to store %extra_argument into yypParser
12231 +**    http_resp_parserARG_FETCH     Code to extract %extra_argument from yypParser
12232 +**    YYNSTATE           the combined number of states.
12233 +**    YYNRULE            the number of rules in the grammar
12234 +**    YYERRORSYMBOL      is the code number of the error symbol.  If not
12235 +**                       defined, then do no error processing.
12236 +*/
12237 +/* \ 1 */
12238 +#define YYCODETYPE unsigned char
12239 +#define YYNOCODE 12
12240 +#define YYACTIONTYPE unsigned char
12241 +#define http_resp_parserTOKENTYPE buffer *
12242 +typedef union {
12243 +  http_resp_parserTOKENTYPE yy0;
12244 +  http_resp * yy2;
12245 +  data_string * yy9;
12246 +  array * yy12;
12247 +  int yy20;
12248 +  int yy23;
12249 +} YYMINORTYPE;
12250 +#define YYSTACKDEPTH 100
12251 +#define http_resp_parserARG_SDECL http_resp_ctx_t *ctx;
12252 +#define http_resp_parserARG_PDECL ,http_resp_ctx_t *ctx
12253 +#define http_resp_parserARG_FETCH http_resp_ctx_t *ctx = yypParser->ctx
12254 +#define http_resp_parserARG_STORE yypParser->ctx = ctx
12255 +#define YYNSTATE 19
12256 +#define YYNRULE 9
12257 +#define YYERRORSYMBOL 4
12258 +#define YYERRSYMDT yy23
12259 +#define YY_NO_ACTION      (YYNSTATE+YYNRULE+2)
12260 +#define YY_ACCEPT_ACTION  (YYNSTATE+YYNRULE+1)
12261 +#define YY_ERROR_ACTION   (YYNSTATE+YYNRULE)
12262 +
12263 +/* Next are that tables used to determine what action to take based on the
12264 +** current state and lookahead token.  These tables are used to implement
12265 +** functions that take a state number and lookahead value and return an
12266 +** action integer.
12267 +**
12268 +** Suppose the action integer is N.  Then the action is determined as
12269 +** follows
12270 +**
12271 +**   0 <= N < YYNSTATE                  Shift N.  That is, push the lookahead
12272 +**                                      token onto the stack and goto state N.
12273 +**
12274 +**   YYNSTATE <= N < YYNSTATE+YYNRULE   Reduce by rule N-YYNSTATE.
12275 +**
12276 +**   N == YYNSTATE+YYNRULE              A syntax error has occurred.
12277 +**
12278 +**   N == YYNSTATE+YYNRULE+1            The parser accepts its input.
12279 +**
12280 +**   N == YYNSTATE+YYNRULE+2            No such action.  Denotes unused
12281 +**                                      slots in the yy_action[] table.
12282 +**
12283 +** The action table is constructed as a single large table named yy_action[].
12284 +** Given state S and lookahead X, the action is computed as
12285 +**
12286 +**      yy_action[ yy_shift_ofst[S] + X ]
12287 +**
12288 +** If the index value yy_shift_ofst[S]+X is out of range or if the value
12289 +** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
12290 +** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
12291 +** and that yy_default[S] should be used instead.
12292 +**
12293 +** The formula above is for computing the action when the lookahead is
12294 +** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
12295 +** a reduce action) then the yy_reduce_ofst[] array is used in place of
12296 +** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
12297 +** YY_SHIFT_USE_DFLT.
12298 +**
12299 +** The following are the tables generated in this section:
12300 +**
12301 +**  yy_action[]        A single table containing all actions.
12302 +**  yy_lookahead[]     A table containing the lookahead for each entry in
12303 +**                     yy_action.  Used to detect hash collisions.
12304 +**  yy_shift_ofst[]    For each state, the offset into yy_action for
12305 +**                     shifting terminals.
12306 +**  yy_reduce_ofst[]   For each state, the offset into yy_action for
12307 +**                     shifting non-terminals after a reduce.
12308 +**  yy_default[]       Default action for each state.
12309 +*/
12310 +static YYACTIONTYPE yy_action[] = {
12311 + /*     0 */     8,   29,   18,    1,   14,    2,    4,   11,   15,   12,
12312 + /*    10 */    14,   13,    4,   21,    5,   19,    3,    5,    6,    7,
12313 + /*    20 */     9,   17,   16,    4,   20,   22,   22,   10,
12314 +};
12315 +static YYCODETYPE yy_lookahead[] = {
12316 + /*     0 */     5,    6,    2,    8,    9,    1,    2,    1,    2,    8,
12317 + /*    10 */     9,    1,    2,    2,    3,    0,    9,    3,    2,    1,
12318 + /*    20 */     7,    2,    2,    2,    0,    2,   11,   10,
12319 +};
12320 +#define YY_SHIFT_USE_DFLT (-1)
12321 +static signed char yy_shift_ofst[] = {
12322 + /*     0 */     0,    4,   15,   -1,   14,   16,   18,   -1,   19,   20,
12323 + /*    10 */     6,   21,   10,   24,   -1,   -1,   -1,   23,   11,
12324 +};
12325 +#define YY_REDUCE_USE_DFLT (-6)
12326 +static signed char yy_reduce_ofst[] = {
12327 + /*     0 */    -5,    7,   -6,   -6,   -6,   -6,   -6,   -6,   13,   17,
12328 + /*    10 */    -6,    1,    7,   -6,   -6,   -6,   -6,   -6,   -6,
12329 +};
12330 +static YYACTIONTYPE yy_default[] = {
12331 + /*     0 */    28,   28,   28,   25,   28,   28,   28,   27,   28,   28,
12332 + /*    10 */    28,   28,   28,   28,   26,   24,   23,   28,   28,
12333 +};
12334 +#define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
12335 +
12336 +/* The next table maps tokens into fallback tokens.  If a construct
12337 +** like the following:
12338 +**
12339 +**      %fallback ID X Y Z.
12340 +**
12341 +** appears in the grammer, then ID becomes a fallback token for X, Y,
12342 +** and Z.  Whenever one of the tokens X, Y, or Z is input to the parser
12343 +** but it does not parse, the type of the token is changed to ID and
12344 +** the parse is retried before an error is thrown.
12345 +*/
12346 +#ifdef YYFALLBACK
12347 +static const YYCODETYPE yyFallback[] = {
12348 +};
12349 +#endif /* YYFALLBACK */
12350 +
12351 +/* The following structure represents a single element of the
12352 +** parser's stack.  Information stored includes:
12353 +**
12354 +**   +  The state number for the parser at this level of the stack.
12355 +**
12356 +**   +  The value of the token stored at this level of the stack.
12357 +**      (In other words, the "major" token.)
12358 +**
12359 +**   +  The semantic value stored at this level of the stack.  This is
12360 +**      the information used by the action routines in the grammar.
12361 +**      It is sometimes called the "minor" token.
12362 +*/
12363 +struct yyStackEntry {
12364 +  int stateno;       /* The state-number */
12365 +  int major;         /* The major token value.  This is the code
12366 +                     ** number for the token at this stack level */
12367 +  YYMINORTYPE minor; /* The user-supplied minor token value.  This
12368 +                     ** is the value of the token  */
12369 +};
12370 +typedef struct yyStackEntry yyStackEntry;
12371 +
12372 +/* The state of the parser is completely contained in an instance of
12373 +** the following structure */
12374 +struct yyParser {
12375 +  int yyidx;                    /* Index of top element in stack */
12376 +  int yyerrcnt;                 /* Shifts left before out of the error */
12377 +  http_resp_parserARG_SDECL                /* A place to hold %extra_argument */
12378 +  yyStackEntry yystack[YYSTACKDEPTH];  /* The parser's stack */
12379 +};
12380 +typedef struct yyParser yyParser;
12381 +
12382 +#ifndef NDEBUG
12383 +#include <stdio.h>
12384 +static FILE *yyTraceFILE = 0;
12385 +static char *yyTracePrompt = 0;
12386 +#endif /* NDEBUG */
12387 +
12388 +#ifndef NDEBUG
12389 +/*
12390 +** Turn parser tracing on by giving a stream to which to write the trace
12391 +** and a prompt to preface each trace message.  Tracing is turned off
12392 +** by making either argument NULL
12393 +**
12394 +** Inputs:
12395 +** <ul>
12396 +** <li> A FILE* to which trace output should be written.
12397 +**      If NULL, then tracing is turned off.
12398 +** <li> A prefix string written at the beginning of every
12399 +**      line of trace output.  If NULL, then tracing is
12400 +**      turned off.
12401 +** </ul>
12402 +**
12403 +** Outputs:
12404 +** None.
12405 +*/
12406 +void http_resp_parserTrace(FILE *TraceFILE, char *zTracePrompt){
12407 +  yyTraceFILE = TraceFILE;
12408 +  yyTracePrompt = zTracePrompt;
12409 +  if( yyTraceFILE==0 ) yyTracePrompt = 0;
12410 +  else if( yyTracePrompt==0 ) yyTraceFILE = 0;
12411 +}
12412 +#endif /* NDEBUG */
12413 +
12414 +#ifndef NDEBUG
12415 +/* For tracing shifts, the names of all terminals and nonterminals
12416 +** are required.  The following table supplies these names */
12417 +static const char *yyTokenName[] = {
12418 +  "$",             "CRLF",          "STRING",        "COLON",       
12419 +  "error",         "protocol",      "response_hdr",  "number",      
12420 +  "headers",       "header",        "reason",      
12421 +};
12422 +#endif /* NDEBUG */
12423 +
12424 +#ifndef NDEBUG
12425 +/* For tracing reduce actions, the names of all rules are required.
12426 +*/
12427 +static const char *yyRuleName[] = {
12428 + /*   0 */ "response_hdr ::= headers CRLF",
12429 + /*   1 */ "response_hdr ::= protocol number reason CRLF headers CRLF",
12430 + /*   2 */ "protocol ::= STRING",
12431 + /*   3 */ "number ::= STRING",
12432 + /*   4 */ "reason ::= STRING",
12433 + /*   5 */ "reason ::= reason STRING",
12434 + /*   6 */ "headers ::= headers header",
12435 + /*   7 */ "headers ::= header",
12436 + /*   8 */ "header ::= STRING COLON STRING CRLF",
12437 +};
12438 +#endif /* NDEBUG */
12439 +
12440 +/*
12441 +** This function returns the symbolic name associated with a token
12442 +** value.
12443 +*/
12444 +const char *http_resp_parserTokenName(int tokenType){
12445 +#ifndef NDEBUG
12446 +  if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
12447 +    return yyTokenName[tokenType];
12448 +  }else{
12449 +    return "Unknown";
12450 +  }
12451 +#else
12452 +  return "";
12453 +#endif
12454 +}
12455 +
12456 +/*
12457 +** This function allocates a new parser.
12458 +** The only argument is a pointer to a function which works like
12459 +** malloc.
12460 +**
12461 +** Inputs:
12462 +** A pointer to the function used to allocate memory.
12463 +**
12464 +** Outputs:
12465 +** A pointer to a parser.  This pointer is used in subsequent calls
12466 +** to http_resp_parser and http_resp_parserFree.
12467 +*/
12468 +void *http_resp_parserAlloc(void *(*mallocProc)(size_t)){
12469 +  yyParser *pParser;
12470 +  pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
12471 +  if( pParser ){
12472 +    pParser->yyidx = -1;
12473 +  }
12474 +  return pParser;
12475 +}
12476 +
12477 +/* The following function deletes the value associated with a
12478 +** symbol.  The symbol can be either a terminal or nonterminal.
12479 +** "yymajor" is the symbol code, and "yypminor" is a pointer to
12480 +** the value.
12481 +*/
12482 +static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
12483 +  switch( yymajor ){
12484 +    /* Here is inserted the actions which take place when a
12485 +    ** terminal or non-terminal is destroyed.  This can happen
12486 +    ** when the symbol is popped from the stack during a
12487 +    ** reduce or during error processing or when a parser is
12488 +    ** being destroyed before it is finished parsing.
12489 +    **
12490 +    ** Note: during a reduce, the only symbols destroyed are those
12491 +    ** which appear on the RHS of the rule, but which are not used
12492 +    ** inside the C code.
12493 +    */
12494 +    case 1:
12495 +    case 2:
12496 +    case 3:
12497 +#line 25 "./http_resp_parser.y"
12498 +{ buffer_free((yypminor->yy0)); }
12499 +#line 327 "http_resp_parser.c"
12500 +      break;
12501 +    case 10:
12502 +#line 24 "./http_resp_parser.y"
12503 +{ buffer_free((yypminor->yy0)); }
12504 +#line 332 "http_resp_parser.c"
12505 +      break;
12506 +    default:  break;   /* If no destructor action specified: do nothing */
12507 +  }
12508 +}
12509 +
12510 +/*
12511 +** Pop the parser's stack once.
12512 +**
12513 +** If there is a destructor routine associated with the token which
12514 +** is popped from the stack, then call it.
12515 +**
12516 +** Return the major token number for the symbol popped.
12517 +*/
12518 +static int yy_pop_parser_stack(yyParser *pParser){
12519 +  YYCODETYPE yymajor;
12520 +  yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
12521 +
12522 +  if( pParser->yyidx<0 ) return 0;
12523 +#ifndef NDEBUG
12524 +  if( yyTraceFILE && pParser->yyidx>=0 ){
12525 +    fprintf(yyTraceFILE,"%sPopping %s\n",
12526 +      yyTracePrompt,
12527 +      yyTokenName[yytos->major]);
12528 +  }
12529 +#endif
12530 +  yymajor = yytos->major;
12531 +  yy_destructor( yymajor, &yytos->minor);
12532 +  pParser->yyidx--;
12533 +  return yymajor;
12534 +}
12535 +
12536 +/*
12537 +** Deallocate and destroy a parser.  Destructors are all called for
12538 +** all stack elements before shutting the parser down.
12539 +**
12540 +** Inputs:
12541 +** <ul>
12542 +** <li>  A pointer to the parser.  This should be a pointer
12543 +**       obtained from http_resp_parserAlloc.
12544 +** <li>  A pointer to a function used to reclaim memory obtained
12545 +**       from malloc.
12546 +** </ul>
12547 +*/
12548 +void http_resp_parserFree(
12549 +  void *p,                    /* The parser to be deleted */
12550 +  void (*freeProc)(void*)     /* Function used to reclaim memory */
12551 +){
12552 +  yyParser *pParser = (yyParser*)p;
12553 +  if( pParser==0 ) return;
12554 +  while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
12555 +  (*freeProc)((void*)pParser);
12556 +}
12557 +
12558 +/*
12559 +** Find the appropriate action for a parser given the terminal
12560 +** look-ahead token iLookAhead.
12561 +**
12562 +** If the look-ahead token is YYNOCODE, then check to see if the action is
12563 +** independent of the look-ahead.  If it is, return the action, otherwise
12564 +** return YY_NO_ACTION.
12565 +*/
12566 +static int yy_find_shift_action(
12567 +  yyParser *pParser,        /* The parser */
12568 +  int iLookAhead            /* The look-ahead token */
12569 +){
12570 +  int i;
12571 +  int stateno = pParser->yystack[pParser->yyidx].stateno;
12572 +
12573 +  /* if( pParser->yyidx<0 ) return YY_NO_ACTION;  */
12574 +  i = yy_shift_ofst[stateno];
12575 +  if( i==YY_SHIFT_USE_DFLT ){
12576 +    return yy_default[stateno];
12577 +  }
12578 +  if( iLookAhead==YYNOCODE ){
12579 +    return YY_NO_ACTION;
12580 +  }
12581 +  i += iLookAhead;
12582 +  if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
12583 +#ifdef YYFALLBACK
12584 +    int iFallback;            /* Fallback token */
12585 +    if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
12586 +           && (iFallback = yyFallback[iLookAhead])!=0 ){
12587 +#ifndef NDEBUG
12588 +      if( yyTraceFILE ){
12589 +        fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
12590 +           yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
12591 +      }
12592 +#endif
12593 +      return yy_find_shift_action(pParser, iFallback);
12594 +    }
12595 +#endif
12596 +    return yy_default[stateno];
12597 +  }else{
12598 +    return yy_action[i];
12599 +  }
12600 +}
12601 +
12602 +/*
12603 +** Find the appropriate action for a parser given the non-terminal
12604 +** look-ahead token iLookAhead.
12605 +**
12606 +** If the look-ahead token is YYNOCODE, then check to see if the action is
12607 +** independent of the look-ahead.  If it is, return the action, otherwise
12608 +** return YY_NO_ACTION.
12609 +*/
12610 +static int yy_find_reduce_action(
12611 +  yyParser *pParser,        /* The parser */
12612 +  int iLookAhead            /* The look-ahead token */
12613 +){
12614 +  int i;
12615 +  int stateno = pParser->yystack[pParser->yyidx].stateno;
12616 +
12617 +  i = yy_reduce_ofst[stateno];
12618 +  if( i==YY_REDUCE_USE_DFLT ){
12619 +    return yy_default[stateno];
12620 +  }
12621 +  if( iLookAhead==YYNOCODE ){
12622 +    return YY_NO_ACTION;
12623 +  }
12624 +  i += iLookAhead;
12625 +  if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
12626 +    return yy_default[stateno];
12627 +  }else{
12628 +    return yy_action[i];
12629 +  }
12630 +}
12631 +
12632 +/*
12633 +** Perform a shift action.
12634 +*/
12635 +static void yy_shift(
12636 +  yyParser *yypParser,          /* The parser to be shifted */
12637 +  int yyNewState,               /* The new state to shift in */
12638 +  int yyMajor,                  /* The major token to shift in */
12639 +  YYMINORTYPE *yypMinor         /* Pointer ot the minor token to shift in */
12640 +){
12641 +  yyStackEntry *yytos;
12642 +  yypParser->yyidx++;
12643 +  if( yypParser->yyidx>=YYSTACKDEPTH ){
12644 +     http_resp_parserARG_FETCH;
12645 +     yypParser->yyidx--;
12646 +#ifndef NDEBUG
12647 +     if( yyTraceFILE ){
12648 +       fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
12649 +     }
12650 +#endif
12651 +     while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
12652 +     /* Here code is inserted which will execute if the parser
12653 +     ** stack every overflows */
12654 +     http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument var */
12655 +     return;
12656 +  }
12657 +  yytos = &yypParser->yystack[yypParser->yyidx];
12658 +  yytos->stateno = yyNewState;
12659 +  yytos->major = yyMajor;
12660 +  yytos->minor = *yypMinor;
12661 +#ifndef NDEBUG
12662 +  if( yyTraceFILE && yypParser->yyidx>0 ){
12663 +    int i;
12664 +    fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
12665 +    fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
12666 +    for(i=1; i<=yypParser->yyidx; i++)
12667 +      fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
12668 +    fprintf(yyTraceFILE,"\n");
12669 +  }
12670 +#endif
12671 +}
12672 +
12673 +/* The following table contains information about every rule that
12674 +** is used during the reduce.
12675 +*/
12676 +static struct {
12677 +  YYCODETYPE lhs;         /* Symbol on the left-hand side of the rule */
12678 +  unsigned char nrhs;     /* Number of right-hand side symbols in the rule */
12679 +} yyRuleInfo[] = {
12680 +  { 6, 2 },
12681 +  { 6, 6 },
12682 +  { 5, 1 },
12683 +  { 7, 1 },
12684 +  { 10, 1 },
12685 +  { 10, 2 },
12686 +  { 8, 2 },
12687 +  { 8, 1 },
12688 +  { 9, 4 },
12689 +};
12690 +
12691 +static void yy_accept(yyParser*);  /* Forward Declaration */
12692 +
12693 +/*
12694 +** Perform a reduce action and the shift that must immediately
12695 +** follow the reduce.
12696 +*/
12697 +static void yy_reduce(
12698 +  yyParser *yypParser,         /* The parser */
12699 +  int yyruleno                 /* Number of the rule by which to reduce */
12700 +){
12701 +  int yygoto;                     /* The next state */
12702 +  int yyact;                      /* The next action */
12703 +  YYMINORTYPE yygotominor;        /* The LHS of the rule reduced */
12704 +  yyStackEntry *yymsp;            /* The top of the parser's stack */
12705 +  int yysize;                     /* Amount to pop the stack */
12706 +  http_resp_parserARG_FETCH;
12707 +  yymsp = &yypParser->yystack[yypParser->yyidx];
12708 +#ifndef NDEBUG
12709 +  if( yyTraceFILE && yyruleno>=0
12710 +        && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
12711 +    fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
12712 +      yyRuleName[yyruleno]);
12713 +  }
12714 +#endif /* NDEBUG */
12715 +
12716 +  switch( yyruleno ){
12717 +  /* Beginning here are the reduction cases.  A typical example
12718 +  ** follows:
12719 +  **   case 0:
12720 +  **  #line <lineno> <grammarfile>
12721 +  **     { ... }           // User supplied code
12722 +  **  #line <lineno> <thisfile>
12723 +  **     break;
12724 +  */
12725 +      case 0:
12726 +#line 28 "./http_resp_parser.y"
12727 +{
12728 +    http_resp *resp = ctx->resp;
12729 +    data_string *ds;
12730
12731 +    resp->protocol = HTTP_VERSION_UNSET;
12732 +
12733 +    buffer_copy_string(resp->reason, ""); /* no reason */
12734 +    array_free(resp->headers);
12735 +    resp->headers = yymsp[-1].minor.yy12;
12736 +
12737 +    if (NULL == (ds = (data_string *)array_get_element(yymsp[-1].minor.yy12, "Status"))) { 
12738 +        resp->status = 0;
12739 +    } else {
12740 +        char *err;
12741 +        resp->status = strtol(ds->value->ptr, &err, 10);
12742 +   
12743 +        if (*err != '\0' && *err != ' ') {
12744 +            buffer_copy_string(ctx->errmsg, "expected a number: ");
12745 +            buffer_append_string_buffer(ctx->errmsg, ds->value);
12746 +            buffer_append_string(ctx->errmsg, err);
12747 +        
12748 +            ctx->ok = 0;
12749 +        }
12750 +    }
12751 +
12752 +    yymsp[-1].minor.yy12 = NULL;
12753 +}
12754 +#line 582 "http_resp_parser.c"
12755 +  yy_destructor(1,&yymsp[0].minor);
12756 +        break;
12757 +      case 1:
12758 +#line 56 "./http_resp_parser.y"
12759 +{
12760 +    http_resp *resp = ctx->resp;
12761 +    
12762 +    resp->status = yymsp[-4].minor.yy20;
12763 +    resp->protocol = yymsp[-5].minor.yy20;
12764 +    buffer_copy_string_buffer(resp->reason, yymsp[-3].minor.yy0);
12765 +    buffer_free(yymsp[-3].minor.yy0); 
12766 +
12767 +    array_free(resp->headers);
12768 +    
12769 +    resp->headers = yymsp[-1].minor.yy12;
12770 +}
12771 +#line 599 "http_resp_parser.c"
12772 +  yy_destructor(1,&yymsp[-2].minor);
12773 +  yy_destructor(1,&yymsp[0].minor);
12774 +        break;
12775 +      case 2:
12776 +#line 69 "./http_resp_parser.y"
12777 +{
12778 +    if (buffer_is_equal_string(yymsp[0].minor.yy0, CONST_STR_LEN("HTTP/1.0"))) {
12779 +        yygotominor.yy20 = HTTP_VERSION_1_0;
12780 +    } else if (buffer_is_equal_string(yymsp[0].minor.yy0, CONST_STR_LEN("HTTP/1.1"))) {
12781 +        yygotominor.yy20 = HTTP_VERSION_1_1;
12782 +    } else {
12783 +        buffer_copy_string(ctx->errmsg, "unknown protocol: ");
12784 +        buffer_append_string_buffer(ctx->errmsg, yymsp[0].minor.yy0);
12785 +        
12786 +        ctx->ok = 0;
12787 +    }
12788 +    buffer_free(yymsp[0].minor.yy0);
12789 +}
12790 +#line 618 "http_resp_parser.c"
12791 +        break;
12792 +      case 3:
12793 +#line 83 "./http_resp_parser.y"
12794 +{
12795 +    char *err;
12796 +    yygotominor.yy20 = strtol(yymsp[0].minor.yy0->ptr, &err, 10);
12797 +    
12798 +    if (*err != '\0') {
12799 +        buffer_copy_string(ctx->errmsg, "expected a number, got: ");
12800 +        buffer_append_string_buffer(ctx->errmsg, yymsp[0].minor.yy0);
12801 +        
12802 +        ctx->ok = 0;
12803 +    }
12804 +    buffer_free(yymsp[0].minor.yy0);
12805 +}
12806 +#line 634 "http_resp_parser.c"
12807 +        break;
12808 +      case 4:
12809 +#line 96 "./http_resp_parser.y"
12810 +{
12811 +    yygotominor.yy0 = yymsp[0].minor.yy0;
12812 +}
12813 +#line 641 "http_resp_parser.c"
12814 +        break;
12815 +      case 5:
12816 +#line 100 "./http_resp_parser.y"
12817 +{
12818 +    yygotominor.yy0 = yymsp[-1].minor.yy0;
12819 +    
12820 +    buffer_append_string(yygotominor.yy0, " ");
12821 +    buffer_append_string_buffer(yygotominor.yy0, yymsp[0].minor.yy0);
12822 +
12823 +    buffer_free(yymsp[0].minor.yy0); 
12824 +}
12825 +#line 653 "http_resp_parser.c"
12826 +        break;
12827 +      case 6:
12828 +#line 109 "./http_resp_parser.y"
12829 +{
12830 +    yygotominor.yy12 = yymsp[-1].minor.yy12;
12831 +    
12832 +    array_insert_unique(yygotominor.yy12, (data_unset *)yymsp[0].minor.yy9);
12833 +}
12834 +#line 662 "http_resp_parser.c"
12835 +        break;
12836 +      case 7:
12837 +#line 115 "./http_resp_parser.y"
12838 +{
12839 +    yygotominor.yy12 = array_init();
12840 +
12841 +    array_insert_unique(yygotominor.yy12, (data_unset *)yymsp[0].minor.yy9);
12842 +}
12843 +#line 671 "http_resp_parser.c"
12844 +        break;
12845 +      case 8:
12846 +#line 120 "./http_resp_parser.y"
12847 +{
12848 +    yygotominor.yy9 = data_string_init();
12849 +    
12850 +    buffer_copy_string_buffer(yygotominor.yy9->key, yymsp[-3].minor.yy0);
12851 +    buffer_copy_string_buffer(yygotominor.yy9->value, yymsp[-1].minor.yy0);    
12852 +    buffer_free(yymsp[-3].minor.yy0);
12853 +    buffer_free(yymsp[-1].minor.yy0);
12854 +}
12855 +#line 683 "http_resp_parser.c"
12856 +  yy_destructor(3,&yymsp[-2].minor);
12857 +  yy_destructor(1,&yymsp[0].minor);
12858 +        break;
12859 +  };
12860 +  yygoto = yyRuleInfo[yyruleno].lhs;
12861 +  yysize = yyRuleInfo[yyruleno].nrhs;
12862 +  yypParser->yyidx -= yysize;
12863 +  yyact = yy_find_reduce_action(yypParser,yygoto);
12864 +  if( yyact < YYNSTATE ){
12865 +    yy_shift(yypParser,yyact,yygoto,&yygotominor);
12866 +  }else if( yyact == YYNSTATE + YYNRULE + 1 ){
12867 +    yy_accept(yypParser);
12868 +  }
12869 +}
12870 +
12871 +/*
12872 +** The following code executes when the parse fails
12873 +*/
12874 +static void yy_parse_failed(
12875 +  yyParser *yypParser           /* The parser */
12876 +){
12877 +  http_resp_parserARG_FETCH;
12878 +#ifndef NDEBUG
12879 +  if( yyTraceFILE ){
12880 +    fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
12881 +  }
12882 +#endif
12883 +  while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
12884 +  /* Here code is inserted which will be executed whenever the
12885 +  ** parser fails */
12886 +#line 15 "./http_resp_parser.y"
12887 +
12888 +  ctx->ok = 0;
12889 +
12890 +#line 718 "http_resp_parser.c"
12891 +  http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
12892 +}
12893 +
12894 +/*
12895 +** The following code executes when a syntax error first occurs.
12896 +*/
12897 +static void yy_syntax_error(
12898 +  yyParser *yypParser,           /* The parser */
12899 +  int yymajor,                   /* The major type of the error token */
12900 +  YYMINORTYPE yyminor            /* The minor type of the error token */
12901 +){
12902 +  http_resp_parserARG_FETCH;
12903 +#define TOKEN (yyminor.yy0)
12904 +  http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
12905 +}
12906 +
12907 +/*
12908 +** The following is executed when the parser accepts
12909 +*/
12910 +static void yy_accept(
12911 +  yyParser *yypParser           /* The parser */
12912 +){
12913 +  http_resp_parserARG_FETCH;
12914 +#ifndef NDEBUG
12915 +  if( yyTraceFILE ){
12916 +    fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
12917 +  }
12918 +#endif
12919 +  while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
12920 +  /* Here code is inserted which will be executed whenever the
12921 +  ** parser accepts */
12922 +  http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
12923 +}
12924 +
12925 +/* The main parser program.
12926 +** The first argument is a pointer to a structure obtained from
12927 +** "http_resp_parserAlloc" which describes the current state of the parser.
12928 +** The second argument is the major token number.  The third is
12929 +** the minor token.  The fourth optional argument is whatever the
12930 +** user wants (and specified in the grammar) and is available for
12931 +** use by the action routines.
12932 +**
12933 +** Inputs:
12934 +** <ul>
12935 +** <li> A pointer to the parser (an opaque structure.)
12936 +** <li> The major token number.
12937 +** <li> The minor token number.
12938 +** <li> An option argument of a grammar-specified type.
12939 +** </ul>
12940 +**
12941 +** Outputs:
12942 +** None.
12943 +*/
12944 +void http_resp_parser(
12945 +  void *yyp,                   /* The parser */
12946 +  int yymajor,                 /* The major token code number */
12947 +  http_resp_parserTOKENTYPE yyminor       /* The value for the token */
12948 +  http_resp_parserARG_PDECL               /* Optional %extra_argument parameter */
12949 +){
12950 +  YYMINORTYPE yyminorunion;
12951 +  int yyact;            /* The parser action. */
12952 +  int yyendofinput;     /* True if we are at the end of input */
12953 +  int yyerrorhit = 0;   /* True if yymajor has invoked an error */
12954 +  yyParser *yypParser;  /* The parser */
12955 +
12956 +  /* (re)initialize the parser, if necessary */
12957 +  yypParser = (yyParser*)yyp;
12958 +  if( yypParser->yyidx<0 ){
12959 +    if( yymajor==0 ) return;
12960 +    yypParser->yyidx = 0;
12961 +    yypParser->yyerrcnt = -1;
12962 +    yypParser->yystack[0].stateno = 0;
12963 +    yypParser->yystack[0].major = 0;
12964 +  }
12965 +  yyminorunion.yy0 = yyminor;
12966 +  yyendofinput = (yymajor==0);
12967 +  http_resp_parserARG_STORE;
12968 +
12969 +#ifndef NDEBUG
12970 +  if( yyTraceFILE ){
12971 +    fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
12972 +  }
12973 +#endif
12974 +
12975 +  do{
12976 +    yyact = yy_find_shift_action(yypParser,yymajor);
12977 +    if( yyact<YYNSTATE ){
12978 +      yy_shift(yypParser,yyact,yymajor,&yyminorunion);
12979 +      yypParser->yyerrcnt--;
12980 +      if( yyendofinput && yypParser->yyidx>=0 ){
12981 +        yymajor = 0;
12982 +      }else{
12983 +        yymajor = YYNOCODE;
12984 +      }
12985 +    }else if( yyact < YYNSTATE + YYNRULE ){
12986 +      yy_reduce(yypParser,yyact-YYNSTATE);
12987 +    }else if( yyact == YY_ERROR_ACTION ){
12988 +      int yymx;
12989 +#ifndef NDEBUG
12990 +      if( yyTraceFILE ){
12991 +        fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
12992 +      }
12993 +#endif
12994 +#ifdef YYERRORSYMBOL
12995 +      /* A syntax error has occurred.
12996 +      ** The response to an error depends upon whether or not the
12997 +      ** grammar defines an error token "ERROR".
12998 +      **
12999 +      ** This is what we do if the grammar does define ERROR:
13000 +      **
13001 +      **  * Call the %syntax_error function.
13002 +      **
13003 +      **  * Begin popping the stack until we enter a state where
13004 +      **    it is legal to shift the error symbol, then shift
13005 +      **    the error symbol.
13006 +      **
13007 +      **  * Set the error count to three.
13008 +      **
13009 +      **  * Begin accepting and shifting new tokens.  No new error
13010 +      **    processing will occur until three tokens have been
13011 +      **    shifted successfully.
13012 +      **
13013 +      */
13014 +      if( yypParser->yyerrcnt<0 ){
13015 +        yy_syntax_error(yypParser,yymajor,yyminorunion);
13016 +      }
13017 +      yymx = yypParser->yystack[yypParser->yyidx].major;
13018 +      if( yymx==YYERRORSYMBOL || yyerrorhit ){
13019 +#ifndef NDEBUG
13020 +        if( yyTraceFILE ){
13021 +          fprintf(yyTraceFILE,"%sDiscard input token %s\n",
13022 +             yyTracePrompt,yyTokenName[yymajor]);
13023 +        }
13024 +#endif
13025 +        yy_destructor(yymajor,&yyminorunion);
13026 +        yymajor = YYNOCODE;
13027 +      }else{
13028 +         while(
13029 +          yypParser->yyidx >= 0 &&
13030 +          yymx != YYERRORSYMBOL &&
13031 +          (yyact = yy_find_shift_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
13032 +        ){
13033 +          yy_pop_parser_stack(yypParser);
13034 +        }
13035 +        if( yypParser->yyidx < 0 || yymajor==0 ){
13036 +          yy_destructor(yymajor,&yyminorunion);
13037 +          yy_parse_failed(yypParser);
13038 +          yymajor = YYNOCODE;
13039 +        }else if( yymx!=YYERRORSYMBOL ){
13040 +          YYMINORTYPE u2;
13041 +          u2.YYERRSYMDT = 0;
13042 +          yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
13043 +        }
13044 +      }
13045 +      yypParser->yyerrcnt = 3;
13046 +      yyerrorhit = 1;
13047 +#else  /* YYERRORSYMBOL is not defined */
13048 +      /* This is what we do if the grammar does not define ERROR:
13049 +      **
13050 +      **  * Report an error message, and throw away the input token.
13051 +      **
13052 +      **  * If the input token is $, then fail the parse.
13053 +      **
13054 +      ** As before, subsequent error messages are suppressed until
13055 +      ** three input tokens have been successfully shifted.
13056 +      */
13057 +      if( yypParser->yyerrcnt<=0 ){
13058 +        yy_syntax_error(yypParser,yymajor,yyminorunion);
13059 +      }
13060 +      yypParser->yyerrcnt = 3;
13061 +      yy_destructor(yymajor,&yyminorunion);
13062 +      if( yyendofinput ){
13063 +        yy_parse_failed(yypParser);
13064 +      }
13065 +      yymajor = YYNOCODE;
13066 +#endif
13067 +    }else{
13068 +      yy_accept(yypParser);
13069 +      yymajor = YYNOCODE;
13070 +    }
13071 +  }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
13072 +  return;
13073 +}
13074 --- ../lighttpd-1.4.11/src/http_resp_parser.h   1970-01-01 03:00:00.000000000 +0300
13075 +++ lighttpd-1.4.12/src/http_resp_parser.h      2006-07-18 13:03:52.000000000 +0300
13076 @@ -0,0 +1,3 @@
13077 +#define TK_CRLF                            1
13078 +#define TK_STRING                          2
13079 +#define TK_COLON                           3
13080 --- ../lighttpd-1.4.11/src/http_resp_parser.y   1970-01-01 03:00:00.000000000 +0300
13081 +++ lighttpd-1.4.12/src/http_resp_parser.y      2006-07-18 13:03:40.000000000 +0300
13082 @@ -0,0 +1,127 @@
13083 +%token_prefix TK_
13084 +%token_type {buffer *}
13085 +%extra_argument {http_resp_ctx_t *ctx}
13086 +%name http_resp_parser
13087 +
13088 +%include {
13089 +#include <assert.h>
13090 +#include <string.h>
13091 +#include "http_resp.h"
13092 +#include "keyvalue.h"
13093 +#include "array.h"
13094 +#include "log.h"
13095 +}
13096 +
13097 +%parse_failure {
13098 +  ctx->ok = 0;
13099 +}
13100 +
13101 +%type protocol { int }
13102 +%type response_hdr { http_resp * }
13103 +%type number { int }
13104 +%type headers { array * }
13105 +%type header { data_string * }
13106 +%destructor reason { buffer_free($$); }
13107 +%token_destructor { buffer_free($$); }
13108 +
13109 +/* just headers + Status: ... */
13110 +response_hdr ::= headers(HDR) CRLF . {
13111 +    http_resp *resp = ctx->resp;
13112 +    data_string *ds;
13113
13114 +    resp->protocol = HTTP_VERSION_UNSET;
13115 +
13116 +    buffer_copy_string(resp->reason, ""); /* no reason */
13117 +    array_free(resp->headers);
13118 +    resp->headers = HDR;
13119 +
13120 +    if (NULL == (ds = (data_string *)array_get_element(HDR, "Status"))) { 
13121 +        resp->status = 0;
13122 +    } else {
13123 +        char *err;
13124 +        resp->status = strtol(ds->value->ptr, &err, 10);
13125 +   
13126 +        if (*err != '\0' && *err != ' ') {
13127 +            buffer_copy_string(ctx->errmsg, "expected a number: ");
13128 +            buffer_append_string_buffer(ctx->errmsg, ds->value);
13129 +            buffer_append_string(ctx->errmsg, err);
13130 +        
13131 +            ctx->ok = 0;
13132 +        }
13133 +    }
13134 +
13135 +    HDR = NULL;
13136 +}
13137 +/* HTTP/1.0 <status> ... */
13138 +response_hdr ::= protocol(B) number(C) reason(D) CRLF headers(HDR) CRLF . {
13139 +    http_resp *resp = ctx->resp;
13140 +    
13141 +    resp->status = C;
13142 +    resp->protocol = B;
13143 +    buffer_copy_string_buffer(resp->reason, D);
13144 +    buffer_free(D); 
13145 +
13146 +    array_free(resp->headers);
13147 +    
13148 +    resp->headers = HDR;
13149 +}
13150 +
13151 +protocol(A) ::= STRING(B). {
13152 +    if (buffer_is_equal_string(B, CONST_STR_LEN("HTTP/1.0"))) {
13153 +        A = HTTP_VERSION_1_0;
13154 +    } else if (buffer_is_equal_string(B, CONST_STR_LEN("HTTP/1.1"))) {
13155 +        A = HTTP_VERSION_1_1;
13156 +    } else {
13157 +        buffer_copy_string(ctx->errmsg, "unknown protocol: ");
13158 +        buffer_append_string_buffer(ctx->errmsg, B);
13159 +        
13160 +        ctx->ok = 0;
13161 +    }
13162 +    buffer_free(B);
13163 +}
13164 +
13165 +number(A) ::= STRING(B). {
13166 +    char *err;
13167 +    A = strtol(B->ptr, &err, 10);
13168 +    
13169 +    if (*err != '\0') {
13170 +        buffer_copy_string(ctx->errmsg, "expected a number, got: ");
13171 +        buffer_append_string_buffer(ctx->errmsg, B);
13172 +        
13173 +        ctx->ok = 0;
13174 +    }
13175 +    buffer_free(B);
13176 +}
13177 +
13178 +reason(A) ::= STRING(B). {
13179 +    A = B;
13180 +}
13181 +
13182 +reason(A) ::= reason(C) STRING(B). {
13183 +    A = C;
13184 +    
13185 +    buffer_append_string(A, " ");
13186 +    buffer_append_string_buffer(A, B);
13187 +
13188 +    buffer_free(B); 
13189 +}
13190 +
13191 +headers(HDRS) ::= headers(SRC) header(HDR). {
13192 +    HDRS = SRC;
13193 +    
13194 +    array_insert_unique(HDRS, (data_unset *)HDR);
13195 +}
13196 +
13197 +headers(HDRS) ::= header(HDR). {
13198 +    HDRS = array_init();
13199 +
13200 +    array_insert_unique(HDRS, (data_unset *)HDR);
13201 +}
13202 +header(HDR) ::= STRING(A) COLON STRING(B) CRLF. {
13203 +    HDR = data_string_init();
13204 +    
13205 +    buffer_copy_string_buffer(HDR->key, A);
13206 +    buffer_copy_string_buffer(HDR->value, B);    
13207 +    buffer_free(A);
13208 +    buffer_free(B);
13209 +}
13210 --- ../lighttpd-1.4.11/src/inet_ntop_cache.c    2005-08-11 01:26:38.000000000 +0300
13211 +++ lighttpd-1.4.12/src/inet_ntop_cache.c       2006-07-16 00:26:04.000000000 +0300
13212 @@ -8,7 +8,7 @@
13213  #include "sys-socket.h"
13214  
13215  const char * inet_ntop_cache_get_ip(server *srv, sock_addr *addr) {
13216 -#ifdef HAVE_IPV6       
13217 +#ifdef HAVE_IPV6
13218         size_t ndx = 0, i;
13219         for (i = 0; i < INET_NTOP_CACHE_MAX; i++) {
13220                 if (srv->inet_ntop_cache[i].ts != 0) {
13221 @@ -20,31 +20,31 @@
13222                                    srv->inet_ntop_cache[i].addr.ipv4.s_addr == addr->ipv4.sin_addr.s_addr) {
13223                                 /* IPv4 found in cache */
13224                                 break;
13225 -                               
13226 +
13227                         }
13228                 }
13229         }
13230 -       
13231 +
13232         if (i == INET_NTOP_CACHE_MAX) {
13233                 /* not found in cache */
13234 -               
13235 +
13236                 i = ndx;
13237 -               inet_ntop(addr->plain.sa_family, 
13238 -                         addr->plain.sa_family == AF_INET6 ? 
13239 +               inet_ntop(addr->plain.sa_family,
13240 +                         addr->plain.sa_family == AF_INET6 ?
13241                           (const void *) &(addr->ipv6.sin6_addr) :
13242                           (const void *) &(addr->ipv4.sin_addr),
13243                           srv->inet_ntop_cache[i].b2, INET6_ADDRSTRLEN);
13244 -               
13245 +
13246                 srv->inet_ntop_cache[i].ts = srv->cur_ts;
13247                 srv->inet_ntop_cache[i].family = addr->plain.sa_family;
13248 -               
13249 +
13250                 if (srv->inet_ntop_cache[i].family == AF_INET) {
13251                         srv->inet_ntop_cache[i].addr.ipv4.s_addr = addr->ipv4.sin_addr.s_addr;
13252                 } else if (srv->inet_ntop_cache[i].family == AF_INET6) {
13253                         memcpy(srv->inet_ntop_cache[i].addr.ipv6.s6_addr, addr->ipv6.sin6_addr.s6_addr, 16);
13254                 }
13255         }
13256 -       
13257 +
13258         return srv->inet_ntop_cache[i].b2;
13259  #else
13260         UNUSED(srv);
13261 --- ../lighttpd-1.4.11/src/iosocket.c   1970-01-01 03:00:00.000000000 +0300
13262 +++ lighttpd-1.4.12/src/iosocket.c      2006-07-18 13:03:40.000000000 +0300
13263 @@ -0,0 +1,36 @@
13264 +#include <stdlib.h>
13265 +
13266 +#include "iosocket.h"
13267 +#include "sys-socket.h"
13268 +#include "sys-files.h"
13269 +#include "array-static.h"
13270 +
13271 +iosocket *iosocket_init(void) {
13272 +       STRUCT_INIT(iosocket, sock);
13273 +
13274 +       sock->fde_ndx = -1;
13275 +       sock->fd = -1;
13276 +
13277 +       sock->type = IOSOCKET_TYPE_SOCKET;
13278 +
13279 +       return sock;
13280 +}
13281 +
13282 +void iosocket_free(iosocket *sock) {
13283 +       if (!sock) return;
13284 +
13285 +       if (sock->fd != -1) {
13286 +               switch (sock->type) {
13287 +               case IOSOCKET_TYPE_SOCKET:
13288 +                       closesocket(sock->fd);
13289 +                       break;
13290 +               case IOSOCKET_TYPE_PIPE:
13291 +                       close(sock->fd);
13292 +                       break;
13293 +               default:
13294 +                       break;
13295 +               }
13296 +       }
13297 +
13298 +       free(sock);
13299 +}
13300 --- ../lighttpd-1.4.11/src/iosocket.h   1970-01-01 03:00:00.000000000 +0300
13301 +++ lighttpd-1.4.12/src/iosocket.h      2006-07-18 13:03:40.000000000 +0300
13302 @@ -0,0 +1,32 @@
13303 +#ifndef _IOSOCKET_H_
13304 +#define _IOSOCKET_H_
13305 +
13306 +#if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
13307 +# define USE_OPENSSL
13308 +# include <openssl/ssl.h>
13309 +#endif
13310 +
13311 +typedef enum {
13312 +       IOSOCKET_TYPE_UNSET,
13313 +       IOSOCKET_TYPE_SOCKET,
13314 +       IOSOCKET_TYPE_PIPE
13315 +} iosocket_t;
13316 +
13317 +/**
13318 + * a non-blocking fd
13319 + */
13320 +typedef struct {
13321 +       int fd;
13322 +       int fde_ndx;
13323 +
13324 +#ifdef USE_OPENSSL
13325 +       SSL *ssl;
13326 +#endif
13327 +
13328 +       iosocket_t type; /**< sendfile on solaris doesn't work on pipes */
13329 +} iosocket;
13330 +
13331 +iosocket *iosocket_init(void);
13332 +void iosocket_free(iosocket *sock);
13333 +
13334 +#endif
13335 --- ../lighttpd-1.4.11/src/joblist.c    2005-08-11 01:26:41.000000000 +0300
13336 +++ lighttpd-1.4.12/src/joblist.c       2006-07-16 00:26:03.000000000 +0300
13337 @@ -7,7 +7,7 @@
13338  
13339  int joblist_append(server *srv, connection *con) {
13340         if (con->in_joblist) return 0;
13341 -       
13342 +
13343         if (srv->joblist->size == 0) {
13344                 srv->joblist->size  = 16;
13345                 srv->joblist->ptr   = malloc(sizeof(*srv->joblist->ptr) * srv->joblist->size);
13346 @@ -15,15 +15,15 @@
13347                 srv->joblist->size += 16;
13348                 srv->joblist->ptr   = realloc(srv->joblist->ptr, sizeof(*srv->joblist->ptr) * srv->joblist->size);
13349         }
13350 -       
13351 +
13352         srv->joblist->ptr[srv->joblist->used++] = con;
13353 -       
13354 +
13355         return 0;
13356  }
13357  
13358  void joblist_free(server *srv, connections *joblist) {
13359         UNUSED(srv);
13360 -               
13361 +
13362         free(joblist->ptr);
13363         free(joblist);
13364  }
13365 @@ -31,14 +31,14 @@
13366  connection *fdwaitqueue_unshift(server *srv, connections *fdwaitqueue) {
13367         connection *con;
13368         UNUSED(srv);
13369 -               
13370 -       
13371 +
13372 +
13373         if (fdwaitqueue->used == 0) return NULL;
13374 -       
13375 +
13376         con = fdwaitqueue->ptr[0];
13377 -       
13378 +
13379         memmove(fdwaitqueue->ptr, &(fdwaitqueue->ptr[1]), --fdwaitqueue->used * sizeof(*(fdwaitqueue->ptr)));
13380 -       
13381 +
13382         return con;
13383  }
13384  
13385 @@ -50,9 +50,9 @@
13386                 srv->fdwaitqueue->size += 16;
13387                 srv->fdwaitqueue->ptr   = realloc(srv->fdwaitqueue->ptr, sizeof(*(srv->fdwaitqueue->ptr)) * srv->fdwaitqueue->size);
13388         }
13389 -       
13390 +
13391         srv->fdwaitqueue->ptr[srv->fdwaitqueue->used++] = con;
13392 -       
13393 +
13394         return 0;
13395  }
13396  
13397 --- ../lighttpd-1.4.11/src/keyvalue.c   2006-03-02 16:08:06.000000000 +0200
13398 +++ lighttpd-1.4.12/src/keyvalue.c      2006-07-16 00:26:03.000000000 +0300
13399 @@ -87,7 +87,8 @@
13400         { 504, "Gateway Timeout" },
13401         { 505, "HTTP Version Not Supported" },
13402         { 507, "Insufficient Storage" }, /* WebDAV */
13403 -       
13404 +       { 509, "Bandwidth Limit exceeded" },
13405 +
13406         { -1, NULL }
13407  };
13408  
13409 @@ -102,12 +103,12 @@
13410         { 501, "501.html" },
13411         { 503, "503.html" },
13412         { 505, "505.html" },
13413 -       
13414 +
13415         { -1, NULL }
13416  };
13417  
13418  
13419 -const char *keyvalue_get_value(keyvalue *kv, int k) { 
13420 +const char *keyvalue_get_value(keyvalue *kv, int k) {
13421         int i;
13422         for (i = 0; kv[i].value; i++) {
13423                 if (kv[i].key == k) return kv[i].value;
13424 @@ -115,7 +116,7 @@
13425         return NULL;
13426  }
13427  
13428 -int keyvalue_get_key(keyvalue *kv, const char *s) { 
13429 +int keyvalue_get_key(keyvalue *kv, const char *s) {
13430         int i;
13431         for (i = 0; kv[i].value; i++) {
13432                 if (0 == strcmp(kv[i].value, s)) return kv[i].key;
13433 @@ -125,9 +126,9 @@
13434  
13435  keyvalue_buffer *keyvalue_buffer_init(void) {
13436         keyvalue_buffer *kvb;
13437 -       
13438 +
13439         kvb = calloc(1, sizeof(*kvb));
13440 -       
13441 +
13442         return kvb;
13443  }
13444  
13445 @@ -135,49 +136,49 @@
13446         size_t i;
13447         if (kvb->size == 0) {
13448                 kvb->size = 4;
13449 -               
13450 +
13451                 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13452 -               
13453 +
13454                 for(i = 0; i < kvb->size; i++) {
13455                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13456                 }
13457         } else if (kvb->used == kvb->size) {
13458                 kvb->size += 4;
13459 -               
13460 +
13461                 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13462 -               
13463 +
13464                 for(i = kvb->used; i < kvb->size; i++) {
13465                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13466                 }
13467         }
13468 -       
13469 +
13470         kvb->kv[kvb->used]->key = key;
13471         kvb->kv[kvb->used]->value = strdup(value);
13472 -       
13473 +
13474         kvb->used++;
13475 -       
13476 +
13477         return 0;
13478  }
13479  
13480  void keyvalue_buffer_free(keyvalue_buffer *kvb) {
13481         size_t i;
13482 -       
13483 +
13484         for (i = 0; i < kvb->size; i++) {
13485                 if (kvb->kv[i]->value) free(kvb->kv[i]->value);
13486                 free(kvb->kv[i]);
13487         }
13488 -       
13489 +
13490         if (kvb->kv) free(kvb->kv);
13491 -       
13492 +
13493         free(kvb);
13494  }
13495  
13496  
13497  s_keyvalue_buffer *s_keyvalue_buffer_init(void) {
13498         s_keyvalue_buffer *kvb;
13499 -       
13500 +
13501         kvb = calloc(1, sizeof(*kvb));
13502 -       
13503 +
13504         return kvb;
13505  }
13506  
13507 @@ -186,50 +187,50 @@
13508         if (kvb->size == 0) {
13509                 kvb->size = 4;
13510                 kvb->used = 0;
13511 -               
13512 +
13513                 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13514 -               
13515 +
13516                 for(i = 0; i < kvb->size; i++) {
13517                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13518                 }
13519         } else if (kvb->used == kvb->size) {
13520                 kvb->size += 4;
13521 -               
13522 +
13523                 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13524 -               
13525 +
13526                 for(i = kvb->used; i < kvb->size; i++) {
13527                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13528                 }
13529         }
13530 -       
13531 +
13532         kvb->kv[kvb->used]->key = key ? strdup(key) : NULL;
13533         kvb->kv[kvb->used]->value = strdup(value);
13534 -       
13535 +
13536         kvb->used++;
13537 -       
13538 +
13539         return 0;
13540  }
13541  
13542  void s_keyvalue_buffer_free(s_keyvalue_buffer *kvb) {
13543         size_t i;
13544 -       
13545 +
13546         for (i = 0; i < kvb->size; i++) {
13547                 if (kvb->kv[i]->key) free(kvb->kv[i]->key);
13548                 if (kvb->kv[i]->value) free(kvb->kv[i]->value);
13549                 free(kvb->kv[i]);
13550         }
13551 -       
13552 +
13553         if (kvb->kv) free(kvb->kv);
13554 -       
13555 +
13556         free(kvb);
13557  }
13558  
13559  
13560  httpauth_keyvalue_buffer *httpauth_keyvalue_buffer_init(void) {
13561         httpauth_keyvalue_buffer *kvb;
13562 -       
13563 +
13564         kvb = calloc(1, sizeof(*kvb));
13565 -       
13566 +
13567         return kvb;
13568  }
13569  
13570 @@ -237,42 +238,42 @@
13571         size_t i;
13572         if (kvb->size == 0) {
13573                 kvb->size = 4;
13574 -               
13575 +
13576                 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13577 -               
13578 +
13579                 for(i = 0; i < kvb->size; i++) {
13580                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13581                 }
13582         } else if (kvb->used == kvb->size) {
13583                 kvb->size += 4;
13584 -               
13585 +
13586                 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13587 -               
13588 +
13589                 for(i = kvb->used; i < kvb->size; i++) {
13590                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13591                 }
13592         }
13593 -       
13594 +
13595         kvb->kv[kvb->used]->key = strdup(key);
13596         kvb->kv[kvb->used]->realm = strdup(realm);
13597         kvb->kv[kvb->used]->type = type;
13598 -       
13599 +
13600         kvb->used++;
13601 -       
13602 +
13603         return 0;
13604  }
13605  
13606  void httpauth_keyvalue_buffer_free(httpauth_keyvalue_buffer *kvb) {
13607         size_t i;
13608 -       
13609 +
13610         for (i = 0; i < kvb->size; i++) {
13611                 if (kvb->kv[i]->key) free(kvb->kv[i]->key);
13612                 if (kvb->kv[i]->realm) free(kvb->kv[i]->realm);
13613                 free(kvb->kv[i]);
13614         }
13615 -       
13616 +
13617         if (kvb->kv) free(kvb->kv);
13618 -       
13619 +
13620         free(kvb);
13621  }
13622  
13623 @@ -306,9 +307,9 @@
13624  
13625  pcre_keyvalue_buffer *pcre_keyvalue_buffer_init(void) {
13626         pcre_keyvalue_buffer *kvb;
13627 -       
13628 +
13629         kvb = calloc(1, sizeof(*kvb));
13630 -       
13631 +
13632         return kvb;
13633  }
13634  
13635 @@ -319,46 +320,46 @@
13636         int erroff;
13637         pcre_keyvalue *kv;
13638  #endif
13639 -       
13640 +
13641         if (!key) return -1;
13642  
13643  #ifdef HAVE_PCRE_H
13644         if (kvb->size == 0) {
13645                 kvb->size = 4;
13646                 kvb->used = 0;
13647 -               
13648 +
13649                 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13650 -               
13651 +
13652                 for(i = 0; i < kvb->size; i++) {
13653                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13654                 }
13655         } else if (kvb->used == kvb->size) {
13656                 kvb->size += 4;
13657 -               
13658 +
13659                 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13660 -               
13661 +
13662                 for(i = kvb->used; i < kvb->size; i++) {
13663                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13664                 }
13665         }
13666 -       
13667 +
13668         kv = kvb->kv[kvb->used];
13669         if (NULL == (kv->key = pcre_compile(key,
13670                                           0, &errptr, &erroff, NULL))) {
13671 -               
13672 +
13673                 fprintf(stderr, "%s.%d: rexexp compilation error at %s\n", __FILE__, __LINE__, errptr);
13674                 return -1;
13675         }
13676  
13677 -       if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) &&  
13678 +       if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) &&
13679                         errptr != NULL) {
13680                 return -1;
13681         }
13682 -       
13683 +
13684         kv->value = buffer_init_string(value);
13685 -       
13686 +
13687         kvb->used++;
13688 -       
13689 +
13690         return 0;
13691  #else
13692         UNUSED(kvb);
13693 @@ -380,9 +381,9 @@
13694                 if (kv->value) buffer_free(kv->value);
13695                 free(kv);
13696         }
13697 -       
13698 +
13699         if (kvb->kv) free(kvb->kv);
13700  #endif
13701 -       
13702 +
13703         free(kvb);
13704  }
13705 --- ../lighttpd-1.4.11/src/keyvalue.h   2006-03-02 16:08:06.000000000 +0200
13706 +++ lighttpd-1.4.12/src/keyvalue.h      2006-07-16 00:26:04.000000000 +0300
13707 @@ -9,19 +9,19 @@
13708  # include <pcre.h>
13709  #endif
13710  
13711 -typedef enum { 
13712 -       HTTP_METHOD_UNSET = -1, 
13713 -       HTTP_METHOD_GET, 
13714 -       HTTP_METHOD_POST, 
13715 -       HTTP_METHOD_HEAD, 
13716 -       HTTP_METHOD_OPTIONS, 
13717 +typedef enum {
13718 +       HTTP_METHOD_UNSET = -1,
13719 +       HTTP_METHOD_GET,
13720 +       HTTP_METHOD_POST,
13721 +       HTTP_METHOD_HEAD,
13722 +       HTTP_METHOD_OPTIONS,
13723         HTTP_METHOD_PROPFIND,  /* WebDAV */
13724 -       HTTP_METHOD_MKCOL, 
13725 -       HTTP_METHOD_PUT, 
13726 -       HTTP_METHOD_DELETE, 
13727 -       HTTP_METHOD_COPY, 
13728 -       HTTP_METHOD_MOVE, 
13729 -       HTTP_METHOD_PROPPATCH, 
13730 +       HTTP_METHOD_MKCOL,
13731 +       HTTP_METHOD_PUT,
13732 +       HTTP_METHOD_DELETE,
13733 +       HTTP_METHOD_COPY,
13734 +       HTTP_METHOD_MOVE,
13735 +       HTTP_METHOD_PROPPATCH,
13736         HTTP_METHOD_REPORT, /* DeltaV */
13737         HTTP_METHOD_CHECKOUT,
13738         HTTP_METHOD_CHECKIN,
13739 @@ -39,13 +39,13 @@
13740  
13741  typedef struct {
13742         int key;
13743 -       
13744 +
13745         char *value;
13746  } keyvalue;
13747  
13748  typedef struct {
13749         char *key;
13750 -       
13751 +
13752         char *value;
13753  } s_keyvalue;
13754  
13755 @@ -54,7 +54,7 @@
13756         pcre *key;
13757         pcre_extra *key_extra;
13758  #endif
13759 -       
13760 +
13761         buffer *value;
13762  } pcre_keyvalue;
13763  
13764 @@ -62,7 +62,7 @@
13765  
13766  typedef struct {
13767         char *key;
13768 -       
13769 +
13770         char *realm;
13771         httpauth_type type;
13772  } httpauth_keyvalue;
13773 --- ../lighttpd-1.4.11/src/lemon.c      2005-09-01 00:21:34.000000000 +0300
13774 +++ lighttpd-1.4.12/src/lemon.c 2006-07-16 00:26:03.000000000 +0300
13775 @@ -579,7 +579,7 @@
13776  */
13777  
13778  /* Find a precedence symbol of every rule in the grammar.
13779 -** 
13780 +**
13781  ** Those rules which have a precedence symbol coded in the input
13782  ** grammar using the "[symbol]" construct will already have the
13783  ** rp->precsym field filled.  Other rules take as their precedence
13784 @@ -869,7 +869,7 @@
13785        cfp->status = INCOMPLETE;
13786      }
13787    }
13788 -  
13789 +
13790    do{
13791      progress = 0;
13792      for(i=0; i<lemp->nstate; i++){
13793 @@ -900,7 +900,7 @@
13794    struct symbol *sp;
13795    struct rule *rp;
13796  
13797 -  /* Add all of the reduce actions 
13798 +  /* Add all of the reduce actions
13799    ** A reduce action is added for each element of the followset of
13800    ** a configuration which has its dot at the extreme right.
13801    */
13802 @@ -1017,7 +1017,7 @@
13803        apx->type = RD_RESOLVED;
13804      }
13805    }else{
13806 -    assert( 
13807 +    assert(
13808        apx->type==SH_RESOLVED ||
13809        apx->type==RD_RESOLVED ||
13810        apx->type==CONFLICT ||
13811 @@ -1350,7 +1350,7 @@
13812    OptInit(argv,options,stderr);
13813    if( version ){
13814       printf("Lemon version 1.0\n");
13815 -     exit(0); 
13816 +     exit(0);
13817    }
13818    if( OptNArgs() < 1 ){
13819      fprintf(stderr,"Exactly one filename argument is required.\n");
13820 @@ -2031,7 +2031,7 @@
13821      case IN_RHS:
13822        if( x[0]=='.' ){
13823          struct rule *rp;
13824 -        rp = (struct rule *)malloc( sizeof(struct rule) + 
13825 +        rp = (struct rule *)malloc( sizeof(struct rule) +
13826               sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs );
13827          if( rp==0 ){
13828            ErrorMsg(psp->filename,psp->tokenlineno,
13829 @@ -2546,7 +2546,7 @@
13830    return fp;
13831  }
13832  
13833 -/* Duplicate the input file without comments and without actions 
13834 +/* Duplicate the input file without comments and without actions
13835  ** on rules */
13836  void Reprint(lemp)
13837  struct lemon *lemp;
13838 @@ -2822,7 +2822,7 @@
13839  PRIVATE FILE *tplt_open(lemp)
13840  struct lemon *lemp;
13841  {
13842 -  
13843 +
13844    char buf[1000];
13845    FILE *in;
13846    char *tpltname;
13847 @@ -2930,7 +2930,7 @@
13848    return ret;
13849  }
13850  
13851 -/* 
13852 +/*
13853  ** Generate code which executes when the rule "rp" is reduced.  Write
13854  ** the code to "out".  Make sure lineno stays up-to-date.
13855  */
13856 @@ -3384,7 +3384,7 @@
13857  
13858    /* Output the yy_shift_ofst[] table */
13859    fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++;
13860 -  fprintf(out, "static %s yy_shift_ofst[] = {\n", 
13861 +  fprintf(out, "static %s yy_shift_ofst[] = {\n",
13862            minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++;
13863    n = lemp->nstate;
13864    for(i=j=0; i<n; i++){
13865 @@ -3405,7 +3405,7 @@
13866  
13867    /* Output the yy_reduce_ofst[] table */
13868    fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++;
13869 -  fprintf(out, "static %s yy_reduce_ofst[] = {\n", 
13870 +  fprintf(out, "static %s yy_reduce_ofst[] = {\n",
13871            minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++;
13872    n = lemp->nstate;
13873    for(i=j=0; i<n; i++){
13874 @@ -3480,7 +3480,7 @@
13875    tplt_xfer(lemp->name,in,out,&lineno);
13876  
13877    /* Generate code which executes every time a symbol is popped from
13878 -  ** the stack while processing errors or while destroying the parser. 
13879 +  ** the stack while processing errors or while destroying the parser.
13880    ** (In other words, generate the %destructor actions)
13881    */
13882    if( lemp->tokendest ){
13883 @@ -3522,7 +3522,7 @@
13884    tplt_print(out,lemp,lemp->overflow,lemp->overflowln,&lineno);
13885    tplt_xfer(lemp->name,in,out,&lineno);
13886  
13887 -  /* Generate the table of rule information 
13888 +  /* Generate the table of rule information
13889    **
13890    ** Note: This code depends on the fact that rules are number
13891    ** sequentually beginning with 0.
13892 @@ -3589,7 +3589,7 @@
13893      for(i=1; i<lemp->nterminal; i++){
13894        fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
13895      }
13896 -    fclose(out);  
13897 +    fclose(out);
13898    }
13899    return;
13900  }
13901 @@ -3630,7 +3630,7 @@
13902          rbest = rp;
13903        }
13904      }
13905
13906 +
13907      /* Do not make a default if the number of rules to default
13908      ** is not at least 2 */
13909      if( nbest<2 ) continue;
13910 @@ -3781,7 +3781,7 @@
13911    if( x1a ){
13912      x1a->size = 1024;
13913      x1a->count = 0;
13914 -    x1a->tbl = (x1node*)malloc( 
13915 +    x1a->tbl = (x1node*)malloc(
13916        (sizeof(x1node) + sizeof(x1node*))*1024 );
13917      if( x1a->tbl==0 ){
13918        free(x1a);
13919 @@ -3943,7 +3943,7 @@
13920    if( x2a ){
13921      x2a->size = 128;
13922      x2a->count = 0;
13923 -    x2a->tbl = (x2node*)malloc( 
13924 +    x2a->tbl = (x2node*)malloc(
13925        (sizeof(x2node) + sizeof(x2node*))*128 );
13926      if( x2a->tbl==0 ){
13927        free(x2a);
13928 @@ -4149,7 +4149,7 @@
13929    if( x3a ){
13930      x3a->size = 128;
13931      x3a->count = 0;
13932 -    x3a->tbl = (x3node*)malloc( 
13933 +    x3a->tbl = (x3node*)malloc(
13934        (sizeof(x3node) + sizeof(x3node*))*128 );
13935      if( x3a->tbl==0 ){
13936        free(x3a);
13937 @@ -4295,7 +4295,7 @@
13938    if( x4a ){
13939      x4a->size = 64;
13940      x4a->count = 0;
13941 -    x4a->tbl = (x4node*)malloc( 
13942 +    x4a->tbl = (x4node*)malloc(
13943        (sizeof(x4node) + sizeof(x4node*))*64 );
13944      if( x4a->tbl==0 ){
13945        free(x4a);
13946 --- ../lighttpd-1.4.11/src/lempar.c     2005-08-11 01:26:40.000000000 +0300
13947 +++ lighttpd-1.4.12/src/lempar.c        2006-07-16 00:26:03.000000000 +0300
13948 @@ -8,10 +8,10 @@
13949  /* Next is all token values, in a form suitable for use by makeheaders.
13950  ** This section will be null unless lemon is run with the -m switch.
13951  */
13952 -/* 
13953 +/*
13954  ** These constants (all generated automatically by the parser generator)
13955  ** specify the various kinds of tokens (terminals) that the parser
13956 -** understands. 
13957 +** understands.
13958  **
13959  ** Each symbol here is a terminal symbol in the grammar.
13960  */
13961 @@ -29,7 +29,7 @@
13962  **                       and nonterminals.  "int" is used otherwise.
13963  **    YYNOCODE           is a number of type YYCODETYPE which corresponds
13964  **                       to no legal terminal or nonterminal number.  This
13965 -**                       number is used to fill in empty slots of the hash 
13966 +**                       number is used to fill in empty slots of the hash
13967  **                       table.
13968  **    YYFALLBACK         If defined, this indicates that one or more tokens
13969  **                       have fall-back values which should be used if the
13970 @@ -38,7 +38,7 @@
13971  **                       and nonterminal numbers.  "unsigned char" is
13972  **                       used if there are fewer than 250 rules and
13973  **                       states combined.  "int" is used otherwise.
13974 -**    ParseTOKENTYPE     is the data type used for minor tokens given 
13975 +**    ParseTOKENTYPE     is the data type used for minor tokens given
13976  **                       directly to the parser from the tokenizer.
13977  **    YYMINORTYPE        is the data type used for all minor tokens.
13978  **                       This is typically a union of many types, one of
13979 @@ -62,7 +62,7 @@
13980  /* Next are that tables used to determine what action to take based on the
13981  ** current state and lookahead token.  These tables are used to implement
13982  ** functions that take a state number and lookahead value and return an
13983 -** action integer.  
13984 +** action integer.
13985  **
13986  ** Suppose the action integer is N.  Then the action is determined as
13987  ** follows
13988 @@ -87,7 +87,7 @@
13989  ** If the index value yy_shift_ofst[S]+X is out of range or if the value
13990  ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
13991  ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
13992 -** and that yy_default[S] should be used instead.  
13993 +** and that yy_default[S] should be used instead.
13994  **
13995  ** The formula above is for computing the action when the lookahead is
13996  ** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
13997 @@ -111,7 +111,7 @@
13998  
13999  /* The next table maps tokens into fallback tokens.  If a construct
14000  ** like the following:
14001 -** 
14002 +**
14003  **      %fallback ID X Y Z.
14004  **
14005  ** appears in the grammer, then ID becomes a fallback token for X, Y,
14006 @@ -163,10 +163,10 @@
14007  #endif /* NDEBUG */
14008  
14009  #ifndef NDEBUG
14010 -/* 
14011 +/*
14012  ** Turn parser tracing on by giving a stream to which to write the trace
14013  ** and a prompt to preface each trace message.  Tracing is turned off
14014 -** by making either argument NULL 
14015 +** by making either argument NULL
14016  **
14017  ** Inputs:
14018  ** <ul>
14019 @@ -191,7 +191,7 @@
14020  #ifndef NDEBUG
14021  /* For tracing shifts, the names of all terminals and nonterminals
14022  ** are required.  The following table supplies these names */
14023 -static const char *yyTokenName[] = { 
14024 +static const char *yyTokenName[] = {
14025  %%
14026  };
14027  #endif /* NDEBUG */
14028 @@ -220,7 +220,7 @@
14029  #endif
14030  }
14031  
14032 -/* 
14033 +/*
14034  ** This function allocates a new parser.
14035  ** The only argument is a pointer to a function which works like
14036  ** malloc.
14037 @@ -251,7 +251,7 @@
14038      /* Here is inserted the actions which take place when a
14039      ** terminal or non-terminal is destroyed.  This can happen
14040      ** when the symbol is popped from the stack during a
14041 -    ** reduce or during error processing or when a parser is 
14042 +    ** reduce or during error processing or when a parser is
14043      ** being destroyed before it is finished parsing.
14044      **
14045      ** Note: during a reduce, the only symbols destroyed are those
14046 @@ -289,7 +289,7 @@
14047    return yymajor;
14048  }
14049  
14050 -/* 
14051 +/*
14052  ** Deallocate and destroy a parser.  Destructors are all called for
14053  ** all stack elements before shutting the parser down.
14054  **
14055 @@ -325,7 +325,7 @@
14056  ){
14057    int i;
14058    int stateno = pParser->yystack[pParser->yyidx].stateno;
14059
14060 +
14061    /* if( pParser->yyidx<0 ) return YY_NO_ACTION;  */
14062    i = yy_shift_ofst[stateno];
14063    if( i==YY_SHIFT_USE_DFLT ){
14064 @@ -369,7 +369,7 @@
14065  ){
14066    int i;
14067    int stateno = pParser->yystack[pParser->yyidx].stateno;
14068
14069 +
14070    i = yy_reduce_ofst[stateno];
14071    if( i==YY_REDUCE_USE_DFLT ){
14072      return yy_default[stateno];
14073 @@ -455,7 +455,7 @@
14074    ParseARG_FETCH;
14075    yymsp = &yypParser->yystack[yypParser->yyidx];
14076  #ifndef NDEBUG
14077 -  if( yyTraceFILE && yyruleno>=0 
14078 +  if( yyTraceFILE && yyruleno>=0
14079          && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
14080      fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
14081        yyRuleName[yyruleno]);
14082 @@ -608,7 +608,7 @@
14083  #ifdef YYERRORSYMBOL
14084        /* A syntax error has occurred.
14085        ** The response to an error depends upon whether or not the
14086 -      ** grammar defines an error token "ERROR".  
14087 +      ** grammar defines an error token "ERROR".
14088        **
14089        ** This is what we do if the grammar does define ERROR:
14090        **
14091 --- ../lighttpd-1.4.11/src/log.c        2005-11-07 15:01:35.000000000 +0200
14092 +++ lighttpd-1.4.12/src/log.c   2006-07-18 13:03:40.000000000 +0300
14093 @@ -5,7 +5,6 @@
14094  #include <errno.h>
14095  #include <fcntl.h>
14096  #include <time.h>
14097 -#include <unistd.h>
14098  #include <string.h>
14099  #include <stdlib.h>
14100  
14101 @@ -16,6 +15,10 @@
14102  #include "config.h"
14103  #endif
14104  
14105 +#ifdef _WIN32
14106 +#undef HAVE_SYSLOG_H
14107 +#endif
14108 +
14109  #ifdef HAVE_SYSLOG_H
14110  #include <syslog.h>
14111  #endif
14112 @@ -23,6 +26,8 @@
14113  #include "log.h"
14114  #include "array.h"
14115  
14116 +#include "sys-files.h"
14117 +
14118  #ifdef HAVE_VALGRIND_VALGRIND_H
14119  #include <valgrind/valgrind.h>
14120  #endif
14121 @@ -31,55 +36,114 @@
14122  # define O_LARGEFILE 0
14123  #endif
14124  
14125 -/** 
14126 +/**
14127   * open the errorlog
14128 - * 
14129 + *
14130   * we have 3 possibilities:
14131   * - stderr (default)
14132 - * - syslog 
14133 + * - syslog
14134   * - logfile
14135 - * 
14136 + *
14137   * if the open failed, report to the user and die
14138 - * 
14139 + *
14140   */
14141  
14142 -int log_error_open(server *srv) {
14143 +
14144 +typedef struct {
14145 +       buffer *file;
14146 +       unsigned short use_syslog;
14147 +
14148 +       /* the errorlog */
14149         int fd;
14150 -       int close_stderr = 1;
14151 +       enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG } mode;
14152 +       buffer *buf;
14153 +
14154 +       time_t cached_ts;
14155 +       buffer *cached_ts_str;
14156 +} errorlog;
14157 +
14158 +errorlog *myconfig = NULL;
14159 +
14160 +void log_init(void) {
14161 +       /* use syslog */
14162 +       errorlog *err;
14163 +
14164 +       err = calloc(1, sizeof(*err));
14165         
14166 +       err->fd = -1;
14167 +       err->mode = ERRORLOG_STDERR;
14168 +       err->buf = buffer_init();
14169 +       err->cached_ts_str = buffer_init();
14170 +
14171 +       myconfig = err;
14172 +}
14173 +
14174 +void log_free(void) {
14175 +       errorlog *err = myconfig;
14176 +
14177 +       if (!err) return;
14178 +
14179 +       TRACE("%s", "server stopped");
14180 +
14181 +       switch(err->mode) {
14182 +       case ERRORLOG_FILE:
14183 +               close(err->fd);
14184 +               break;
14185 +       case ERRORLOG_SYSLOG:
14186 +#ifdef HAVE_SYSLOG_H
14187 +               closelog();
14188 +#endif
14189 +               break;
14190 +       case ERRORLOG_STDERR:
14191 +               break;
14192 +       }
14193 +
14194 +       buffer_free(err->buf);
14195 +       buffer_free(err->cached_ts_str);
14196 +       if (err->file) buffer_free(err->file);
14197 +
14198 +       free(err);
14199 +
14200 +       myconfig = NULL;
14201 +}
14202 +
14203 +int log_error_open(buffer *file, int use_syslog) {
14204 +       int fd;
14205 +       int close_stderr = 1;
14206 +
14207 +       errorlog *err = myconfig;
14208 +
14209  #ifdef HAVE_SYSLOG_H
14210         /* perhaps someone wants to use syslog() */
14211         openlog("lighttpd", LOG_CONS | LOG_PID, LOG_DAEMON);
14212  #endif
14213 -       srv->errorlog_mode = ERRORLOG_STDERR;
14214 -       
14215 -       if (srv->srvconf.errorlog_use_syslog) {
14216 -               srv->errorlog_mode = ERRORLOG_SYSLOG;
14217 -       } else if (!buffer_is_empty(srv->srvconf.errorlog_file)) {
14218 -               const char *logfile = srv->srvconf.errorlog_file->ptr;
14219 -               
14220 -               if (-1 == (srv->errorlog_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14221 -                       log_error_write(srv, __FILE__, __LINE__, "SSSS", 
14222 -                                       "opening errorlog '", logfile,
14223 +       err->mode = ERRORLOG_STDERR;
14224 +
14225 +       if (use_syslog) {
14226 +               err->mode = ERRORLOG_SYSLOG;
14227 +       } else if (!buffer_is_empty(file)) {
14228 +               if (-1 == (err->fd = open(file->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14229 +                       log_error_write(NULL, __FILE__, __LINE__, "SBSS",
14230 +                                       "opening errorlog '", file,
14231                                         "' failed: ", strerror(errno));
14232 -                       
14233 +
14234                         return -1;
14235                 }
14236  #ifdef FD_CLOEXEC
14237                 /* close fd on exec (cgi) */
14238 -               fcntl(srv->errorlog_fd, F_SETFD, FD_CLOEXEC);
14239 +               fcntl(err->fd, F_SETFD, FD_CLOEXEC);
14240  #endif
14241 -               srv->errorlog_mode = ERRORLOG_FILE;
14242 +               err->mode = ERRORLOG_FILE;
14243         }
14244 -       
14245 -       log_error_write(srv, __FILE__, __LINE__, "s", "server started");
14246 -       
14247 +
14248 +       TRACE("%s", "server started");
14249 +
14250  #ifdef HAVE_VALGRIND_VALGRIND_H
14251         /* don't close stderr for debugging purposes if run in valgrind */
14252         if (RUNNING_ON_VALGRIND) close_stderr = 0;
14253  #endif
14254 -       if (srv->errorlog_mode == ERRORLOG_STDERR) close_stderr = 0;
14255 -       
14256 +       if (err->mode == ERRORLOG_STDERR) close_stderr = 0;
14257 +
14258         /* move stderr to /dev/null */
14259         if (close_stderr &&
14260             -1 != (fd = open("/dev/null", O_WRONLY))) {
14261 @@ -90,167 +154,202 @@
14262         return 0;
14263  }
14264  
14265 -/** 
14266 +/**
14267   * open the errorlog
14268 - * 
14269 + *
14270   * if the open failed, report to the user and die
14271   * if no filename is given, use syslog instead
14272 - * 
14273 + *
14274   */
14275  
14276 -int log_error_cycle(server *srv) {
14277 +int log_error_cycle(void) {
14278         /* only cycle if we are not in syslog-mode */
14279 -       
14280 -       if (srv->errorlog_mode == ERRORLOG_FILE) {
14281 -               const char *logfile = srv->srvconf.errorlog_file->ptr;
14282 +
14283 +       errorlog *err = myconfig;
14284 +
14285 +       if (err->mode == ERRORLOG_FILE) {
14286 +               buffer *file = err->file;
14287                 /* already check of opening time */
14288 -               
14289 +
14290                 int new_fd;
14291 -               
14292 -               if (-1 == (new_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14293 +
14294 +               if (-1 == (new_fd = open(file->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14295                         /* write to old log */
14296 -                       log_error_write(srv, __FILE__, __LINE__, "SSSSS", 
14297 -                                       "cycling errorlog '", logfile,
14298 +                       log_error_write(NULL, __FILE__, __LINE__, "SBSSS",
14299 +                                       "cycling errorlog '", file,
14300                                         "' failed: ", strerror(errno),
14301                                         ", falling back to syslog()");
14302 -                       
14303 -                       close(srv->errorlog_fd);
14304 -                       srv->errorlog_fd = -1;
14305 -#ifdef HAVE_SYSLOG_H   
14306 -                       srv->errorlog_mode = ERRORLOG_SYSLOG;
14307 +
14308 +                       close(err->fd);
14309 +                       err->fd = -1;
14310 +#ifdef HAVE_SYSLOG_H
14311 +                       err->mode = ERRORLOG_SYSLOG;
14312  #endif
14313                 } else {
14314                         /* ok, new log is open, close the old one */
14315 -                       close(srv->errorlog_fd);
14316 -                       srv->errorlog_fd = new_fd;
14317 +                       close(err->fd);
14318 +                       err->fd = new_fd;
14319                 }
14320         }
14321 -       
14322 -       log_error_write(srv, __FILE__, __LINE__, "s", "logfiles cycled");
14323 -       
14324 -       return 0;
14325 -}
14326  
14327 -int log_error_close(server *srv) {
14328 -       log_error_write(srv, __FILE__, __LINE__, "s", "server stopped");
14329 -       
14330 -       switch(srv->errorlog_mode) {
14331 -       case ERRORLOG_FILE:
14332 -               close(srv->errorlog_fd);
14333 -               break;
14334 -       case ERRORLOG_SYSLOG:
14335 -#ifdef HAVE_SYSLOG_H
14336 -               closelog();
14337 -#endif
14338 -               break;
14339 -       case ERRORLOG_STDERR:
14340 -               break;
14341 -       }
14342 -       
14343 +       TRACE("%s", "logfiles cycled");
14344 +
14345         return 0;
14346  }
14347  
14348 -int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...) {
14349 +int log_error_write(void *srv, const char *filename, unsigned int line, const char *fmt, ...) {
14350         va_list ap;
14351 -       
14352 -       switch(srv->errorlog_mode) {
14353 +       time_t t;
14354 +
14355 +       errorlog *err = myconfig;
14356 +
14357 +       switch(err->mode) {
14358         case ERRORLOG_FILE:
14359         case ERRORLOG_STDERR:
14360                 /* cache the generated timestamp */
14361 -               if (srv->cur_ts != srv->last_generated_debug_ts) {
14362 -                       buffer_prepare_copy(srv->ts_debug_str, 255);
14363 -                       strftime(srv->ts_debug_str->ptr, srv->ts_debug_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts)));
14364 -                       srv->ts_debug_str->used = strlen(srv->ts_debug_str->ptr) + 1;
14365 -                       
14366 -                       srv->last_generated_debug_ts = srv->cur_ts;
14367 +               t = time(NULL);
14368 +               
14369 +               if (t != err->cached_ts) {
14370 +                       buffer_prepare_copy(err->cached_ts_str, 255);
14371 +                       strftime(err->cached_ts_str->ptr, err->cached_ts_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(t)));
14372 +                       err->cached_ts_str->used = strlen(err->cached_ts_str->ptr) + 1;
14373 +                       err->cached_ts = t;
14374                 }
14375  
14376 -               buffer_copy_string_buffer(srv->errorlog_buf, srv->ts_debug_str);
14377 -               BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ": (");
14378 +               buffer_copy_string_buffer(err->buf, err->cached_ts_str);
14379 +               BUFFER_APPEND_STRING_CONST(err->buf, ": (");
14380                 break;
14381         case ERRORLOG_SYSLOG:
14382                 /* syslog is generating its own timestamps */
14383 -               BUFFER_COPY_STRING_CONST(srv->errorlog_buf, "(");
14384 +               BUFFER_COPY_STRING_CONST(err->buf, "(");
14385                 break;
14386         }
14387 -       
14388 -       buffer_append_string(srv->errorlog_buf, filename);
14389 -       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ".");
14390 -       buffer_append_long(srv->errorlog_buf, line);
14391 -       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ") ");
14392 -       
14393 -       
14394 +
14395 +       buffer_append_string(err->buf, filename);
14396 +       BUFFER_APPEND_STRING_CONST(err->buf, ".");
14397 +       buffer_append_long(err->buf, line);
14398 +       BUFFER_APPEND_STRING_CONST(err->buf, ") ");
14399 +
14400         for(va_start(ap, fmt); *fmt; fmt++) {
14401                 int d;
14402                 char *s;
14403                 buffer *b;
14404                 off_t o;
14405 -               
14406 +
14407                 switch(*fmt) {
14408                 case 's':           /* string */
14409                         s = va_arg(ap, char *);
14410 -                       buffer_append_string(srv->errorlog_buf, s);
14411 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14412 +                       buffer_append_string(err->buf, s);
14413 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
14414                         break;
14415                 case 'b':           /* buffer */
14416                         b = va_arg(ap, buffer *);
14417 -                       buffer_append_string_buffer(srv->errorlog_buf, b);
14418 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14419 +                       buffer_append_string_buffer(err->buf, b);
14420 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
14421                         break;
14422                 case 'd':           /* int */
14423                         d = va_arg(ap, int);
14424 -                       buffer_append_long(srv->errorlog_buf, d);
14425 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14426 +                       buffer_append_long(err->buf, d);
14427 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
14428                         break;
14429                 case 'o':           /* off_t */
14430                         o = va_arg(ap, off_t);
14431 -                       buffer_append_off_t(srv->errorlog_buf, o);
14432 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14433 +                       buffer_append_off_t(err->buf, o);
14434 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
14435                         break;
14436                 case 'x':           /* int (hex) */
14437                         d = va_arg(ap, int);
14438 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "0x");
14439 -                       buffer_append_long_hex(srv->errorlog_buf, d);
14440 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14441 +                       BUFFER_APPEND_STRING_CONST(err->buf, "0x");
14442 +                       buffer_append_long_hex(err->buf, d);
14443 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
14444                         break;
14445                 case 'S':           /* string */
14446                         s = va_arg(ap, char *);
14447 -                       buffer_append_string(srv->errorlog_buf, s);
14448 +                       buffer_append_string(err->buf, s);
14449                         break;
14450                 case 'B':           /* buffer */
14451                         b = va_arg(ap, buffer *);
14452 -                       buffer_append_string_buffer(srv->errorlog_buf, b);
14453 +                       buffer_append_string_buffer(err->buf, b);
14454                         break;
14455                 case 'D':           /* int */
14456                         d = va_arg(ap, int);
14457 -                       buffer_append_long(srv->errorlog_buf, d);
14458 +                       buffer_append_long(err->buf, d);
14459                         break;
14460                 case '(':
14461                 case ')':
14462 -               case '<':       
14463 +               case '<':
14464                 case '>':
14465                 case ',':
14466                 case ' ':
14467 -                       buffer_append_string_len(srv->errorlog_buf, fmt, 1);
14468 +                       buffer_append_string_len(err->buf, fmt, 1);
14469                         break;
14470                 }
14471         }
14472         va_end(ap);
14473 -       
14474 -       switch(srv->errorlog_mode) {
14475 +
14476 +       switch(err->mode) {
14477         case ERRORLOG_FILE:
14478 -               BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "\n");
14479 -               write(srv->errorlog_fd, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1);
14480 +               BUFFER_APPEND_STRING_CONST(err->buf, "\n");
14481 +               write(err->fd, err->buf->ptr, err->buf->used - 1);
14482                 break;
14483         case ERRORLOG_STDERR:
14484 -               BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "\n");
14485 -               write(STDERR_FILENO, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1);
14486 +               BUFFER_APPEND_STRING_CONST(err->buf, "\n");
14487 +               write(STDERR_FILENO, err->buf->ptr, err->buf->used - 1);
14488                 break;
14489 +#ifdef HAVE_SYSLOG_H
14490 +       case ERRORLOG_SYSLOG:
14491 +               syslog(LOG_ERR, "%s", err->buf->ptr);
14492 +               break;
14493 +#endif
14494 +       }
14495 +
14496 +       return 0;
14497 +}
14498 +
14499 +static int log_trace_write(const char *fmt, va_list ap) {
14500 +       buffer *b;
14501 +       int l;
14502 +       errorlog *err = myconfig;
14503 +       
14504 +       b = buffer_init();
14505 +       buffer_prepare_copy(b, 1024);
14506 +       l = vsnprintf(b->ptr, b->size - 1, fmt, ap);
14507 +       if (l > 0) {
14508 +               b->used = (l > b->size - 1) ? b->size : l + 1;
14509 +       }
14510 +
14511 +       /* write b */
14512 +       switch(err->mode) {
14513 +       case ERRORLOG_FILE:
14514 +               buffer_append_string(b, "\r\n");
14515 +               write(err->fd, b->ptr, b->used - 1);
14516 +               break;
14517 +       case ERRORLOG_STDERR:
14518 +               buffer_append_string(b, "\r\n");
14519 +               write(STDERR_FILENO, b->ptr, b->used - 1);
14520 +               break;
14521 +#ifdef HAVE_SYSLOG_H
14522         case ERRORLOG_SYSLOG:
14523 -               syslog(LOG_ERR, "%s", srv->errorlog_buf->ptr);
14524 +               syslog(LOG_ERR, "%s", b->ptr);
14525                 break;
14526 +#endif
14527         }
14528         
14529 +       buffer_free(b);
14530 +
14531 +       return 0;
14532 +}
14533 +
14534 +int log_trace(const char *fmt, ...) {
14535 +       va_list ap;
14536 +
14537 +       va_start(ap, fmt);
14538 +
14539 +       log_trace_write(fmt, ap);
14540 +
14541 +       va_end(ap);
14542 +
14543         return 0;
14544  }
14545  
14546 +
14547 --- ../lighttpd-1.4.11/src/log.h        2005-08-11 01:26:36.000000000 +0300
14548 +++ lighttpd-1.4.12/src/log.h   2006-07-18 13:03:40.000000000 +0300
14549 @@ -1,13 +1,22 @@
14550  #ifndef _LOG_H_
14551  #define _LOG_H_
14552  
14553 -#include "server.h"
14554 +#include "buffer.h"
14555  
14556 -#define WP() log_error_write(srv, __FILE__, __LINE__, "");
14557 +void log_init(void); 
14558 +void log_free(void); 
14559  
14560 -int log_error_open(server *srv);
14561 -int log_error_close(server *srv);
14562 -int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...);
14563 -int log_error_cycle(server *srv);
14564 -       
14565 +int log_error_open(buffer *file, int use_syslog);
14566 +int log_error_close();
14567 +int log_error_write(void *srv, const char *filename, unsigned int line, const char *fmt, ...);
14568 +int log_error_cycle();
14569 +
14570 +#define ERROR(fmt, ...) \
14571 +       log_trace("%s.%d: (error) "fmt, __FILE__, __LINE__, __VA_ARGS__)
14572 +
14573 +#define TRACE(fmt, ...) \
14574 +       log_trace("%s.%d: (trace) "fmt, __FILE__, __LINE__, __VA_ARGS__)
14575 +
14576 +#define SEGFAULT() do { ERROR("%s", "Ooh, Ooh, Ooh. Something is not good ... going down"); abort(); } while(0)
14577 +int log_trace(const char *fmt, ...);
14578  #endif
14579 --- ../lighttpd-1.4.11/src/md5.h        2005-11-17 16:20:40.000000000 +0200
14580 +++ lighttpd-1.4.12/src/md5.h   2006-07-16 00:26:04.000000000 +0300
14581 @@ -30,9 +30,15 @@
14582  # include <inttypes.h>
14583  #endif
14584  
14585 +#ifdef _WIN32
14586 +#define UINT4 unsigned __int32
14587 +#define UINT2 unsigned __int16
14588 +#define POINTER unsigned char *
14589 +#else
14590  #define UINT4 uint32_t
14591  #define UINT2 uint16_t
14592  #define POINTER unsigned char *
14593 +#endif
14594  
14595  /* MD5 context. */
14596  typedef struct {
14597 --- ../lighttpd-1.4.11/src/mod_access.c 2006-01-14 19:44:54.000000000 +0200
14598 +++ lighttpd-1.4.12/src/mod_access.c    2006-07-16 00:26:04.000000000 +0300
14599 @@ -8,126 +8,125 @@
14600  
14601  #include "plugin.h"
14602  
14603 +#include "sys-strings.h"
14604 +
14605  typedef struct {
14606         array *access_deny;
14607  } plugin_config;
14608  
14609  typedef struct {
14610         PLUGIN_DATA;
14611 -       
14612 +
14613         plugin_config **config_storage;
14614 -       
14615 -       plugin_config conf; 
14616 +
14617 +       plugin_config conf;
14618  } plugin_data;
14619  
14620  INIT_FUNC(mod_access_init) {
14621         plugin_data *p;
14622 -       
14623 +
14624         p = calloc(1, sizeof(*p));
14625 -       
14626 +
14627         return p;
14628  }
14629  
14630  FREE_FUNC(mod_access_free) {
14631         plugin_data *p = p_d;
14632 -       
14633 +
14634         UNUSED(srv);
14635  
14636         if (!p) return HANDLER_GO_ON;
14637 -       
14638 +
14639         if (p->config_storage) {
14640                 size_t i;
14641                 for (i = 0; i < srv->config_context->used; i++) {
14642                         plugin_config *s = p->config_storage[i];
14643 -                       
14644 +
14645                         array_free(s->access_deny);
14646 -                       
14647 +
14648                         free(s);
14649                 }
14650                 free(p->config_storage);
14651         }
14652 -       
14653 +
14654         free(p);
14655 -       
14656 +
14657         return HANDLER_GO_ON;
14658  }
14659  
14660  SETDEFAULTS_FUNC(mod_access_set_defaults) {
14661         plugin_data *p = p_d;
14662         size_t i = 0;
14663 -       
14664 -       config_values_t cv[] = { 
14665 +
14666 +       config_values_t cv[] = {
14667                 { "url.access-deny",             NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
14668                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
14669         };
14670 -       
14671 +
14672         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
14673 -       
14674 +
14675         for (i = 0; i < srv->config_context->used; i++) {
14676                 plugin_config *s;
14677 -               
14678 +
14679                 s = calloc(1, sizeof(plugin_config));
14680                 s->access_deny    = array_init();
14681 -               
14682 +
14683                 cv[0].destination = s->access_deny;
14684 -               
14685 +
14686                 p->config_storage[i] = s;
14687 -       
14688 +
14689                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
14690                         return HANDLER_ERROR;
14691                 }
14692         }
14693 -       
14694 +
14695         return HANDLER_GO_ON;
14696  }
14697  
14698 -#define PATCH(x) \
14699 -       p->conf.x = s->x;
14700  static int mod_access_patch_connection(server *srv, connection *con, plugin_data *p) {
14701         size_t i, j;
14702         plugin_config *s = p->config_storage[0];
14703  
14704 -       PATCH(access_deny);
14705 -       
14706 +       PATCH_OPTION(access_deny);
14707 +
14708         /* skip the first, the global context */
14709         for (i = 1; i < srv->config_context->used; i++) {
14710                 data_config *dc = (data_config *)srv->config_context->data[i];
14711                 s = p->config_storage[i];
14712 -               
14713 +
14714                 /* condition didn't match */
14715                 if (!config_check_cond(srv, con, dc)) continue;
14716 -               
14717 +
14718                 /* merge config */
14719                 for (j = 0; j < dc->value->used; j++) {
14720                         data_unset *du = dc->value->data[j];
14721 -                       
14722 +
14723                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.access-deny"))) {
14724 -                               PATCH(access_deny);
14725 +                               PATCH_OPTION(access_deny);
14726                         }
14727                 }
14728         }
14729 -       
14730 +
14731         return 0;
14732  }
14733 -#undef PATCH
14734  
14735  URIHANDLER_FUNC(mod_access_uri_handler) {
14736         plugin_data *p = p_d;
14737         int s_len;
14738         size_t k;
14739 -       
14740 +
14741         if (con->uri.path->used == 0) return HANDLER_GO_ON;
14742 -       
14743 +
14744         mod_access_patch_connection(srv, con, p);
14745 -       
14746 +
14747         s_len = con->uri.path->used - 1;
14748 -       
14749 +
14750         for (k = 0; k < p->conf.access_deny->used; k++) {
14751                 data_string *ds = (data_string *)p->conf.access_deny->data[k];
14752                 int ct_len = ds->value->used - 1;
14753 -               
14754 +
14755                 if (ct_len > s_len) continue;
14756 -               
14757 +
14758                 if (ds->value->used == 0) continue;
14759  
14760                 /* if we have a case-insensitive FS we have to lower-case the URI here too */
14761 @@ -135,18 +134,18 @@
14762                 if (con->conf.force_lowercase_filenames) {
14763                         if (0 == strncasecmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
14764                                 con->http_status = 403;
14765 -                       
14766 +
14767                                 return HANDLER_FINISHED;
14768                         }
14769                 } else {
14770                         if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
14771                                 con->http_status = 403;
14772 -                       
14773 +
14774                                 return HANDLER_FINISHED;
14775                         }
14776                 }
14777         }
14778 -       
14779 +
14780         /* not found */
14781         return HANDLER_GO_ON;
14782  }
14783 @@ -155,13 +154,13 @@
14784  int mod_access_plugin_init(plugin *p) {
14785         p->version     = LIGHTTPD_VERSION_ID;
14786         p->name        = buffer_init_string("access");
14787 -       
14788 +
14789         p->init        = mod_access_init;
14790         p->set_defaults = mod_access_set_defaults;
14791         p->handle_uri_clean  = mod_access_uri_handler;
14792         p->cleanup     = mod_access_free;
14793 -       
14794 +
14795         p->data        = NULL;
14796 -       
14797 +
14798         return 0;
14799  }
14800 --- ../lighttpd-1.4.11/src/mod_accesslog.c      2006-01-31 14:01:43.000000000 +0200
14801 +++ lighttpd-1.4.12/src/mod_accesslog.c 2006-07-16 00:26:04.000000000 +0300
14802 @@ -6,8 +6,7 @@
14803  #include <ctype.h>
14804  #include <stdlib.h>
14805  #include <string.h>
14806 -#include <fcntl.h>
14807 -#include <unistd.h>
14808 +#include <fcntl.h> /* only the defines on windows */
14809  #include <errno.h>
14810  #include <time.h>
14811  
14812 @@ -22,6 +21,7 @@
14813  #include "inet_ntop_cache.h"
14814  
14815  #include "sys-socket.h"
14816 +#include "sys-files.h"
14817  
14818  #ifdef HAVE_SYSLOG_H
14819  # include <syslog.h>
14820 @@ -29,7 +29,7 @@
14821  
14822  typedef struct {
14823         char key;
14824 -       enum { 
14825 +       enum {
14826                 FORMAT_UNSET,
14827                         FORMAT_UNSUPPORTED,
14828                         FORMAT_PERCENT,
14829 @@ -41,7 +41,7 @@
14830                         FORMAT_STATUS,
14831                         FORMAT_BYTES_OUT_NO_HEADER,
14832                         FORMAT_HEADER,
14833 -                       
14834 +
14835                         FORMAT_REMOTE_ADDR,
14836                         FORMAT_LOCAL_ADDR,
14837                         FORMAT_COOKIE,
14838 @@ -59,20 +59,20 @@
14839                         FORMAT_CONNECTION_STATUS,
14840                         FORMAT_BYTES_IN,
14841                         FORMAT_BYTES_OUT,
14842 -                       
14843 +
14844                         FORMAT_RESPONSE_HEADER
14845         } type;
14846  } format_mapping;
14847  
14848  /**
14849 - * 
14850 - * 
14851 + *
14852 + *
14853   * "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
14854 - * 
14855 + *
14856   */
14857  
14858 -const format_mapping fmap[] = 
14859 -{ 
14860 +const format_mapping fmap[] =
14861 +{
14862         { '%', FORMAT_PERCENT },
14863         { 'h', FORMAT_REMOTE_HOST },
14864         { 'l', FORMAT_REMOTE_IDENT },
14865 @@ -82,7 +82,7 @@
14866         { 's', FORMAT_STATUS },
14867         { 'b', FORMAT_BYTES_OUT_NO_HEADER },
14868         { 'i', FORMAT_HEADER },
14869 -       
14870 +
14871         { 'a', FORMAT_REMOTE_ADDR },
14872         { 'A', FORMAT_LOCAL_ADDR },
14873         { 'B', FORMAT_BYTES_OUT_NO_HEADER },
14874 @@ -103,23 +103,23 @@
14875         { 'X', FORMAT_CONNECTION_STATUS },
14876         { 'I', FORMAT_BYTES_IN },
14877         { 'O', FORMAT_BYTES_OUT },
14878 -       
14879 +
14880         { 'o', FORMAT_RESPONSE_HEADER },
14881 -       
14882 +
14883         { '\0', FORMAT_UNSET }
14884  };
14885  
14886  
14887  typedef struct {
14888         enum { FIELD_UNSET, FIELD_STRING, FIELD_FORMAT } type;
14889 -       
14890 +
14891         buffer *string;
14892         int field;
14893  } format_field;
14894  
14895  typedef struct {
14896         format_field **ptr;
14897 -       
14898 +
14899         size_t used;
14900         size_t size;
14901  } format_fields;
14902 @@ -128,39 +128,39 @@
14903         buffer *access_logfile;
14904         buffer *format;
14905         unsigned short use_syslog;
14906 -       
14907 -       
14908 +
14909 +
14910         int    log_access_fd;
14911         time_t last_generated_accesslog_ts;
14912         time_t *last_generated_accesslog_ts_ptr;
14913 -       
14914 -       
14915 +
14916 +
14917         buffer *access_logbuffer;
14918         buffer *ts_accesslog_str;
14919 -       
14920 +
14921         format_fields *parsed_format;
14922  } plugin_config;
14923  
14924  typedef struct {
14925         PLUGIN_DATA;
14926 -       
14927 +
14928         plugin_config **config_storage;
14929 -       plugin_config conf; 
14930 +       plugin_config conf;
14931  } plugin_data;
14932  
14933  INIT_FUNC(mod_accesslog_init) {
14934         plugin_data *p;
14935 -       
14936 +
14937         p = calloc(1, sizeof(*p));
14938 -       
14939 +
14940         return p;
14941  }
14942  
14943  int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) {
14944         size_t i, j, k = 0, start = 0;
14945 -       
14946 +
14947         for (i = 0; i < format->used - 1; i++) {
14948 -               
14949 +
14950                 switch(format->ptr[i]) {
14951                 case '%':
14952                         if (start != i) {
14953 @@ -173,19 +173,19 @@
14954                                         fields->size += 16;
14955                                         fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
14956                                 }
14957 -                               
14958 +
14959                                 fields->ptr[fields->used] = malloc(sizeof(format_fields));
14960                                 fields->ptr[fields->used]->type = FIELD_STRING;
14961                                 fields->ptr[fields->used]->string = buffer_init();
14962 -                               
14963 +
14964                                 buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
14965 -                               
14966 +
14967                                 fields->used++;
14968                         }
14969 -                       
14970 -                       
14971 +
14972 +
14973                         /* we need a new field */
14974 -                       
14975 +
14976                         if (fields->size == 0) {
14977                                 fields->size = 16;
14978                                 fields->used = 0;
14979 @@ -194,43 +194,43 @@
14980                                 fields->size += 16;
14981                                 fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
14982                         }
14983 -                       
14984 +
14985                         /* search for the terminating command */
14986                         switch (format->ptr[i+1]) {
14987                         case '>':
14988                         case '<':
14989                                 /* only for s */
14990 -                               
14991 +
14992                                 for (j = 0; fmap[j].key != '\0'; j++) {
14993                                         if (fmap[j].key != format->ptr[i+2]) continue;
14994 -                                       
14995 +
14996                                         /* found key */
14997 -                                               
14998 +
14999                                         fields->ptr[fields->used] = malloc(sizeof(format_fields));
15000                                         fields->ptr[fields->used]->type = FIELD_FORMAT;
15001                                         fields->ptr[fields->used]->field = fmap[j].type;
15002                                         fields->ptr[fields->used]->string = NULL;
15003 -                                       
15004 +
15005                                         fields->used++;
15006 -                                       
15007 +
15008                                         break;
15009                                 }
15010 -                               
15011 +
15012                                 if (fmap[j].key == '\0') {
15013                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15014                                         return -1;
15015                                 }
15016 -                               
15017 +
15018                                 start = i + 3;
15019 -                               
15020 +
15021                                 break;
15022                         case '{':
15023                                 /* go forward to } */
15024 -                               
15025 +
15026                                 for (k = i+2; k < format->used - 1; k++) {
15027                                         if (format->ptr[k] == '}') break;
15028                                 }
15029 -                               
15030 +
15031                                 if (k == format->used - 1) {
15032                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15033                                         return -1;
15034 @@ -239,62 +239,62 @@
15035                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15036                                         return -1;
15037                                 }
15038 -                               
15039 +
15040                                 for (j = 0; fmap[j].key != '\0'; j++) {
15041                                         if (fmap[j].key != format->ptr[k+1]) continue;
15042 -                                       
15043 +
15044                                         /* found key */
15045 -                                               
15046 +
15047                                         fields->ptr[fields->used] = malloc(sizeof(format_fields));
15048                                         fields->ptr[fields->used]->type = FIELD_FORMAT;
15049                                         fields->ptr[fields->used]->field = fmap[j].type;
15050                                         fields->ptr[fields->used]->string = buffer_init();
15051 -                                       
15052 +
15053                                         buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + i + 2, k - (i + 2));
15054 -                                       
15055 +
15056                                         fields->used++;
15057 -                                       
15058 +
15059                                         break;
15060                                 }
15061 -                               
15062 +
15063                                 if (fmap[j].key == '\0') {
15064                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15065                                         return -1;
15066                                 }
15067 -                               
15068 +
15069                                 start = k + 2;
15070 -                               
15071 +
15072                                 break;
15073                         default:
15074                                 for (j = 0; fmap[j].key != '\0'; j++) {
15075                                         if (fmap[j].key != format->ptr[i+1]) continue;
15076 -                                       
15077 +
15078                                         /* found key */
15079 -                                               
15080 +
15081                                         fields->ptr[fields->used] = malloc(sizeof(format_fields));
15082                                         fields->ptr[fields->used]->type = FIELD_FORMAT;
15083                                         fields->ptr[fields->used]->field = fmap[j].type;
15084                                         fields->ptr[fields->used]->string = NULL;
15085 -                                       
15086 +
15087                                         fields->used++;
15088 -                                       
15089 +
15090                                         break;
15091                                 }
15092 -                               
15093 +
15094                                 if (fmap[j].key == '\0') {
15095                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15096                                         return -1;
15097                                 }
15098 -                               
15099 +
15100                                 start = i + 2;
15101 -                               
15102 +
15103                                 break;
15104                         }
15105 -                       
15106 +
15107                         break;
15108                 }
15109         }
15110 -       
15111 +
15112         if (start < i) {
15113                 /* copy the string */
15114                 if (fields->size == 0) {
15115 @@ -305,32 +305,32 @@
15116                         fields->size += 16;
15117                         fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
15118                 }
15119 -               
15120 +
15121                 fields->ptr[fields->used] = malloc(sizeof(format_fields));
15122                 fields->ptr[fields->used]->type = FIELD_STRING;
15123                 fields->ptr[fields->used]->string = buffer_init();
15124 -               
15125 +
15126                 buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
15127 -               
15128 +
15129                 fields->used++;
15130         }
15131 -       
15132 +
15133         return 0;
15134  }
15135  
15136  FREE_FUNC(mod_accesslog_free) {
15137         plugin_data *p = p_d;
15138         size_t i;
15139 -       
15140 +
15141         if (!p) return HANDLER_GO_ON;
15142 -       
15143 +
15144         if (p->config_storage) {
15145 -               
15146 +
15147                 for (i = 0; i < srv->config_context->used; i++) {
15148                         plugin_config *s = p->config_storage[i];
15149  
15150                         if (!s) continue;
15151 -                       
15152 +
15153                         if (s->access_logbuffer->used) {
15154                                 if (s->use_syslog) {
15155  # ifdef HAVE_SYSLOG_H
15156 @@ -342,14 +342,14 @@
15157                                         write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
15158                                 }
15159                         }
15160 -                       
15161 +
15162                         if (s->log_access_fd != -1) close(s->log_access_fd);
15163 -                       
15164 +
15165                         buffer_free(s->ts_accesslog_str);
15166                         buffer_free(s->access_logbuffer);
15167                         buffer_free(s->format);
15168                         buffer_free(s->access_logfile);
15169 -                       
15170 +
15171                         if (s->parsed_format) {
15172                                 size_t j;
15173                                 for (j = 0; j < s->parsed_format->used; j++) {
15174 @@ -359,36 +359,36 @@
15175                                 free(s->parsed_format->ptr);
15176                                 free(s->parsed_format);
15177                         }
15178 -                       
15179 +
15180                         free(s);
15181                 }
15182 -       
15183 +
15184                 free(p->config_storage);
15185         }
15186 -       
15187 +
15188         free(p);
15189 -       
15190 +
15191         return HANDLER_GO_ON;
15192  }
15193  
15194  SETDEFAULTS_FUNC(log_access_open) {
15195         plugin_data *p = p_d;
15196         size_t i = 0;
15197 -       
15198 -       config_values_t cv[] = { 
15199 +
15200 +       config_values_t cv[] = {
15201                 { "accesslog.filename",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
15202                 { "accesslog.use-syslog",           NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
15203                 { "accesslog.format",               NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
15204                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
15205         };
15206 -       
15207 +
15208         if (!p) return HANDLER_ERROR;
15209 -       
15210 +
15211         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
15212 -       
15213 +
15214         for (i = 0; i < srv->config_context->used; i++) {
15215                 plugin_config *s;
15216 -               
15217 +
15218                 s = calloc(1, sizeof(plugin_config));
15219                 s->access_logfile = buffer_init();
15220                 s->format = buffer_init();
15221 @@ -397,44 +397,44 @@
15222                 s->log_access_fd = -1;
15223                 s->last_generated_accesslog_ts = 0;
15224                 s->last_generated_accesslog_ts_ptr = &(s->last_generated_accesslog_ts);
15225 -               
15226 -       
15227 +
15228 +
15229                 cv[0].destination = s->access_logfile;
15230                 cv[1].destination = &(s->use_syslog);
15231                 cv[2].destination = s->format;
15232 -       
15233 +
15234                 p->config_storage[i] = s;
15235 -               
15236 +
15237                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
15238                         return HANDLER_ERROR;
15239                 }
15240 -               
15241 +
15242                 if (i == 0 && buffer_is_empty(s->format)) {
15243                         /* set a default logfile string */
15244 -                       
15245 +
15246                         buffer_copy_string(s->format, "%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"");
15247                 }
15248 -               
15249 +
15250                 /* parse */
15251 -               
15252 +
15253                 if (s->format->used) {
15254                         s->parsed_format = calloc(1, sizeof(*(s->parsed_format)));
15255 -                       
15256 +
15257                         if (-1 == accesslog_parse_format(srv, s->parsed_format, s->format)) {
15258  
15259 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
15260 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
15261                                                 "parsing accesslog-definition failed:", s->format);
15262  
15263                                 return HANDLER_ERROR;
15264                         }
15265  #if 0
15266 -                       /* debugging */                 
15267 +                       /* debugging */
15268                         for (j = 0; j < s->parsed_format->used; j++) {
15269                                 switch (s->parsed_format->ptr[j]->type) {
15270                                 case FIELD_FORMAT:
15271 -                                       log_error_write(srv, __FILE__, __LINE__, "ssds", 
15272 +                                       log_error_write(srv, __FILE__, __LINE__, "ssds",
15273                                                         "config:", "format", s->parsed_format->ptr[j]->field,
15274 -                                                       s->parsed_format->ptr[j]->string ? 
15275 +                                                       s->parsed_format->ptr[j]->string ?
15276                                                         s->parsed_format->ptr[j]->string->ptr : "" );
15277                                         break;
15278                                 case FIELD_STRING:
15279 @@ -446,52 +446,52 @@
15280                         }
15281  #endif
15282                 }
15283 -               
15284 +
15285                 if (s->use_syslog) {
15286                         /* ignore the next checks */
15287                         continue;
15288                 }
15289 -               
15290 +
15291                 if (buffer_is_empty(s->access_logfile)) continue;
15292 -               
15293 +
15294                 if (s->access_logfile->ptr[0] == '|') {
15295  #ifdef HAVE_FORK
15296                         /* create write pipe and spawn process */
15297 -                       
15298 +
15299                         int to_log_fds[2];
15300                         pid_t pid;
15301 -                       
15302 +
15303                         if (pipe(to_log_fds)) {
15304                                 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed: ", strerror(errno));
15305                                 return HANDLER_ERROR;
15306                         }
15307 -                       
15308 +
15309                         /* fork, execve */
15310                         switch (pid = fork()) {
15311 -                       case 0: 
15312 +                       case 0:
15313                                 /* child */
15314 -                               
15315 +
15316                                 close(STDIN_FILENO);
15317                                 dup2(to_log_fds[0], STDIN_FILENO);
15318                                 close(to_log_fds[0]);
15319                                 /* not needed */
15320                                 close(to_log_fds[1]);
15321 -                               
15322 +
15323                                 /* we don't need the client socket */
15324                                 for (i = 3; i < 256; i++) {
15325                                         close(i);
15326                                 }
15327 -                               
15328 -                               /* exec the log-process (skip the | ) 
15329 -                                * 
15330 +
15331 +                               /* exec the log-process (skip the | )
15332 +                                *
15333                                  */
15334 -                               
15335 +
15336                                 execl("/bin/sh", "sh", "-c", s->access_logfile->ptr + 1, NULL);
15337  
15338 -                               log_error_write(srv, __FILE__, __LINE__, "sss", 
15339 -                                               "spawning log-process failed: ", strerror(errno), 
15340 +                               log_error_write(srv, __FILE__, __LINE__, "sss",
15341 +                                               "spawning log-process failed: ", strerror(errno),
15342                                                 s->access_logfile->ptr + 1);
15343 -                               
15344 +
15345                                 exit(-1);
15346                                 break;
15347                         case -1:
15348 @@ -500,27 +500,28 @@
15349                                 break;
15350                         default:
15351                                 close(to_log_fds[0]);
15352 -                               
15353 +
15354                                 s->log_access_fd = to_log_fds[1];
15355 -                               
15356 +
15357                                 break;
15358                         }
15359  #else
15360                         return -1;
15361  #endif
15362 -               } else if (-1 == (s->log_access_fd = 
15363 +               } else if (-1 == (s->log_access_fd =
15364                                   open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
15365 -                       
15366 -                       log_error_write(srv, __FILE__, __LINE__, "ssb", 
15367 -                                       "opening access-log failed:", 
15368 +
15369 +                       log_error_write(srv, __FILE__, __LINE__, "ssb",
15370 +                                       "opening access-log failed:",
15371                                         strerror(errno), s->access_logfile);
15372 -                       
15373 +
15374                         return HANDLER_ERROR;
15375                 }
15376 +#ifndef _WIN32
15377                 fcntl(s->log_access_fd, F_SETFD, FD_CLOEXEC);
15378 -       
15379 +#endif
15380         }
15381 -       
15382 +
15383         return HANDLER_GO_ON;
15384  }
15385  
15386 @@ -529,7 +530,7 @@
15387         size_t i;
15388  
15389         if (!p->config_storage) return HANDLER_GO_ON;
15390 -               
15391 +
15392         for (i = 0; i < srv->config_context->used; i++) {
15393                 plugin_config *s = p->config_storage[i];
15394  
15395 @@ -544,90 +545,87 @@
15396                         } else if (s->log_access_fd != -1) {
15397                                 write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
15398                         }
15399 -                       
15400 +
15401                         buffer_reset(s->access_logbuffer);
15402                 }
15403 -               
15404 +
15405                 if (s->use_syslog == 0 &&
15406                     !buffer_is_empty(s->access_logfile) &&
15407                     s->access_logfile->ptr[0] != '|') {
15408 -                       
15409 +
15410                         close(s->log_access_fd);
15411 -                       
15412 -                       if (-1 == (s->log_access_fd = 
15413 +
15414 +                       if (-1 == (s->log_access_fd =
15415                                    open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
15416 -                               
15417 +
15418                                 log_error_write(srv, __FILE__, __LINE__, "ss", "cycling access-log failed:", strerror(errno));
15419 -                               
15420 +
15421                                 return HANDLER_ERROR;
15422                         }
15423                 }
15424         }
15425 -       
15426 +
15427         return HANDLER_GO_ON;
15428  }
15429  
15430 -#define PATCH(x) \
15431 -       p->conf.x = s->x;
15432  static int mod_accesslog_patch_connection(server *srv, connection *con, plugin_data *p) {
15433         size_t i, j;
15434         plugin_config *s = p->config_storage[0];
15435 -       
15436 -       PATCH(access_logfile);
15437 -       PATCH(format);
15438 -       PATCH(log_access_fd);
15439 -       PATCH(last_generated_accesslog_ts_ptr);
15440 -       PATCH(access_logbuffer);
15441 -       PATCH(ts_accesslog_str);
15442 -       PATCH(parsed_format);
15443 -       PATCH(use_syslog);
15444 -       
15445 +
15446 +       PATCH_OPTION(access_logfile);
15447 +       PATCH_OPTION(format);
15448 +       PATCH_OPTION(log_access_fd);
15449 +       PATCH_OPTION(last_generated_accesslog_ts_ptr);
15450 +       PATCH_OPTION(access_logbuffer);
15451 +       PATCH_OPTION(ts_accesslog_str);
15452 +       PATCH_OPTION(parsed_format);
15453 +       PATCH_OPTION(use_syslog);
15454 +
15455         /* skip the first, the global context */
15456         for (i = 1; i < srv->config_context->used; i++) {
15457                 data_config *dc = (data_config *)srv->config_context->data[i];
15458                 s = p->config_storage[i];
15459 -               
15460 +
15461                 /* condition didn't match */
15462                 if (!config_check_cond(srv, con, dc)) continue;
15463 -               
15464 +
15465                 /* merge config */
15466                 for (j = 0; j < dc->value->used; j++) {
15467                         data_unset *du = dc->value->data[j];
15468 -                       
15469 +
15470                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.filename"))) {
15471 -                               PATCH(access_logfile);
15472 -                               PATCH(log_access_fd);
15473 -                               PATCH(last_generated_accesslog_ts_ptr);
15474 -                               PATCH(access_logbuffer);
15475 -                               PATCH(ts_accesslog_str);
15476 +                               PATCH_OPTION(access_logfile);
15477 +                               PATCH_OPTION(log_access_fd);
15478 +                               PATCH_OPTION(last_generated_accesslog_ts_ptr);
15479 +                               PATCH_OPTION(access_logbuffer);
15480 +                               PATCH_OPTION(ts_accesslog_str);
15481                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.format"))) {
15482 -                               PATCH(format);
15483 -                               PATCH(parsed_format);
15484 +                               PATCH_OPTION(format);
15485 +                               PATCH_OPTION(parsed_format);
15486                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.use-syslog"))) {
15487 -                               PATCH(use_syslog);
15488 +                               PATCH_OPTION(use_syslog);
15489                         }
15490                 }
15491         }
15492 -       
15493 +
15494         return 0;
15495  }
15496 -#undef PATCH
15497  
15498  REQUESTDONE_FUNC(log_access_write) {
15499         plugin_data *p = p_d;
15500         buffer *b;
15501         size_t j;
15502 -       
15503 +
15504         int newts = 0;
15505         data_string *ds;
15506 -       
15507 +
15508         mod_accesslog_patch_connection(srv, con, p);
15509 -       
15510 +
15511         b = p->conf.access_logbuffer;
15512         if (b->used == 0) {
15513                 buffer_copy_string(b, "");
15514         }
15515 -       
15516 +
15517         for (j = 0; j < p->conf.parsed_format->used; j++) {
15518                 switch(p->conf.parsed_format->ptr[j]->type) {
15519                 case FIELD_STRING:
15520 @@ -636,14 +634,14 @@
15521                 case FIELD_FORMAT:
15522                         switch(p->conf.parsed_format->ptr[j]->field) {
15523                         case FORMAT_TIMESTAMP:
15524 -                               
15525 +
15526                                 /* cache the generated timestamp */
15527                                 if (srv->cur_ts != *(p->conf.last_generated_accesslog_ts_ptr)) {
15528                                         struct tm tm;
15529  #if defined(HAVE_STRUCT_TM_GMTOFF)
15530                                         long scd, hrs, min;
15531  #endif
15532 -               
15533 +
15534                                         buffer_prepare_copy(p->conf.ts_accesslog_str, 255);
15535  #if defined(HAVE_STRUCT_TM_GMTOFF)
15536  # ifdef HAVE_LOCALTIME_R
15537 @@ -653,17 +651,17 @@
15538                                         strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, "[%d/%b/%Y:%H:%M:%S ", localtime_r(&(srv->cur_ts)));
15539  # endif
15540                                         p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
15541 -                                       
15542 +
15543                                         buffer_append_string(p->conf.ts_accesslog_str, tm.tm_gmtoff >= 0 ? "+" : "-");
15544 -                                       
15545 +
15546                                         scd = abs(tm.tm_gmtoff);
15547                                         hrs = scd / 3600;
15548                                         min = (scd % 3600) / 60;
15549 -                                       
15550 +
15551                                         /* hours */
15552                                         if (hrs < 10) buffer_append_string(p->conf.ts_accesslog_str, "0");
15553                                         buffer_append_long(p->conf.ts_accesslog_str, hrs);
15554 -                                       
15555 +
15556                                         if (min < 10) buffer_append_string(p->conf.ts_accesslog_str, "0");
15557                                         buffer_append_long(p->conf.ts_accesslog_str, min);
15558                                         BUFFER_APPEND_STRING_CONST(p->conf.ts_accesslog_str, "]");
15559 @@ -676,20 +674,20 @@
15560  #endif
15561                                         p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
15562  #endif
15563 -                                       
15564 +
15565                                         *(p->conf.last_generated_accesslog_ts_ptr) = srv->cur_ts;
15566                                         newts = 1;
15567                                 }
15568 -                               
15569 +
15570                                 buffer_append_string_buffer(b, p->conf.ts_accesslog_str);
15571 -                               
15572 +
15573                                 break;
15574                         case FORMAT_REMOTE_HOST:
15575 -       
15576 +
15577                                 /* handle inet_ntop cache */
15578 -       
15579 +
15580                                 buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
15581 -                               
15582 +
15583                                 break;
15584                         case FORMAT_REMOTE_IDENT:
15585                                 /* ident */
15586 @@ -710,10 +708,10 @@
15587                         case FORMAT_STATUS:
15588                                 buffer_append_long(b, con->http_status);
15589                                 break;
15590 -       
15591 +
15592                         case FORMAT_BYTES_OUT_NO_HEADER:
15593                                 if (con->bytes_written > 0) {
15594 -                                       buffer_append_off_t(b, 
15595 +                                       buffer_append_off_t(b,
15596                                                             con->bytes_written - con->bytes_header <= 0 ? 0 : con->bytes_written - con->bytes_header);
15597                                 } else {
15598                                         BUFFER_APPEND_STRING_CONST(b, "-");
15599 @@ -772,7 +770,7 @@
15600                                 }
15601                                 break;
15602                         case FORMAT_REQUEST_PROTOCOL:
15603 -                               buffer_append_string(b, 
15604 +                               buffer_append_string(b,
15605                                                      con->request.http_version == HTTP_VERSION_1_1 ? "HTTP/1.1" : "HTTP/1.0");
15606                                 break;
15607                         case FORMAT_REQUEST_METHOD:
15608 @@ -801,7 +799,7 @@
15609                                  { 'D', FORMAT_TIME_USED_MS },
15610                                  { 'e', FORMAT_ENV },
15611                                  */
15612 -                               
15613 +
15614                                 break;
15615                         }
15616                         break;
15617 @@ -809,7 +807,7 @@
15618                         break;
15619                 }
15620         }
15621 -       
15622 +
15623         BUFFER_APPEND_STRING_CONST(b, "\n");
15624  
15625         if (p->conf.use_syslog ||  /* syslog doesn't cache */
15626 @@ -828,7 +826,7 @@
15627                 }
15628                 buffer_reset(b);
15629         }
15630 -       
15631 +
15632         return HANDLER_GO_ON;
15633  }
15634  
15635 @@ -836,15 +834,15 @@
15636  int mod_accesslog_plugin_init(plugin *p) {
15637         p->version     = LIGHTTPD_VERSION_ID;
15638         p->name        = buffer_init_string("accesslog");
15639 -       
15640 +
15641         p->init        = mod_accesslog_init;
15642         p->set_defaults= log_access_open;
15643         p->cleanup     = mod_accesslog_free;
15644 -       
15645 +
15646         p->handle_request_done  = log_access_write;
15647         p->handle_sighup        = log_access_cycle;
15648 -       
15649 +
15650         p->data        = NULL;
15651 -       
15652 +
15653         return 0;
15654  }
15655 --- ../lighttpd-1.4.11/src/mod_alias.c  2006-03-01 23:18:51.000000000 +0200
15656 +++ lighttpd-1.4.12/src/mod_alias.c     2006-07-16 00:26:03.000000000 +0300
15657 @@ -8,6 +8,7 @@
15658  #include "buffer.h"
15659  
15660  #include "plugin.h"
15661 +#include "sys-strings.h"
15662  
15663  /* plugin config for all request/connections */
15664  typedef struct {
15665 @@ -16,44 +17,44 @@
15666  
15667  typedef struct {
15668         PLUGIN_DATA;
15669 -       
15670 +
15671         plugin_config **config_storage;
15672 -       
15673 -       plugin_config conf; 
15674 +
15675 +       plugin_config conf;
15676  } plugin_data;
15677  
15678  /* init the plugin data */
15679  INIT_FUNC(mod_alias_init) {
15680         plugin_data *p;
15681 -       
15682 +
15683         p = calloc(1, sizeof(*p));
15684 -       
15685 -       
15686 -       
15687 +
15688 +
15689 +
15690         return p;
15691  }
15692  
15693  /* detroy the plugin data */
15694  FREE_FUNC(mod_alias_free) {
15695         plugin_data *p = p_d;
15696 -       
15697 +
15698         if (!p) return HANDLER_GO_ON;
15699 -       
15700 +
15701         if (p->config_storage) {
15702                 size_t i;
15703 -               
15704 +
15705                 for (i = 0; i < srv->config_context->used; i++) {
15706                         plugin_config *s = p->config_storage[i];
15707 -                       
15708 +
15709                         array_free(s->alias);
15710 -                       
15711 +
15712                         free(s);
15713                 }
15714                 free(p->config_storage);
15715         }
15716 -       
15717 +
15718         free(p);
15719 -       
15720 +
15721         return HANDLER_GO_ON;
15722  }
15723  
15724 @@ -62,25 +63,25 @@
15725  SETDEFAULTS_FUNC(mod_alias_set_defaults) {
15726         plugin_data *p = p_d;
15727         size_t i = 0;
15728 -       
15729 -       config_values_t cv[] = { 
15730 +
15731 +       config_values_t cv[] = {
15732                 { "alias.url",                  NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
15733                 { NULL,                         NULL, T_CONFIG_UNSET,  T_CONFIG_SCOPE_UNSET }
15734         };
15735 -       
15736 +
15737         if (!p) return HANDLER_ERROR;
15738 -       
15739 +
15740         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
15741 -       
15742 +
15743         for (i = 0; i < srv->config_context->used; i++) {
15744                 plugin_config *s;
15745 -               
15746 +
15747                 s = calloc(1, sizeof(plugin_config));
15748 -               s->alias = array_init();        
15749 +               s->alias = array_init();
15750                 cv[0].destination = s->alias;
15751 -               
15752 +
15753                 p->config_storage[i] = s;
15754 -               
15755 +
15756                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
15757                         return HANDLER_ERROR;
15758                 }
15759 @@ -110,76 +111,73 @@
15760                         }
15761                 }
15762         }
15763 -       
15764 +
15765         return HANDLER_GO_ON;
15766  }
15767  
15768 -#define PATCH(x) \
15769 -       p->conf.x = s->x;
15770  static int mod_alias_patch_connection(server *srv, connection *con, plugin_data *p) {
15771         size_t i, j;
15772         plugin_config *s = p->config_storage[0];
15773 -       
15774 -       PATCH(alias);
15775 -       
15776 +
15777 +       PATCH_OPTION(alias);
15778 +
15779         /* skip the first, the global context */
15780         for (i = 1; i < srv->config_context->used; i++) {
15781                 data_config *dc = (data_config *)srv->config_context->data[i];
15782                 s = p->config_storage[i];
15783 -               
15784 +
15785                 /* condition didn't match */
15786                 if (!config_check_cond(srv, con, dc)) continue;
15787 -               
15788 +
15789                 /* merge config */
15790                 for (j = 0; j < dc->value->used; j++) {
15791                         data_unset *du = dc->value->data[j];
15792 -                       
15793 +
15794                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("alias.url"))) {
15795 -                               PATCH(alias);
15796 +                               PATCH_OPTION(alias);
15797                         }
15798                 }
15799         }
15800 -       
15801 +
15802         return 0;
15803  }
15804 -#undef PATCH
15805  
15806  PHYSICALPATH_FUNC(mod_alias_physical_handler) {
15807         plugin_data *p = p_d;
15808         int uri_len, basedir_len;
15809         char *uri_ptr;
15810         size_t k;
15811 -       
15812 +
15813         if (con->physical.path->used == 0) return HANDLER_GO_ON;
15814 -       
15815 +
15816         mod_alias_patch_connection(srv, con, p);
15817 -       
15818 +
15819         /* not to include the tailing slash */
15820         basedir_len = (con->physical.basedir->used - 1) - 1;
15821         uri_len = con->physical.path->used - 1 - basedir_len;
15822         uri_ptr = con->physical.path->ptr + basedir_len;
15823 -       
15824 +
15825         for (k = 0; k < p->conf.alias->used; k++) {
15826                 data_string *ds = (data_string *)p->conf.alias->data[k];
15827                 int alias_len = ds->key->used - 1;
15828 -               
15829 +
15830                 if (alias_len > uri_len) continue;
15831                 if (ds->key->used == 0) continue;
15832 -               
15833 +
15834                 if (0 == (con->conf.force_lowercase_filenames ?
15835                                         strncasecmp(uri_ptr, ds->key->ptr, alias_len) :
15836                                         strncmp(uri_ptr, ds->key->ptr, alias_len))) {
15837                         /* matched */
15838 -                       
15839 +
15840                         buffer_copy_string_buffer(con->physical.basedir, ds->value);
15841                         buffer_copy_string_buffer(srv->tmp_buf, ds->value);
15842                         buffer_append_string(srv->tmp_buf, uri_ptr + alias_len);
15843                         buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
15844 -                       
15845 +
15846                         return HANDLER_GO_ON;
15847                 }
15848         }
15849 -       
15850 +
15851         /* not found */
15852         return HANDLER_GO_ON;
15853  }
15854 @@ -189,13 +187,13 @@
15855  int mod_alias_plugin_init(plugin *p) {
15856         p->version     = LIGHTTPD_VERSION_ID;
15857         p->name        = buffer_init_string("alias");
15858 -       
15859 +
15860         p->init           = mod_alias_init;
15861         p->handle_physical= mod_alias_physical_handler;
15862         p->set_defaults   = mod_alias_set_defaults;
15863         p->cleanup        = mod_alias_free;
15864 -       
15865 +
15866         p->data        = NULL;
15867 -       
15868 +
15869         return 0;
15870  }
15871 --- ../lighttpd-1.4.11/src/mod_auth.c   2006-02-15 20:01:31.000000000 +0200
15872 +++ lighttpd-1.4.12/src/mod_auth.c      2006-07-18 13:03:40.000000000 +0300
15873 @@ -5,168 +5,167 @@
15874  #include <string.h>
15875  #include <errno.h>
15876  #include <fcntl.h>
15877 -#include <unistd.h>
15878  
15879  #include "plugin.h"
15880  #include "http_auth.h"
15881  #include "log.h"
15882  #include "response.h"
15883  
15884 +#include "sys-strings.h"
15885 +#include "sys-files.h"
15886 +
15887  handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s);
15888  
15889  
15890  /**
15891   * the basic and digest auth framework
15892 - * 
15893 + *
15894   * - config handling
15895   * - protocol handling
15896 - * 
15897 - * http_auth.c 
15898 - * http_auth_digest.c 
15899 - * 
15900 + *
15901 + * http_auth.c
15902 + * http_auth_digest.c
15903 + *
15904   * do the real work
15905   */
15906  
15907  INIT_FUNC(mod_auth_init) {
15908         mod_auth_plugin_data *p;
15909 -       
15910 +
15911         p = calloc(1, sizeof(*p));
15912 -       
15913 +
15914         p->tmp_buf = buffer_init();
15915 -       
15916 +
15917         p->auth_user = buffer_init();
15918  #ifdef USE_LDAP
15919         p->ldap_filter = buffer_init();
15920  #endif
15921 -       
15922 +
15923         return p;
15924  }
15925  
15926  FREE_FUNC(mod_auth_free) {
15927         mod_auth_plugin_data *p = p_d;
15928 -       
15929 +
15930         UNUSED(srv);
15931  
15932         if (!p) return HANDLER_GO_ON;
15933 -       
15934 +
15935         buffer_free(p->tmp_buf);
15936         buffer_free(p->auth_user);
15937  #ifdef USE_LDAP
15938         buffer_free(p->ldap_filter);
15939  #endif
15940 -       
15941 +
15942         if (p->config_storage) {
15943                 size_t i;
15944                 for (i = 0; i < srv->config_context->used; i++) {
15945                         mod_auth_plugin_config *s = p->config_storage[i];
15946 -                       
15947 +
15948                         if (!s) continue;
15949 -                       
15950 +
15951                         array_free(s->auth_require);
15952                         buffer_free(s->auth_plain_groupfile);
15953                         buffer_free(s->auth_plain_userfile);
15954                         buffer_free(s->auth_htdigest_userfile);
15955                         buffer_free(s->auth_htpasswd_userfile);
15956                         buffer_free(s->auth_backend_conf);
15957 -                       
15958 +
15959                         buffer_free(s->auth_ldap_hostname);
15960                         buffer_free(s->auth_ldap_basedn);
15961                         buffer_free(s->auth_ldap_binddn);
15962                         buffer_free(s->auth_ldap_bindpw);
15963                         buffer_free(s->auth_ldap_filter);
15964                         buffer_free(s->auth_ldap_cafile);
15965 -                       
15966 +
15967  #ifdef USE_LDAP
15968                         buffer_free(s->ldap_filter_pre);
15969                         buffer_free(s->ldap_filter_post);
15970 -                       
15971 +
15972                         if (s->ldap) ldap_unbind_s(s->ldap);
15973  #endif
15974 -                       
15975 +
15976                         free(s);
15977                 }
15978                 free(p->config_storage);
15979         }
15980 -       
15981 +
15982         free(p);
15983 -       
15984 +
15985         return HANDLER_GO_ON;
15986  }
15987  
15988 -#define PATCH(x) \
15989 -       p->conf.x = s->x;
15990  static int mod_auth_patch_connection(server *srv, connection *con, mod_auth_plugin_data *p) {
15991         size_t i, j;
15992         mod_auth_plugin_config *s = p->config_storage[0];
15993  
15994 -       PATCH(auth_backend);
15995 -       PATCH(auth_plain_groupfile);
15996 -       PATCH(auth_plain_userfile);
15997 -       PATCH(auth_htdigest_userfile);
15998 -       PATCH(auth_htpasswd_userfile);
15999 -       PATCH(auth_require);
16000 -       PATCH(auth_debug);
16001 -       PATCH(auth_ldap_hostname);
16002 -       PATCH(auth_ldap_basedn);
16003 -       PATCH(auth_ldap_binddn);
16004 -       PATCH(auth_ldap_bindpw);
16005 -       PATCH(auth_ldap_filter);
16006 -       PATCH(auth_ldap_cafile);
16007 -       PATCH(auth_ldap_starttls);
16008 +       PATCH_OPTION(auth_backend);
16009 +       PATCH_OPTION(auth_plain_groupfile);
16010 +       PATCH_OPTION(auth_plain_userfile);
16011 +       PATCH_OPTION(auth_htdigest_userfile);
16012 +       PATCH_OPTION(auth_htpasswd_userfile);
16013 +       PATCH_OPTION(auth_require);
16014 +       PATCH_OPTION(auth_debug);
16015 +       PATCH_OPTION(auth_ldap_hostname);
16016 +       PATCH_OPTION(auth_ldap_basedn);
16017 +       PATCH_OPTION(auth_ldap_binddn);
16018 +       PATCH_OPTION(auth_ldap_bindpw);
16019 +       PATCH_OPTION(auth_ldap_filter);
16020 +       PATCH_OPTION(auth_ldap_cafile);
16021 +       PATCH_OPTION(auth_ldap_starttls);
16022  #ifdef USE_LDAP
16023 -       PATCH(ldap);
16024 -       PATCH(ldap_filter_pre);
16025 -       PATCH(ldap_filter_post);
16026 +       PATCH_OPTION(ldap);
16027 +       PATCH_OPTION(ldap_filter_pre);
16028 +       PATCH_OPTION(ldap_filter_post);
16029  #endif
16030 -       
16031 +
16032         /* skip the first, the global context */
16033         for (i = 1; i < srv->config_context->used; i++) {
16034                 data_config *dc = (data_config *)srv->config_context->data[i];
16035                 s = p->config_storage[i];
16036 -               
16037 +
16038                 /* condition didn't match */
16039                 if (!config_check_cond(srv, con, dc)) continue;
16040 -               
16041 +
16042                 /* merge config */
16043                 for (j = 0; j < dc->value->used; j++) {
16044                         data_unset *du = dc->value->data[j];
16045 -                       
16046 +
16047                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend"))) {
16048 -                               PATCH(auth_backend);
16049 +                               PATCH_OPTION(auth_backend);
16050                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.groupfile"))) {
16051 -                               PATCH(auth_plain_groupfile);
16052 +                               PATCH_OPTION(auth_plain_groupfile);
16053                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.userfile"))) {
16054 -                               PATCH(auth_plain_userfile);
16055 +                               PATCH_OPTION(auth_plain_userfile);
16056                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htdigest.userfile"))) {
16057 -                               PATCH(auth_htdigest_userfile);
16058 +                               PATCH_OPTION(auth_htdigest_userfile);
16059                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htpasswd.userfile"))) {
16060 -                               PATCH(auth_htpasswd_userfile);
16061 +                               PATCH_OPTION(auth_htpasswd_userfile);
16062                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.require"))) {
16063 -                               PATCH(auth_require);
16064 +                               PATCH_OPTION(auth_require);
16065                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.debug"))) {
16066 -                               PATCH(auth_debug);
16067 +                               PATCH_OPTION(auth_debug);
16068                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.hostname"))) {
16069 -                               PATCH(auth_ldap_hostname);
16070 +                               PATCH_OPTION(auth_ldap_hostname);
16071  #ifdef USE_LDAP
16072 -                               PATCH(ldap);
16073 -                               PATCH(ldap_filter_pre);
16074 -                               PATCH(ldap_filter_post);
16075 +                               PATCH_OPTION(ldap);
16076 +                               PATCH_OPTION(ldap_filter_pre);
16077 +                               PATCH_OPTION(ldap_filter_post);
16078  #endif
16079                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.base-dn"))) {
16080 -                               PATCH(auth_ldap_basedn);
16081 +                               PATCH_OPTION(auth_ldap_basedn);
16082                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.filter"))) {
16083 -                               PATCH(auth_ldap_filter);
16084 +                               PATCH_OPTION(auth_ldap_filter);
16085                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.ca-file"))) {
16086 -                               PATCH(auth_ldap_cafile);
16087 +                               PATCH_OPTION(auth_ldap_cafile);
16088                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.starttls"))) {
16089 -                               PATCH(auth_ldap_starttls);
16090 +                               PATCH_OPTION(auth_ldap_starttls);
16091                         }
16092                 }
16093         }
16094 -       
16095 +
16096         return 0;
16097  }
16098 -#undef PATCH
16099  
16100  static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
16101         size_t k;
16102 @@ -175,22 +174,22 @@
16103         data_string *ds;
16104         mod_auth_plugin_data *p = p_d;
16105         array *req;
16106 -       
16107 +
16108         /* select the right config */
16109         mod_auth_patch_connection(srv, con, p);
16110 -       
16111 +
16112         if (p->conf.auth_require == NULL) return HANDLER_GO_ON;
16113 -       
16114 +
16115         /*
16116          * AUTH
16117 -        *  
16118 +        *
16119          */
16120 -       
16121 +
16122         /* do we have to ask for auth ? */
16123 -       
16124 +
16125         auth_required = 0;
16126         auth_satisfied = 0;
16127 -       
16128 +
16129         /* search auth-directives for path */
16130         for (k = 0; k < p->conf.auth_require->used; k++) {
16131                 buffer *req = p->conf.auth_require->data[k]->key;
16132 @@ -212,76 +211,76 @@
16133                         }
16134                 }
16135         }
16136 -       
16137 +
16138         /* nothing to do for us */
16139         if (auth_required == 0) return HANDLER_GO_ON;
16140 -       
16141 +
16142         req = ((data_array *)(p->conf.auth_require->data[k]))->value;
16143 -       
16144 +
16145         /* try to get Authorization-header */
16146 -               
16147 +
16148         if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Authorization"))) {
16149                 http_authorization = ds->value->ptr;
16150         }
16151 -       
16152 +
16153         if (ds && ds->value && ds->value->used) {
16154                 char *auth_realm;
16155                 data_string *method;
16156 -               
16157 +
16158                 method = (data_string *)array_get_element(req, "method");
16159 -               
16160 +
16161                 /* parse auth-header */
16162                 if (NULL != (auth_realm = strchr(http_authorization, ' '))) {
16163                         int auth_type_len = auth_realm - http_authorization;
16164 -                       
16165 +
16166                         if ((auth_type_len == 5) &&
16167                             (0 == strncmp(http_authorization, "Basic", auth_type_len))) {
16168 -                               
16169 -                               if (0 == strcmp(method->value->ptr, "basic")) {
16170 +
16171 +                               if (buffer_is_equal_string(method->value, CONST_STR_LEN("basic"))) {
16172                                         auth_satisfied = http_auth_basic_check(srv, con, p, req, con->uri.path, auth_realm+1);
16173                                 }
16174                         } else if ((auth_type_len == 6) &&
16175                                    (0 == strncmp(http_authorization, "Digest", auth_type_len))) {
16176 -                               if (0 == strcmp(method->value->ptr, "digest")) {
16177 +                               if (buffer_is_equal_string(method->value, CONST_STR_LEN("digest"))) {
16178                                         if (-1 == (auth_satisfied = http_auth_digest_check(srv, con, p, req, con->uri.path, auth_realm+1))) {
16179                                                 con->http_status = 400;
16180 -                                               
16181 +
16182                                                 /* a field was missing */
16183 -                                               
16184 +
16185                                                 return HANDLER_FINISHED;
16186                                         }
16187                                 }
16188                         } else {
16189 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
16190 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
16191                                                 "unknown authentification type:",
16192                                                 http_authorization);
16193                         }
16194                 }
16195         }
16196 -       
16197 +
16198         if (!auth_satisfied) {
16199                 data_string *method, *realm;
16200                 method = (data_string *)array_get_element(req, "method");
16201                 realm = (data_string *)array_get_element(req, "realm");
16202 -               
16203 +
16204                 con->http_status = 401;
16205 -                       
16206 -               if (0 == strcmp(method->value->ptr, "basic")) {
16207 +
16208 +               if (buffer_is_equal_string(method->value, CONST_STR_LEN("basic"))) {
16209                         buffer_copy_string(p->tmp_buf, "Basic realm=\"");
16210                         buffer_append_string_buffer(p->tmp_buf, realm->value);
16211                         buffer_append_string(p->tmp_buf, "\"");
16212 -                       
16213 +
16214                         response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
16215 -               } else if (0 == strcmp(method->value->ptr, "digest")) {
16216 +               } else if (buffer_is_equal_string(method->value, CONST_STR_LEN("digest"))) {
16217                         char hh[33];
16218                         http_auth_digest_generate_nonce(srv, p, srv->tmp_buf, hh);
16219 -                       
16220 +
16221                         buffer_copy_string(p->tmp_buf, "Digest realm=\"");
16222                         buffer_append_string_buffer(p->tmp_buf, realm->value);
16223                         buffer_append_string(p->tmp_buf, "\", nonce=\"");
16224                         buffer_append_string(p->tmp_buf, hh);
16225                         buffer_append_string(p->tmp_buf, "\", qop=\"auth\"");
16226 -                       
16227 +
16228                         response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
16229                 } else {
16230                         /* evil */
16231 @@ -289,18 +288,18 @@
16232                 return HANDLER_FINISHED;
16233         } else {
16234                 /* the REMOTE_USER header */
16235 -               
16236 +
16237                 buffer_copy_string_buffer(con->authed_user, p->auth_user);
16238         }
16239 -       
16240 +
16241         return HANDLER_GO_ON;
16242  }
16243  
16244  SETDEFAULTS_FUNC(mod_auth_set_defaults) {
16245         mod_auth_plugin_data *p = p_d;
16246         size_t i;
16247 -       
16248 -       config_values_t cv[] = { 
16249 +
16250 +       config_values_t cv[] = {
16251                 { "auth.backend",                   NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
16252                 { "auth.backend.plain.groupfile",   NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
16253                 { "auth.backend.plain.userfile",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
16254 @@ -317,7 +316,7 @@
16255                 { "auth.debug",                     NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },  /* 13 */
16256                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
16257         };
16258 -       
16259 +
16260         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
16261  
16262         for (i = 0; i < srv->config_context->used; i++) {
16263 @@ -325,14 +324,14 @@
16264                 size_t n;
16265                 data_array *da;
16266                 array *ca;
16267 -               
16268 +
16269                 s = calloc(1, sizeof(mod_auth_plugin_config));
16270                 s->auth_plain_groupfile = buffer_init();
16271                 s->auth_plain_userfile = buffer_init();
16272                 s->auth_htdigest_userfile = buffer_init();
16273                 s->auth_htpasswd_userfile = buffer_init();
16274                 s->auth_backend_conf = buffer_init();
16275 -               
16276 +
16277                 s->auth_ldap_hostname = buffer_init();
16278                 s->auth_ldap_basedn = buffer_init();
16279                 s->auth_ldap_binddn = buffer_init();
16280 @@ -341,15 +340,15 @@
16281                 s->auth_ldap_cafile = buffer_init();
16282                 s->auth_ldap_starttls = 0;
16283                 s->auth_debug = 0;
16284 -               
16285 +
16286                 s->auth_require = array_init();
16287 -               
16288 +
16289  #ifdef USE_LDAP
16290                 s->ldap_filter_pre = buffer_init();
16291                 s->ldap_filter_post = buffer_init();
16292                 s->ldap = NULL;
16293  #endif
16294 -       
16295 +
16296                 cv[0].destination = s->auth_backend_conf;
16297                 cv[1].destination = s->auth_plain_groupfile;
16298                 cv[2].destination = s->auth_plain_userfile;
16299 @@ -364,146 +363,148 @@
16300                 cv[11].destination = s->auth_htdigest_userfile;
16301                 cv[12].destination = s->auth_htpasswd_userfile;
16302                 cv[13].destination = &(s->auth_debug);
16303 -               
16304 +
16305                 p->config_storage[i] = s;
16306                 ca = ((data_config *)srv->config_context->data[i])->value;
16307 -               
16308 +
16309                 if (0 != config_insert_values_global(srv, ca, cv)) {
16310                         return HANDLER_ERROR;
16311                 }
16312 -               
16313 -               if (s->auth_backend_conf->used) {
16314 -                       if (0 == strcmp(s->auth_backend_conf->ptr, "htpasswd")) {
16315 +
16316 +               if (!buffer_is_empty(s->auth_backend_conf)) {
16317 +                       if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("htpasswd"))) {
16318                                 s->auth_backend = AUTH_BACKEND_HTPASSWD;
16319 -                       } else if (0 == strcmp(s->auth_backend_conf->ptr, "htdigest")) {
16320 +                       } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("htdigest"))) {
16321                                 s->auth_backend = AUTH_BACKEND_HTDIGEST;
16322 -                       } else if (0 == strcmp(s->auth_backend_conf->ptr, "plain")) {
16323 +                       } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("plain"))) {
16324                                 s->auth_backend = AUTH_BACKEND_PLAIN;
16325 -                       } else if (0 == strcmp(s->auth_backend_conf->ptr, "ldap")) {
16326 +                       } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("ldap"))) {
16327                                 s->auth_backend = AUTH_BACKEND_LDAP;
16328                         } else {
16329                                 log_error_write(srv, __FILE__, __LINE__, "sb", "auth.backend not supported:", s->auth_backend_conf);
16330 -                               
16331 +
16332                                 return HANDLER_ERROR;
16333                         }
16334                 }
16335  
16336                 /* no auth.require for this section */
16337                 if (NULL == (da = (data_array *)array_get_element(ca, "auth.require"))) continue;
16338 -               
16339 +
16340                 if (da->type != TYPE_ARRAY) continue;
16341 -               
16342 +
16343                 for (n = 0; n < da->value->used; n++) {
16344                         size_t m;
16345                         data_array *da_file = (data_array *)da->value->data[n];
16346 -                       const char *method, *realm, *require;
16347 -                       
16348 +                       buffer *method, *realm, *require;
16349 +
16350                         if (da->value->data[n]->type != TYPE_ARRAY) {
16351 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
16352 -                                               "auth.require should contain an array as in:", 
16353 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
16354 +                                               "auth.require should contain an array as in:",
16355                                                 "auth.require = ( \"...\" => ( ..., ...) )");
16356  
16357                                 return HANDLER_ERROR;
16358                         }
16359 -                                       
16360 +
16361                         method = realm = require = NULL;
16362 -                                       
16363 +
16364                         for (m = 0; m < da_file->value->used; m++) {
16365 -                               if (da_file->value->data[m]->type == TYPE_STRING) {
16366 -                                       if (0 == strcmp(da_file->value->data[m]->key->ptr, "method")) {
16367 -                                               method = ((data_string *)(da_file->value->data[m]))->value->ptr;
16368 -                                       } else if (0 == strcmp(da_file->value->data[m]->key->ptr, "realm")) {
16369 -                                               realm = ((data_string *)(da_file->value->data[m]))->value->ptr;
16370 -                                       } else if (0 == strcmp(da_file->value->data[m]->key->ptr, "require")) {
16371 -                                               require = ((data_string *)(da_file->value->data[m]))->value->ptr;
16372 -                                       } else {
16373 -                                               log_error_write(srv, __FILE__, __LINE__, "ssbs", 
16374 -                                                       "the field is unknown in:", 
16375 +                               data_string *ds_auth_req = (data_string *)da_file->value->data[m];
16376 +
16377 +                               if (ds_auth_req->type != TYPE_STRING) {
16378 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbs",
16379 +                                               "a string was expected for:",
16380 +                                               "auth.require = ( \"...\" => ( ..., -> \"",
16381 +                                               ds_auth_req->key,
16382 +                                               "\" <- => \"...\" ) )");
16383 +
16384 +                                       return HANDLER_ERROR;
16385 +                               }
16386 +
16387 +                               if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("method"))) {
16388 +                                       method = ds_auth_req->value;
16389 +                               } else if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("realm"))) {
16390 +                                       realm = ds_auth_req->value;
16391 +                               } else if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("require"))) {
16392 +                                       require = ds_auth_req->value;
16393 +                               } else {
16394 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbs",
16395 +                                                       "the field is unknown in:",
16396                                                         "auth.require = ( \"...\" => ( ..., -> \"",
16397                                                         da_file->value->data[m]->key,
16398                                                         "\" <- => \"...\" ) )");
16399  
16400 -                                               return HANDLER_ERROR;
16401 -                                       }
16402 -                               } else {
16403 -                                       log_error_write(srv, __FILE__, __LINE__, "ssbs", 
16404 -                                               "a string was expected for:", 
16405 -                                               "auth.require = ( \"...\" => ( ..., -> \"",
16406 -                                               da_file->value->data[m]->key,
16407 -                                               "\" <- => \"...\" ) )");
16408 -                                       
16409                                         return HANDLER_ERROR;
16410 +
16411                                 }
16412                         }
16413 -                                       
16414 +
16415                         if (method == NULL) {
16416 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
16417 -                                               "the require field is missing in:", 
16418 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
16419 +                                               "the require field is missing in:",
16420                                                 "auth.require = ( \"...\" => ( ..., \"method\" => \"...\" ) )");
16421                                 return HANDLER_ERROR;
16422 -                       } else {
16423 -                               if (0 != strcmp(method, "basic") &&
16424 -                                   0 != strcmp(method, "digest")) {
16425 -                                       log_error_write(srv, __FILE__, __LINE__, "ss",
16426 -                                                       "method has to be either \"basic\" or \"digest\" in",
16427 -                                                       "auth.require = ( \"...\" => ( ..., \"method\" => \"...\") )");
16428 -                                       return HANDLER_ERROR;
16429 -                               }
16430 +                       } 
16431 +                       if (!buffer_is_equal_string(method, CONST_STR_LEN("basic")) &&
16432 +                           !buffer_is_equal_string(method, CONST_STR_LEN("digest"))) {
16433 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
16434 +                                               "method has to be either \"basic\" or \"digest\" in",
16435 +                                               "auth.require = ( \"...\" => ( ..., \"method\" => \"...\") )");
16436 +                               return HANDLER_ERROR;
16437                         }
16438 -                       
16439 +
16440                         if (realm == NULL) {
16441 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
16442 -                                               "the require field is missing in:", 
16443 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
16444 +                                               "the require field is missing in:",
16445                                                 "auth.require = ( \"...\" => ( ..., \"realm\" => \"...\" ) )");
16446                                 return HANDLER_ERROR;
16447                         }
16448 -                       
16449 +
16450                         if (require == NULL) {
16451 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
16452 -                                               "the require field is missing in:", 
16453 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
16454 +                                               "the require field is missing in:",
16455                                                 "auth.require = ( \"...\" => ( ..., \"require\" => \"...\" ) )");
16456                                 return HANDLER_ERROR;
16457                         }
16458 -                       
16459 +
16460                         if (method && realm && require) {
16461                                 data_string *ds;
16462                                 data_array *a;
16463 -                               
16464 +
16465                                 a = data_array_init();
16466                                 buffer_copy_string_buffer(a->key, da_file->key);
16467 -                               
16468 +
16469                                 ds = data_string_init();
16470 -                               
16471 +
16472                                 buffer_copy_string(ds->key, "method");
16473 -                               buffer_copy_string(ds->value, method);
16474 -                               
16475 +                               buffer_copy_string_buffer(ds->value, method);
16476 +
16477                                 array_insert_unique(a->value, (data_unset *)ds);
16478 -                               
16479 +
16480                                 ds = data_string_init();
16481 -                               
16482 +
16483                                 buffer_copy_string(ds->key, "realm");
16484 -                               buffer_copy_string(ds->value, realm);
16485 -                               
16486 +                               buffer_copy_string_buffer(ds->value, realm);
16487 +
16488                                 array_insert_unique(a->value, (data_unset *)ds);
16489 -                               
16490 +
16491                                 ds = data_string_init();
16492 -                               
16493 +
16494                                 buffer_copy_string(ds->key, "require");
16495 -                               buffer_copy_string(ds->value, require);
16496 -                               
16497 +                               buffer_copy_string_buffer(ds->value, require);
16498 +
16499                                 array_insert_unique(a->value, (data_unset *)ds);
16500 -                               
16501 +
16502                                 array_insert_unique(s->auth_require, (data_unset *)a);
16503                         }
16504                 }
16505 -       
16506 +
16507                 switch(s->auth_backend) {
16508                 case AUTH_BACKEND_PLAIN:
16509                         if (s->auth_plain_userfile->used) {
16510                                 int fd;
16511                                 /* try to read */
16512                                 if (-1 == (fd = open(s->auth_plain_userfile->ptr, O_RDONLY))) {
16513 -                                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
16514 +                                       log_error_write(srv, __FILE__, __LINE__, "sbss",
16515                                                         "opening auth.backend.plain.userfile:", s->auth_plain_userfile,
16516                                                         "failed:", strerror(errno));
16517                                         return HANDLER_ERROR;
16518 @@ -516,7 +517,7 @@
16519                                 int fd;
16520                                 /* try to read */
16521                                 if (-1 == (fd = open(s->auth_htpasswd_userfile->ptr, O_RDONLY))) {
16522 -                                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
16523 +                                       log_error_write(srv, __FILE__, __LINE__, "sbss",
16524                                                         "opening auth.backend.htpasswd.userfile:", s->auth_htpasswd_userfile,
16525                                                         "failed:", strerror(errno));
16526                                         return HANDLER_ERROR;
16527 @@ -529,7 +530,7 @@
16528                                 int fd;
16529                                 /* try to read */
16530                                 if (-1 == (fd = open(s->auth_htdigest_userfile->ptr, O_RDONLY))) {
16531 -                                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
16532 +                                       log_error_write(srv, __FILE__, __LINE__, "sbss",
16533                                                         "opening auth.backend.htdigest.userfile:", s->auth_htdigest_userfile,
16534                                                         "failed:", strerror(errno));
16535                                         return HANDLER_ERROR;
16536 @@ -554,75 +555,75 @@
16537  handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s) {
16538  #ifdef USE_LDAP
16539                         int ret;
16540 -#if 0                  
16541 +#if 0
16542                         if (s->auth_ldap_basedn->used == 0) {
16543                                 log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.base-dn has to be set");
16544 -                               
16545 +
16546                                 return HANDLER_ERROR;
16547                         }
16548  #endif
16549 -                       
16550 +
16551                         if (s->auth_ldap_filter->used) {
16552                                 char *dollar;
16553 -                               
16554 +
16555                                 /* parse filter */
16556 -                       
16557 +
16558                                 if (NULL == (dollar = strchr(s->auth_ldap_filter->ptr, '$'))) {
16559                                         log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.filter is missing a replace-operator '$'");
16560 -                                       
16561 +
16562                                         return HANDLER_ERROR;
16563                                 }
16564 -                               
16565 +
16566                                 buffer_copy_string_len(s->ldap_filter_pre, s->auth_ldap_filter->ptr, dollar - s->auth_ldap_filter->ptr);
16567                                 buffer_copy_string(s->ldap_filter_post, dollar+1);
16568                         }
16569 -                       
16570 +
16571                         if (s->auth_ldap_hostname->used) {
16572                                 if (NULL == (s->ldap = ldap_init(s->auth_ldap_hostname->ptr, LDAP_PORT))) {
16573                                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno));
16574 -                                       
16575 +
16576                                         return HANDLER_ERROR;
16577                                 }
16578 -                               
16579 +
16580                                 ret = LDAP_VERSION3;
16581                                 if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(s->ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) {
16582                                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
16583 -                               
16584 +
16585                                         return HANDLER_ERROR;
16586                                 }
16587  
16588                                 if (s->auth_ldap_starttls) {
16589 -                                       /* if no CA file is given, it is ok, as we will use encryption 
16590 +                                       /* if no CA file is given, it is ok, as we will use encryption
16591                                          * if the server requires a CAfile it will tell us */
16592                                         if (!buffer_is_empty(s->auth_ldap_cafile)) {
16593 -                                               if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, 
16594 +                                               if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
16595                                                                                 s->auth_ldap_cafile->ptr))) {
16596 -                                                       log_error_write(srv, __FILE__, __LINE__, "ss", 
16597 +                                                       log_error_write(srv, __FILE__, __LINE__, "ss",
16598                                                                         "Loading CA certificate failed:", ldap_err2string(ret));
16599 -                                               
16600 +
16601                                                         return HANDLER_ERROR;
16602                                                 }
16603                                         }
16604 -       
16605 +
16606                                         if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(s->ldap, NULL,  NULL))) {
16607                                                 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
16608 -                                               
16609 +
16610                                                 return HANDLER_ERROR;
16611                                         }
16612                                 }
16613 -                               
16614 -                               
16615 +
16616 +
16617                                 /* 1. */
16618                                 if (s->auth_ldap_binddn->used) {
16619                                         if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, s->auth_ldap_binddn->ptr, s->auth_ldap_bindpw->ptr))) {
16620                                                 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
16621 -                                               
16622 +
16623                                                 return HANDLER_ERROR;
16624                                         }
16625                                 } else {
16626                                         if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, NULL, NULL))) {
16627                                                 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
16628 -                                               
16629 +
16630                                                 return HANDLER_ERROR;
16631                                         }
16632                                 }
16633 @@ -641,8 +642,8 @@
16634         p->set_defaults = mod_auth_set_defaults;
16635         p->handle_uri_clean = mod_auth_uri_handler;
16636         p->cleanup     = mod_auth_free;
16637 -       
16638 +
16639         p->data        = NULL;
16640 -       
16641 +
16642         return 0;
16643  }
16644 --- ../lighttpd-1.4.11/src/mod_cgi.c    2006-02-22 15:15:10.000000000 +0200
16645 +++ lighttpd-1.4.12/src/mod_cgi.c       2006-07-18 13:03:40.000000000 +0300
16646 @@ -1,21 +1,8 @@
16647  #include <sys/types.h>
16648 -#ifdef __WIN32
16649 -#include <winsock2.h>
16650 -#else
16651 -#include <sys/socket.h>
16652 -#include <sys/wait.h>
16653 -#include <sys/mman.h>
16654 -
16655 -#include <netinet/in.h>
16656 -
16657 -#include <arpa/inet.h>
16658 -#endif
16659  
16660 -#include <unistd.h>
16661  #include <errno.h>
16662  #include <stdlib.h>
16663  #include <string.h>
16664 -#include <fdevent.h>
16665  #include <signal.h>
16666  #include <ctype.h>
16667  #include <assert.h>
16668 @@ -29,8 +16,16 @@
16669  #include "connections.h"
16670  #include "joblist.h"
16671  #include "http_chunk.h"
16672 +#include "fdevent.h"
16673  
16674  #include "plugin.h"
16675 +#include "http_resp.h"
16676 +
16677 +#include "sys-files.h"
16678 +#include "sys-mmap.h"
16679 +#include "sys-socket.h"
16680 +#include "sys-strings.h"
16681 +#include "sys-process.h"
16682  
16683  #ifdef HAVE_SYS_FILIO_H
16684  # include <sys/filio.h>
16685 @@ -40,11 +35,12 @@
16686  
16687  typedef struct {
16688         char **ptr;
16689 -       
16690 +
16691         size_t size;
16692         size_t used;
16693  } char_array;
16694  
16695 +#define pid_t int
16696  typedef struct {
16697         pid_t *ptr;
16698         size_t used;
16699 @@ -58,57 +54,68 @@
16700  typedef struct {
16701         PLUGIN_DATA;
16702         buffer_pid_t cgi_pid;
16703 -       
16704 +
16705         buffer *tmp_buf;
16706 -       buffer *parse_response;
16707 -       
16708 +
16709 +       http_resp *resp;
16710 +
16711         plugin_config **config_storage;
16712 -       
16713 -       plugin_config conf; 
16714 +
16715 +       plugin_config conf;
16716  } plugin_data;
16717  
16718 +typedef enum {
16719 +       CGI_STATE_UNSET,
16720 +       CGI_STATE_CONNECTING,
16721 +       CGI_STATE_READ_RESPONSE_HEADER,
16722 +       CGI_STATE_READ_RESPONSE_CONTENT
16723 +} cgi_state_t;
16724 +
16725  typedef struct {
16726         pid_t pid;
16727 -       int fd;
16728 -       int fde_ndx; /* index into the fd-event buffer */
16729 -       
16730 -       connection *remote_conn;  /* dumb pointer */
16731 -       plugin_data *plugin_data; /* dumb pointer */
16732 -       
16733 -       buffer *response;
16734 -       buffer *response_header;
16735 -} handler_ctx;
16736  
16737 -static handler_ctx * cgi_handler_ctx_init() {
16738 -       handler_ctx *hctx = calloc(1, sizeof(*hctx));
16739 +       iosocket *sock;
16740  
16741 -       assert(hctx);
16742 -       
16743 -       hctx->response = buffer_init();
16744 -       hctx->response_header = buffer_init();
16745 -       
16746 -       return hctx;
16747 -}
16748 +       chunkqueue *rb;
16749 +       chunkqueue *wb;
16750  
16751 -static void cgi_handler_ctx_free(handler_ctx *hctx) {
16752 -       buffer_free(hctx->response);
16753 -       buffer_free(hctx->response_header);
16754 -       
16755 -       free(hctx);
16756 +       cgi_state_t state;
16757 +
16758 +       connection *remote_con;  /* dumb pointer */
16759 +} cgi_session;
16760 +
16761 +static cgi_session * cgi_session_init() {
16762 +       cgi_session *sess = calloc(1, sizeof(*sess));
16763 +       assert(sess);
16764 +
16765 +       sess->sock = iosocket_init();
16766 +       sess->wb = chunkqueue_init();
16767 +       sess->rb = chunkqueue_init();
16768 +
16769 +       return sess;
16770  }
16771  
16772 -enum {FDEVENT_HANDLED_UNSET, FDEVENT_HANDLED_FINISHED, FDEVENT_HANDLED_NOT_FINISHED, FDEVENT_HANDLED_ERROR};
16773 +static void cgi_session_free(cgi_session *sess) {
16774 +       if (!sess) return;
16775 +
16776 +       iosocket_free(sess->sock);
16777 +
16778 +       chunkqueue_free(sess->wb);
16779 +       chunkqueue_free(sess->rb);
16780 +
16781 +       free(sess);
16782 +}
16783  
16784  INIT_FUNC(mod_cgi_init) {
16785         plugin_data *p;
16786 -       
16787 +
16788         p = calloc(1, sizeof(*p));
16789  
16790         assert(p);
16791 -       
16792 +
16793         p->tmp_buf = buffer_init();
16794 -       p->parse_response = buffer_init();
16795 -       
16796 +       p->resp = http_response_init();
16797 +
16798         return p;
16799  }
16800  
16801 @@ -116,62 +123,62 @@
16802  FREE_FUNC(mod_cgi_free) {
16803         plugin_data *p = p_d;
16804         buffer_pid_t *r = &(p->cgi_pid);
16805 -       
16806 +
16807         UNUSED(srv);
16808 -       
16809 +
16810         if (p->config_storage) {
16811                 size_t i;
16812                 for (i = 0; i < srv->config_context->used; i++) {
16813                         plugin_config *s = p->config_storage[i];
16814 -                       
16815 +
16816                         array_free(s->cgi);
16817 -                       
16818 +
16819                         free(s);
16820                 }
16821                 free(p->config_storage);
16822         }
16823 -       
16824 +
16825  
16826         if (r->ptr) free(r->ptr);
16827 -       
16828 +
16829         buffer_free(p->tmp_buf);
16830 -       buffer_free(p->parse_response);
16831 -       
16832 +       http_response_free(p->resp);
16833 +
16834         free(p);
16835 -       
16836 +
16837         return HANDLER_GO_ON;
16838  }
16839  
16840  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
16841         plugin_data *p = p_d;
16842         size_t i = 0;
16843 -       
16844 -       config_values_t cv[] = { 
16845 +
16846 +       config_values_t cv[] = {
16847                 { "cgi.assign",                  NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
16848                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET}
16849         };
16850  
16851         if (!p) return HANDLER_ERROR;
16852 -       
16853 +
16854         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
16855 -       
16856 +
16857         for (i = 0; i < srv->config_context->used; i++) {
16858                 plugin_config *s;
16859 -               
16860 +
16861                 s = calloc(1, sizeof(plugin_config));
16862                 assert(s);
16863 -               
16864 +
16865                 s->cgi    = array_init();
16866 -               
16867 +
16868                 cv[0].destination = s->cgi;
16869 -               
16870 +
16871                 p->config_storage[i] = s;
16872 -       
16873 +
16874                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
16875                         return HANDLER_ERROR;
16876                 }
16877         }
16878 -       
16879 +
16880         return HANDLER_GO_ON;
16881  }
16882  
16883 @@ -180,13 +187,13 @@
16884         int m = -1;
16885         size_t i;
16886         buffer_pid_t *r = &(p->cgi_pid);
16887 -       
16888 +
16889         UNUSED(srv);
16890  
16891         for (i = 0; i < r->used; i++) {
16892                 if (r->ptr[i] > m) m = r->ptr[i];
16893         }
16894 -       
16895 +
16896         if (r->size == 0) {
16897                 r->size = 16;
16898                 r->ptr = malloc(sizeof(*r->ptr) * r->size);
16899 @@ -194,321 +201,178 @@
16900                 r->size += 16;
16901                 r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
16902         }
16903 -       
16904 +
16905         r->ptr[r->used++] = pid;
16906 -       
16907 +
16908         return m;
16909  }
16910  
16911  static int cgi_pid_del(server *srv, plugin_data *p, pid_t pid) {
16912         size_t i;
16913         buffer_pid_t *r = &(p->cgi_pid);
16914 -       
16915 +
16916         UNUSED(srv);
16917  
16918         for (i = 0; i < r->used; i++) {
16919                 if (r->ptr[i] == pid) break;
16920         }
16921 -       
16922 +
16923         if (i != r->used) {
16924                 /* found */
16925 -               
16926 +
16927                 if (i != r->used - 1) {
16928                         r->ptr[i] = r->ptr[r->used - 1];
16929                 }
16930                 r->used--;
16931         }
16932 -       
16933 +
16934         return 0;
16935  }
16936  
16937 -static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in, int eol) {
16938 -       char *ns;
16939 -       const char *s;
16940 -       int line = 0;
16941 -       
16942 -       UNUSED(srv);
16943 -       
16944 -       buffer_copy_string_buffer(p->parse_response, in);
16945 -       
16946 -       for (s = p->parse_response->ptr; 
16947 -            NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n'))); 
16948 -            s = ns + (eol == EOL_RN ? 2 : 1), line++) {
16949 -               const char *key, *value;
16950 -               int key_len;
16951 -               data_string *ds;
16952 -               
16953 -               ns[0] = '\0';
16954 -               
16955 -               if (line == 0 && 
16956 -                   0 == strncmp(s, "HTTP/1.", 7)) {
16957 -                       /* non-parsed header ... we parse them anyway */
16958 -                       
16959 -                       if ((s[7] == '1' ||
16960 -                            s[7] == '0') &&
16961 -                           s[8] == ' ') {
16962 -                               int status;
16963 -                               /* after the space should be a status code for us */
16964 -                               
16965 -                               status = strtol(s+9, NULL, 10);
16966 -                               
16967 -                               if (con->http_status >= 100 &&
16968 -                                   con->http_status < 1000) {
16969 -                                       /* we expected 3 digits and didn't got them */
16970 -                                       con->parsed_response |= HTTP_STATUS;
16971 -                                       con->http_status = status;
16972 -                               }
16973 -                       }
16974 -               } else {
16975 -               
16976 -                       key = s;
16977 -                       if (NULL == (value = strchr(s, ':'))) {
16978 -                               /* we expect: "<key>: <value>\r\n" */
16979 -                               continue;
16980 -                       }
16981 -                       
16982 -                       key_len = value - key;
16983 -                       value += 1;
16984 -                       
16985 -                       /* skip LWS */
16986 -                       while (*value == ' ' || *value == '\t') value++;
16987 -                       
16988 -                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
16989 -                               ds = data_response_init();
16990 -                       }
16991 -                       buffer_copy_string_len(ds->key, key, key_len);
16992 -                       buffer_copy_string(ds->value, value);
16993 -                       
16994 -                       array_insert_unique(con->response.headers, (data_unset *)ds);
16995 -                       
16996 -                       switch(key_len) {
16997 -                       case 4:
16998 -                               if (0 == strncasecmp(key, "Date", key_len)) {
16999 -                                       con->parsed_response |= HTTP_DATE;
17000 -                               }
17001 -                               break;
17002 -                       case 6:
17003 -                               if (0 == strncasecmp(key, "Status", key_len)) {
17004 -                                       con->http_status = strtol(value, NULL, 10);
17005 -                                       con->parsed_response |= HTTP_STATUS;
17006 -                               }
17007 -                               break;
17008 -                       case 8:
17009 -                               if (0 == strncasecmp(key, "Location", key_len)) {
17010 -                                       con->parsed_response |= HTTP_LOCATION;
17011 -                               }
17012 -                               break;
17013 -                       case 10:
17014 -                               if (0 == strncasecmp(key, "Connection", key_len)) {
17015 -                                       con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
17016 -                                       con->parsed_response |= HTTP_CONNECTION;
17017 -                               }
17018 -                               break;
17019 -                       case 14:
17020 -                               if (0 == strncasecmp(key, "Content-Length", key_len)) {
17021 -                                       con->response.content_length = strtol(value, NULL, 10);
17022 -                                       con->parsed_response |= HTTP_CONTENT_LENGTH;
17023 -                               }
17024 -                               break;
17025 -                       default:
17026 -                               break;
17027 -                       }
17028 -               }
17029 -       }
17030 -       
17031 -       /* CGI/1.1 rev 03 - 7.2.1.2 */
17032 -       if ((con->parsed_response & HTTP_LOCATION) &&
17033 -           !(con->parsed_response & HTTP_STATUS)) {
17034 -               con->http_status = 302;
17035 +static int cgi_demux_response(server *srv, connection *con, plugin_data *p) {
17036 +       cgi_session *sess = con->plugin_ctx[p->id];
17037 +       chunk *c = NULL;
17038 +
17039 +       switch(srv->network_backend_read(srv, con, sess->sock, sess->rb)) {
17040 +       case NETWORK_STATUS_SUCCESS:
17041 +               /* we got content */
17042 +               break;
17043 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
17044 +               return 0;
17045 +       case NETWORK_STATUS_CONNECTION_CLOSE:
17046 +               /* this is a bit too early */
17047 +               ERROR("%s", "cgi-connection got closed before we read the response-header (CGI died ?)");
17048 +               return -1;
17049 +       default:
17050 +               /* oops */
17051 +               ERROR("%s", "oops, read-pipe-read failed and I don't know why");
17052 +               return -1;
17053         }
17054 -       
17055 -       return 0;
17056 -}
17057  
17058 +       /* looks like we got some content
17059 +       *
17060 +       * split off the header from the incoming stream
17061 +       */
17062  
17063 -static int cgi_demux_response(server *srv, handler_ctx *hctx) {
17064 -       plugin_data *p    = hctx->plugin_data;
17065 -       connection  *con  = hctx->remote_conn;
17066 -       
17067 -       while(1) {
17068 -               int n;
17069 -               
17070 -               buffer_prepare_copy(hctx->response, 1024);
17071 -               if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {
17072 -                       if (errno == EAGAIN || errno == EINTR) {
17073 -                               /* would block, wait for signal */
17074 -                               return FDEVENT_HANDLED_NOT_FINISHED;
17075 -                       }
17076 -                       /* error */
17077 -                       log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd);
17078 -                       return FDEVENT_HANDLED_ERROR;
17079 -               }
17080 -               
17081 -               if (n == 0) {
17082 -                       /* read finished */
17083 -                       
17084 -                       con->file_finished = 1;
17085 -                       
17086 -                       /* send final chunk */
17087 -                       http_chunk_append_mem(srv, con, NULL, 0);
17088 -                       joblist_append(srv, con);
17089 -                       
17090 -                       return FDEVENT_HANDLED_FINISHED;
17091 -               }
17092 -               
17093 -               hctx->response->ptr[n] = '\0';
17094 -               hctx->response->used = n+1;
17095 -               
17096 -               /* split header from body */
17097 -               
17098 -               if (con->file_started == 0) {
17099 -                       char *c;
17100 -                       int in_header = 0;
17101 -                       int header_end = 0;
17102 -                       int cp, eol = EOL_UNSET;
17103 -                       size_t used = 0;
17104 -                       
17105 -                       buffer_append_string_buffer(hctx->response_header, hctx->response);
17106 -                       
17107 -                       /* nph (non-parsed headers) */
17108 -                       if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;
17109 -                       
17110 -                       /* search for the \r\n\r\n or \n\n in the string */
17111 -                       for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) {
17112 -                               if (*c == ':') in_header = 1;
17113 -                               else if (*c == '\n') {
17114 -                                       if (in_header == 0) {
17115 -                                               /* got a response without a response header */
17116 -                                               
17117 -                                               c = NULL;
17118 -                                               header_end = 1;
17119 -                                               break;
17120 -                                       }
17121 -                                       
17122 -                                       if (eol == EOL_UNSET) eol = EOL_N;
17123 -                                       
17124 -                                       if (*(c+1) == '\n') {
17125 -                                               header_end = 1;
17126 -                                               break;
17127 -                                       }
17128 -                                       
17129 -                               } else if (used > 1 && *c == '\r' && *(c+1) == '\n') {
17130 -                                       if (in_header == 0) {
17131 -                                               /* got a response without a response header */
17132 -                                               
17133 -                                               c = NULL;
17134 -                                               header_end = 1;
17135 -                                               break;
17136 -                                       }
17137 -                                       
17138 -                                       if (eol == EOL_UNSET) eol = EOL_RN;
17139 -                                       
17140 -                                       if (used > 3 &&
17141 -                                           *(c+2) == '\r' && 
17142 -                                           *(c+3) == '\n') {
17143 -                                               header_end = 1;
17144 -                                               break;
17145 -                                       }
17146 -                                       
17147 -                                       /* skip the \n */
17148 -                                       c++;
17149 -                                       cp++;
17150 -                                       used--;
17151 +       if (con->file_started == 0) {
17152 +               size_t i;
17153 +               int have_content_length = 0;
17154 +
17155 +               http_response_reset(p->resp);
17156 +
17157 +               /* the response header is not fully received yet,
17158 +               *
17159 +               * extract the http-response header from the rb-cq
17160 +               */
17161 +               switch (http_response_parse_cq(sess->rb, p->resp)) {
17162 +               case PARSE_ERROR:
17163 +                       /* parsing failed */
17164 +
17165 +                       TRACE("%s", "response parser failed");
17166 +
17167 +                       con->http_status = 502; /* Bad Gateway */
17168 +                       return -1;
17169 +               case PARSE_NEED_MORE:
17170 +                       return 0;
17171 +               case PARSE_SUCCESS:
17172 +                       con->http_status = p->resp->status;
17173 +
17174 +                       chunkqueue_remove_finished_chunks(sess->rb);
17175 +
17176 +                       /* copy the http-headers */
17177 +                       for (i = 0; i < p->resp->headers->used; i++) {
17178 +                               const char *ign[] = { "Status", "Connection", NULL };
17179 +                               size_t j;
17180 +                               data_string *ds;
17181 +
17182 +                               data_string *header = (data_string *)p->resp->headers->data[i];
17183 +
17184 +                               /* some headers are ignored by default */
17185 +                               for (j = 0; ign[j]; j++) {
17186 +                                       if (0 == strcasecmp(ign[j], header->key->ptr)) break;
17187                                 }
17188 -                       }
17189 -                       
17190 -                       if (header_end) {
17191 -                               if (c == NULL) {
17192 -                                       /* no header, but a body */
17193 -                                       
17194 -                                       if (con->request.http_version == HTTP_VERSION_1_1) {
17195 -                                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
17196 -                                       }
17197 -                                       
17198 -                                       http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
17199 -                                       joblist_append(srv, con);
17200 -                               } else {
17201 -                                       size_t hlen = c - hctx->response_header->ptr + (eol == EOL_RN ? 4 : 2);
17202 -                                       size_t blen = hctx->response_header->used - hlen - 1;
17203 -                               
17204 -                                       /* a small hack: terminate after at the second \r */
17205 -                                       hctx->response_header->used = hlen + 1 - (eol == EOL_RN ? 2 : 1);
17206 -                                       hctx->response_header->ptr[hlen - (eol == EOL_RN ? 2 : 1)] = '\0';
17207 -                               
17208 -                                       /* parse the response header */
17209 -                                       cgi_response_parse(srv, con, p, hctx->response_header, eol);
17210 -                                       
17211 -                                       /* enable chunked-transfer-encoding */
17212 -                                       if (con->request.http_version == HTTP_VERSION_1_1 &&
17213 -                                           !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
17214 -                                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
17215 -                                       }
17216 -                                       
17217 -                                       if ((hctx->response->used != hlen) && blen > 0) {
17218 -                                               http_chunk_append_mem(srv, con, c + (eol == EOL_RN ? 4: 2), blen + 1);
17219 -                                               joblist_append(srv, con);
17220 -                                       }
17221 +                               if (ign[j]) continue;
17222 +
17223 +                               if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
17224 +                                       /* CGI/1.1 rev 03 - 7.2.1.2 */
17225 +                                       if (con->http_status == 0) con->http_status = 302;
17226 +                               } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
17227 +                                       have_content_length = 1;
17228                                 }
17229                                 
17230 -                               con->file_started = 1;
17231 +                               if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
17232 +                                       ds = data_response_init();
17233 +                               }
17234 +                               buffer_copy_string_buffer(ds->key, header->key);
17235 +                               buffer_copy_string_buffer(ds->value, header->value);
17236 +
17237 +                               array_insert_unique(con->response.headers, (data_unset *)ds);
17238                         }
17239 -               } else {
17240 -                       http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
17241 -                       joblist_append(srv, con);
17242 +
17243 +                       con->file_started = 1;
17244 +                       sess->state = CGI_STATE_READ_RESPONSE_CONTENT;
17245 +
17246 +                       if (con->request.http_version == HTTP_VERSION_1_1 &&
17247 +                           !have_content_length) {
17248 +                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
17249 +                       }
17250 +
17251 +                       break;
17252                 }
17253 -               
17254 -#if 0          
17255 -               log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr);
17256 -#endif
17257         }
17258 -       
17259 -       return FDEVENT_HANDLED_NOT_FINISHED;
17260 +
17261 +       /* FIXME: pass the response-header to the other plugins to
17262 +       * setup the filter-queue
17263 +       *
17264 +       * - use next-queue instead of con->write_queue
17265 +       */
17266 +
17267 +       /* copy the content to the next cq */
17268 +       for (c = sess->rb->first; c; c = c->next) {
17269 +               http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
17270 +
17271 +               c->offset = c->mem->used - 1;
17272 +       }
17273 +
17274 +       chunkqueue_remove_finished_chunks(sess->rb);
17275 +       joblist_append(srv, con);
17276 +
17277 +       return 0;
17278  }
17279  
17280 -static handler_t cgi_connection_close(server *srv, handler_ctx *hctx) {
17281 +static handler_t cgi_connection_close(server *srv, connection *con, plugin_data *p) {
17282 +       cgi_session *sess = con->plugin_ctx[p->id];
17283         int status;
17284         pid_t pid;
17285 -       plugin_data *p;
17286 -       connection  *con;
17287 -       
17288 -       if (NULL == hctx) return HANDLER_GO_ON;
17289 -       
17290 -       p    = hctx->plugin_data;
17291 -       con  = hctx->remote_conn;
17292 -       
17293 +
17294 +       if (NULL == sess) return HANDLER_GO_ON;
17295         if (con->mode != p->id) return HANDLER_GO_ON;
17296  
17297 -#ifndef __WIN32
17298 -       
17299 +#ifndef _WIN32
17300 +
17301         /* the connection to the browser went away, but we still have a connection
17302 -        * to the CGI script 
17303 +        * to the CGI script
17304          *
17305          * close cgi-connection
17306          */
17307 -       
17308 -       if (hctx->fd != -1) {
17309 +
17310 +       if (sess->sock->fd != -1) {
17311                 /* close connection to the cgi-script */
17312 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
17313 -               fdevent_unregister(srv->ev, hctx->fd);
17314 -               
17315 -               if (close(hctx->fd)) {
17316 -                       log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
17317 -               }
17318 -               
17319 -               hctx->fd = -1;
17320 -               hctx->fde_ndx = -1;
17321 +               fdevent_event_del(srv->ev, sess->sock);
17322 +               fdevent_unregister(srv->ev, sess->sock);
17323         }
17324 -       
17325 -       pid = hctx->pid;
17326 -       
17327 +
17328 +       pid = sess->pid;
17329 +
17330         con->plugin_ctx[p->id] = NULL;
17331 -       
17332 +
17333         /* is this a good idea ? */
17334 -       cgi_handler_ctx_free(hctx);
17335 -       
17336 +       cgi_session_free(sess);
17337 +
17338         /* if waitpid hasn't been called by response.c yet, do it here */
17339         if (pid) {
17340                 /* check if the CGI-script is already gone */
17341 +#ifndef _WIN32
17342                 switch(waitpid(pid, &status, WNOHANG)) {
17343                 case 0:
17344                         /* not finished yet */
17345 @@ -519,35 +383,35 @@
17346                 case -1:
17347                         /* */
17348                         if (errno == EINTR) break;
17349 -                       
17350 -                       /* 
17351 -                        * errno == ECHILD happens if _subrequest catches the process-status before 
17352 +
17353 +                       /*
17354 +                        * errno == ECHILD happens if _subrequest catches the process-status before
17355                          * we have read the response of the cgi process
17356 -                        * 
17357 +                        *
17358                          * -> catch status
17359                          * -> WAIT_FOR_EVENT
17360                          * -> read response
17361                          * -> we get here with waitpid == ECHILD
17362 -                        * 
17363 +                        *
17364                          */
17365                         if (errno == ECHILD) return HANDLER_GO_ON;
17366 -                       
17367 +
17368                         log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
17369                         return HANDLER_ERROR;
17370                 default:
17371                         /* Send an error if we haven't sent any data yet */
17372                         if (0 == con->file_started) {
17373                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
17374 -                               con->http_status = 500;
17375 +                               if (con->http_status == 0) con->http_status = 500;
17376                                 con->mode = DIRECT;
17377                         }
17378 -                               
17379 +
17380                         if (WIFEXITED(status)) {
17381  #if 0
17382                                 log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) cgi exited fine, pid:", pid);
17383  #endif
17384                                 pid = 0;
17385 -                               
17386 +
17387                                 return HANDLER_GO_ON;
17388                         } else {
17389                                 log_error_write(srv, __FILE__, __LINE__, "sd", "cgi died, pid:", pid);
17390 @@ -555,122 +419,126 @@
17391                                 return HANDLER_GO_ON;
17392                         }
17393                 }
17394 -               
17395 -       
17396 +
17397 +
17398                 kill(pid, SIGTERM);
17399 -               
17400 +#endif
17401                 /* cgi-script is still alive, queue the PID for removal */
17402                 cgi_pid_add(srv, p, pid);
17403         }
17404 -#endif 
17405 +#endif
17406         return HANDLER_GO_ON;
17407  }
17408  
17409  static handler_t cgi_connection_close_callback(server *srv, connection *con, void *p_d) {
17410         plugin_data *p = p_d;
17411 -       
17412 -       return cgi_connection_close(srv, con->plugin_ctx[p->id]);
17413 +
17414 +       return cgi_connection_close(srv, con, p);
17415  }
17416  
17417  
17418  static handler_t cgi_handle_fdevent(void *s, void *ctx, int revents) {
17419         server      *srv  = (server *)s;
17420 -       handler_ctx *hctx = ctx;
17421 -       connection  *con  = hctx->remote_conn;
17422 -       
17423 -       joblist_append(srv, con);
17424 -       
17425 -       if (hctx->fd == -1) {
17426 -               log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "invalid cgi-fd");
17427 -               
17428 -               return HANDLER_ERROR;
17429 -       }
17430 -       
17431 +       cgi_session *sess = ctx;
17432 +       connection  *con  = sess->remote_con;
17433 +       chunk *c;
17434 +
17435         if (revents & FDEVENT_IN) {
17436 -               switch (cgi_demux_response(srv, hctx)) {
17437 -               case FDEVENT_HANDLED_NOT_FINISHED:
17438 +               switch (sess->state) {
17439 +               case CGI_STATE_READ_RESPONSE_HEADER:
17440 +                       /* parse the header and set file-started, the demuxer will care about it */
17441 +                       joblist_append(srv, con);
17442 +
17443                         break;
17444 -               case FDEVENT_HANDLED_FINISHED:
17445 -                       /* we are done */
17446 -                       
17447 +               case CGI_STATE_READ_RESPONSE_CONTENT:
17448 +                       /* just forward the content to the out-going queue */
17449 +
17450 +                       chunkqueue_remove_finished_chunks(sess->rb);
17451 +
17452 +                       switch (srv->network_backend_read(srv, sess->remote_con, sess->sock, sess->rb)) {
17453 +                       case NETWORK_STATUS_CONNECTION_CLOSE:
17454 +                               fdevent_event_del(srv->ev, sess->sock);
17455 +
17456 +                               /* the connection is gone
17457 +                                * make the connect */
17458 +                               sess->remote_con->file_finished = 1;
17459  #if 0
17460 -                       log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "finished");
17461 +                               fdevent_event_del(srv->ev, sess->sock);
17462  #endif
17463 -                       cgi_connection_close(srv, hctx);
17464 -                       
17465 -                       /* if we get a IN|HUP and have read everything don't exec the close twice */ 
17466 -                       return HANDLER_FINISHED;
17467 -               case FDEVENT_HANDLED_ERROR:
17468 -                       connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
17469 -                       con->http_status = 500;
17470 -                       con->mode = DIRECT;
17471 -                       
17472 -                       log_error_write(srv, __FILE__, __LINE__, "s", "demuxer failed: ");
17473 +                       case NETWORK_STATUS_SUCCESS:
17474 +                               /* read even more, do we have all the content */
17475 +
17476 +                               /* how much do we want to read ? */
17477 +                               
17478 +                               /* call stream-decoder (HTTP-chunked, FastCGI, ... ) */
17479 +
17480 +                               chunkqueue_remove_finished_chunks(sess->rb);
17481 +
17482 +                               /* copy the content to the next cq */
17483 +                               for (c = sess->rb->first; c; c = c->next) {
17484 +                                       if (c->mem->used == 0) continue;
17485 +
17486 +                                       http_chunk_append_mem(srv, sess->remote_con, c->mem->ptr + c->offset, c->mem->used - c->offset);
17487 +       
17488 +                                       c->offset = c->mem->used - 1;
17489 +
17490 +                               }
17491 +                               chunkqueue_remove_finished_chunks(sess->rb);
17492 +
17493 +                               if (sess->remote_con->file_finished) {
17494 +                                       /* send final HTTP-Chunk packet */
17495 +                                       http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
17496 +                               }
17497 +                               
17498 +                               break;
17499 +                       default:
17500 +                               ERROR("%s", "oops, we failed to read");
17501 +                               break;
17502 +                       }
17503 +
17504 +                       joblist_append(srv, sess->remote_con);
17505 +                       break;
17506 +               default:
17507 +                       TRACE("unexpected state for a FDEVENT_IN: %d", sess->state);
17508                         break;
17509                 }
17510         }
17511 -       
17512 +
17513         if (revents & FDEVENT_OUT) {
17514                 /* nothing to do */
17515         }
17516 -       
17517 +
17518         /* perhaps this issue is already handled */
17519         if (revents & FDEVENT_HUP) {
17520 -               /* check if we still have a unfinished header package which is a body in reality */
17521 -               if (con->file_started == 0 &&
17522 -                   hctx->response_header->used) {
17523 -                       con->file_started = 1;
17524 -                       http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
17525 -                       joblist_append(srv, con);
17526 -               }
17527 -               
17528 -               if (con->file_finished == 0) {
17529 -                       http_chunk_append_mem(srv, con, NULL, 0);
17530 -                       joblist_append(srv, con);
17531 -               }
17532 -               
17533                 con->file_finished = 1;
17534 -               
17535 -               if (chunkqueue_is_empty(con->write_queue)) {
17536 -                       /* there is nothing left to write */
17537 -                       connection_set_state(srv, con, CON_STATE_RESPONSE_END);
17538 -               } else {
17539 -                       /* used the write-handler to finish the request on demand */
17540 -                       
17541 -               }
17542 -               
17543 -# if 0
17544 -               log_error_write(srv, __FILE__, __LINE__, "sddd", "got HUP from cgi", con->fd, hctx->fd, revents);
17545 -# endif
17546 -               
17547 -               /* rtsigs didn't liked the close */
17548 -               cgi_connection_close(srv, hctx);
17549 +
17550 +               fdevent_event_del(srv->ev, sess->sock);
17551 +
17552 +               /* someone has to close this socket now :) */
17553 +               http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
17554 +               joblist_append(srv, sess->remote_con);
17555         } else if (revents & FDEVENT_ERR) {
17556                 con->file_finished = 1;
17557 -               
17558 +
17559                 /* kill all connections to the cgi process */
17560 -               cgi_connection_close(srv, hctx);
17561 -#if 1
17562 -               log_error_write(srv, __FILE__, __LINE__, "s", "cgi-FDEVENT_ERR");
17563 -#endif                 
17564 -               return HANDLER_ERROR;
17565 +               fdevent_event_del(srv->ev, sess->sock);
17566         }
17567 -       
17568 +
17569         return HANDLER_FINISHED;
17570  }
17571  
17572  
17573  static int cgi_env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
17574         char *dst;
17575 -       
17576 +
17577         if (!key || !val) return -1;
17578 -       
17579 +
17580         dst = malloc(key_len + val_len + 3);
17581         memcpy(dst, key, key_len);
17582         dst[key_len] = '=';
17583         /* add the \0 from the value */
17584         memcpy(dst + key_len + 1, val, val_len + 1);
17585 -       
17586 +
17587         if (env->size == 0) {
17588                 env->size = 16;
17589                 env->ptr = malloc(env->size * sizeof(*env->ptr));
17590 @@ -678,45 +546,45 @@
17591                 env->size += 16;
17592                 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
17593         }
17594 -       
17595 +
17596         env->ptr[env->used++] = dst;
17597 -       
17598 +
17599         return 0;
17600  }
17601  
17602  static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *cgi_handler) {
17603         pid_t pid;
17604 -       
17605 +
17606  #ifdef HAVE_IPV6
17607         char b2[INET6_ADDRSTRLEN + 1];
17608  #endif
17609 -       
17610 +
17611         int to_cgi_fds[2];
17612         int from_cgi_fds[2];
17613         struct stat st;
17614 -       
17615 -#ifndef __WIN32        
17616 -       
17617 +
17618 +#ifndef _WIN32
17619 +
17620         if (cgi_handler->used > 1) {
17621                 /* stat the exec file */
17622                 if (-1 == (stat(cgi_handler->ptr, &st))) {
17623 -                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
17624 +                       log_error_write(srv, __FILE__, __LINE__, "sbss",
17625                                         "stat for cgi-handler", cgi_handler,
17626                                         "failed:", strerror(errno));
17627                         return -1;
17628                 }
17629         }
17630 -       
17631 +
17632         if (pipe(to_cgi_fds)) {
17633                 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
17634                 return -1;
17635         }
17636 -       
17637 +
17638         if (pipe(from_cgi_fds)) {
17639                 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
17640                 return -1;
17641         }
17642 -       
17643 +
17644         /* fork, execve */
17645         switch (pid = fork()) {
17646         case 0: {
17647 @@ -730,44 +598,40 @@
17648                 char *c;
17649                 const char *s;
17650                 server_socket *srv_sock = con->srv_socket;
17651 -               
17652 +
17653                 /* move stdout to from_cgi_fd[1] */
17654                 close(STDOUT_FILENO);
17655                 dup2(from_cgi_fds[1], STDOUT_FILENO);
17656                 close(from_cgi_fds[1]);
17657                 /* not needed */
17658                 close(from_cgi_fds[0]);
17659 -               
17660 +
17661                 /* move the stdin to to_cgi_fd[0] */
17662                 close(STDIN_FILENO);
17663                 dup2(to_cgi_fds[0], STDIN_FILENO);
17664                 close(to_cgi_fds[0]);
17665                 /* not needed */
17666                 close(to_cgi_fds[1]);
17667 -               
17668 -               /* HACK: 
17669 -                * this is not nice, but it works
17670 -                *
17671 -                * we feed the stderr of the CGI to our errorlog, if possible
17672 +
17673 +               /**
17674 +                * FIXME: add a event-handler for STDERR_FILENO and let it LOG()
17675                  */
17676 -               if (srv->errorlog_mode == ERRORLOG_FILE) {
17677 -                       close(STDERR_FILENO);
17678 -                       dup2(srv->errorlog_fd, STDERR_FILENO);
17679 -               }
17680 -               
17681 +
17682 +               close(STDERR_FILENO);
17683 +
17684                 /* create environment */
17685                 env.ptr = NULL;
17686                 env.size = 0;
17687                 env.used = 0;
17688 -               
17689 +
17690                 cgi_env_add(&env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
17691  
17692                 if (!buffer_is_empty(con->server_name)) {
17693                         cgi_env_add(&env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
17694                 } else {
17695  #ifdef HAVE_IPV6
17696 -                       s = inet_ntop(srv_sock->addr.plain.sa_family, 
17697 -                                     srv_sock->addr.plain.sa_family == AF_INET6 ? 
17698 +                       s = inet_ntop(srv_sock->addr.plain.sa_family,
17699 +                                     srv_sock->addr.plain.sa_family == AF_INET6 ?
17700                                       (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
17701                                       (const void *) &(srv_sock->addr.ipv4.sin_addr),
17702                                       b2, sizeof(b2)-1);
17703 @@ -779,10 +643,12 @@
17704                 cgi_env_add(&env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
17705  
17706                 s = get_http_version_name(con->request.http_version);
17707 -               
17708 +
17709 +               TRACE("http-version: %s (%d)", s, con->request.http_version);
17710 +
17711                 cgi_env_add(&env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
17712 -               
17713 -               ltostr(buf, 
17714 +
17715 +               ltostr(buf,
17716  #ifdef HAVE_IPV6
17717                         ntohs(srv_sock->addr.plain.sa_family == AF_INET6 ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
17718  #else
17719 @@ -790,10 +656,10 @@
17720  #endif
17721                         );
17722                 cgi_env_add(&env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
17723 -               
17724 +
17725  #ifdef HAVE_IPV6
17726 -               s = inet_ntop(srv_sock->addr.plain.sa_family, 
17727 -                             srv_sock->addr.plain.sa_family == AF_INET6 ? 
17728 +               s = inet_ntop(srv_sock->addr.plain.sa_family,
17729 +                             srv_sock->addr.plain.sa_family == AF_INET6 ?
17730                               (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
17731                               (const void *) &(srv_sock->addr.ipv4.sin_addr),
17732                               b2, sizeof(b2)-1);
17733 @@ -811,15 +677,18 @@
17734                 cgi_env_add(&env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200"));
17735                 if (!buffer_is_empty(con->uri.query)) {
17736                         cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
17737 +               } else {
17738 +                       /* set a empty QUERY_STRING */
17739 +                       cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
17740                 }
17741                 if (!buffer_is_empty(con->request.orig_uri)) {
17742                         cgi_env_add(&env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
17743                 }
17744 -               
17745 -               
17746 +
17747 +
17748  #ifdef HAVE_IPV6
17749 -               s = inet_ntop(con->dst_addr.plain.sa_family, 
17750 -                             con->dst_addr.plain.sa_family == AF_INET6 ? 
17751 +               s = inet_ntop(con->dst_addr.plain.sa_family,
17752 +                             con->dst_addr.plain.sa_family == AF_INET6 ?
17753                               (const void *) &(con->dst_addr.ipv6.sin6_addr) :
17754                               (const void *) &(con->dst_addr.ipv4.sin_addr),
17755                               b2, sizeof(b2)-1);
17756 @@ -828,7 +697,7 @@
17757  #endif
17758                 cgi_env_add(&env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
17759  
17760 -               ltostr(buf, 
17761 +               ltostr(buf,
17762  #ifdef HAVE_IPV6
17763                         ntohs(con->dst_addr.plain.sa_family == AF_INET6 ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
17764  #else
17765 @@ -836,19 +705,19 @@
17766  #endif
17767                         );
17768                 cgi_env_add(&env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
17769 -               
17770 +
17771                 if (!buffer_is_empty(con->authed_user)) {
17772                         cgi_env_add(&env, CONST_STR_LEN("REMOTE_USER"),
17773                                     CONST_BUF_LEN(con->authed_user));
17774                 }
17775 -               
17776 +
17777                 /* request.content_length < SSIZE_MAX, see request.c */
17778                 ltostr(buf, con->request.content_length);
17779                 cgi_env_add(&env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
17780                 cgi_env_add(&env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
17781                 cgi_env_add(&env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
17782                 cgi_env_add(&env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
17783 -               
17784 +
17785                 /* for valgrind */
17786                 if (NULL != (s = getenv("LD_PRELOAD"))) {
17787                         cgi_env_add(&env, CONST_STR_LEN("LD_PRELOAD"), s, strlen(s));
17788 @@ -863,24 +732,24 @@
17789                         cgi_env_add(&env, CONST_STR_LEN("SYSTEMROOT"), s, strlen(s));
17790                 }
17791  #endif
17792 -               
17793 +
17794                 for (n = 0; n < con->request.headers->used; n++) {
17795                         data_string *ds;
17796 -                       
17797 +
17798                         ds = (data_string *)con->request.headers->data[n];
17799 -                       
17800 +
17801                         if (ds->value->used && ds->key->used) {
17802                                 size_t j;
17803 -                               
17804 +
17805                                 buffer_reset(p->tmp_buf);
17806 -                               
17807 +
17808                                 if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
17809                                         buffer_copy_string(p->tmp_buf, "HTTP_");
17810                                         p->tmp_buf->used--; /* strip \0 after HTTP_ */
17811                                 }
17812 -                               
17813 +
17814                                 buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
17815 -                               
17816 +
17817                                 for (j = 0; j < ds->key->used - 1; j++) {
17818                                         char cr = '_';
17819                                         if (light_isalpha(ds->key->ptr[j])) {
17820 @@ -893,46 +762,46 @@
17821                                         p->tmp_buf->ptr[p->tmp_buf->used++] = cr;
17822                                 }
17823                                 p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
17824 -                               
17825 +
17826                                 cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
17827                         }
17828                 }
17829 -               
17830 +
17831                 for (n = 0; n < con->environment->used; n++) {
17832                         data_string *ds;
17833 -                       
17834 +
17835                         ds = (data_string *)con->environment->data[n];
17836 -                       
17837 +
17838                         if (ds->value->used && ds->key->used) {
17839                                 size_t j;
17840 -                               
17841 +
17842                                 buffer_reset(p->tmp_buf);
17843 -                               
17844 +
17845                                 buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
17846 -                               
17847 +
17848                                 for (j = 0; j < ds->key->used - 1; j++) {
17849 -                                       p->tmp_buf->ptr[p->tmp_buf->used++] = 
17850 -                                               isalpha((unsigned char)ds->key->ptr[j]) ? 
17851 +                                       p->tmp_buf->ptr[p->tmp_buf->used++] =
17852 +                                               isalpha((unsigned char)ds->key->ptr[j]) ?
17853                                                 toupper((unsigned char)ds->key->ptr[j]) : '_';
17854                                 }
17855                                 p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
17856 -                               
17857 +
17858                                 cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
17859                         }
17860                 }
17861 -               
17862 +
17863                 if (env.size == env.used) {
17864                         env.size += 16;
17865                         env.ptr = realloc(env.ptr, env.size * sizeof(*env.ptr));
17866                 }
17867 -               
17868 +
17869                 env.ptr[env.used] = NULL;
17870 -               
17871 +
17872                 /* set up args */
17873                 argc = 3;
17874                 args = malloc(sizeof(*args) * argc);
17875                 i = 0;
17876 -               
17877 +
17878                 if (cgi_handler->used > 1) {
17879                         args[i++] = cgi_handler->ptr;
17880                 }
17881 @@ -942,7 +811,7 @@
17882                 /* search for the last / */
17883                 if (NULL != (c = strrchr(con->physical.path->ptr, '/'))) {
17884                         *c = '\0';
17885 -                       
17886 +
17887                         /* change to the physical directory */
17888                         if (-1 == chdir(con->physical.path->ptr)) {
17889                                 log_error_write(srv, __FILE__, __LINE__, "ssb", "chdir failed:", strerror(errno), con->physical.path);
17890 @@ -952,14 +821,14 @@
17891  
17892                 /* we don't need the client socket */
17893                 for (i = 3; i < 256; i++) {
17894 -                       if (i != srv->errorlog_fd) close(i);
17895 +                       close(i);
17896                 }
17897 -               
17898 +
17899                 /* exec the cgi */
17900                 execve(args[0], args, env.ptr);
17901 -               
17902 +
17903                 log_error_write(srv, __FILE__, __LINE__, "sss", "CGI failed:", strerror(errno), args[0]);
17904 -               
17905 +
17906                 /* */
17907                 SEGFAULT();
17908                 break;
17909 @@ -969,16 +838,16 @@
17910                 log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed:", strerror(errno));
17911                 break;
17912         default: {
17913 -               handler_ctx *hctx;
17914 +               cgi_session *sess;
17915                 /* father */
17916  
17917                 close(from_cgi_fds[1]);
17918                 close(to_cgi_fds[0]);
17919 -               
17920 +
17921                 if (con->request.content_length) {
17922                         chunkqueue *cq = con->request_content_queue;
17923                         chunk *c;
17924 -               
17925 +
17926                         assert(chunkqueue_length(cq) == (off_t)con->request.content_length);
17927  
17928                         /* there is content to send */
17929 @@ -993,16 +862,16 @@
17930                                                 if (-1 == c->file.fd &&  /* open the file if not already open */
17931                                                     -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
17932                                                         log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
17933 -                                       
17934 +
17935                                                         close(from_cgi_fds[0]);
17936                                                         close(to_cgi_fds[1]);
17937                                                         return -1;
17938                                                 }
17939  
17940                                                 c->file.mmap.length = c->file.length;
17941 -                               
17942 +
17943                                                 if (MAP_FAILED == (c->file.mmap.start = mmap(0,  c->file.mmap.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
17944 -                                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ", 
17945 +                                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
17946                                                                         strerror(errno), c->file.name,  c->file.fd);
17947  
17948                                                         close(from_cgi_fds[0]);
17949 @@ -1012,7 +881,7 @@
17950  
17951                                                 close(c->file.fd);
17952                                                 c->file.fd = -1;
17953 -       
17954 +
17955                                                 /* chunk_reset() or chunk_free() will cleanup for us */
17956                                         }
17957  
17958 @@ -1020,7 +889,7 @@
17959                                                 switch(errno) {
17960                                                 case ENOSPC:
17961                                                         con->http_status = 507;
17962 -               
17963 +
17964                                                         break;
17965                                                 default:
17966                                                         con->http_status = 403;
17967 @@ -1033,7 +902,7 @@
17968                                                 switch(errno) {
17969                                                 case ENOSPC:
17970                                                         con->http_status = 507;
17971 -               
17972 +
17973                                                         break;
17974                                                 default:
17975                                                         con->http_status = 403;
17976 @@ -1056,103 +925,95 @@
17977                 }
17978  
17979                 close(to_cgi_fds[1]);
17980 -                               
17981 +
17982                 /* register PID and wait for them asyncronously */
17983                 con->mode = p->id;
17984                 buffer_reset(con->physical.path);
17985 -               
17986 -               hctx = cgi_handler_ctx_init();
17987 -               
17988 -               hctx->remote_conn = con;
17989 -               hctx->plugin_data = p;
17990 -               hctx->pid = pid;
17991 -               hctx->fd = from_cgi_fds[0];
17992 -               hctx->fde_ndx = -1;
17993 -               
17994 -               con->plugin_ctx[p->id] = hctx;
17995 -               
17996 -               fdevent_register(srv->ev, hctx->fd, cgi_handle_fdevent, hctx);
17997 -               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
17998 -               
17999 -               if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
18000 +
18001 +               sess = cgi_session_init();
18002 +
18003 +               sess->remote_con = con;
18004 +               sess->pid = pid;
18005 +
18006 +               sess->sock->fd = from_cgi_fds[0];
18007 +               sess->sock->type = IOSOCKET_TYPE_PIPE;
18008 +
18009 +               if (-1 == fdevent_fcntl_set(srv->ev, sess->sock)) {
18010                         log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
18011 -                       
18012 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
18013 -                       fdevent_unregister(srv->ev, hctx->fd);
18014 -                       
18015 -                       log_error_write(srv, __FILE__, __LINE__, "sd", "cgi close:", hctx->fd);
18016 -                       
18017 -                       close(hctx->fd);
18018 -                       
18019 -                       cgi_handler_ctx_free(hctx);
18020 -                       
18021 -                       con->plugin_ctx[p->id] = NULL;
18022 -                       
18023 +
18024 +                       cgi_session_free(sess);
18025 +
18026                         return -1;
18027                 }
18028 -               
18029 +
18030 +               con->plugin_ctx[p->id] = sess;
18031 +
18032 +               fdevent_register(srv->ev, sess->sock, cgi_handle_fdevent, sess);
18033 +               fdevent_event_add(srv->ev, sess->sock, FDEVENT_IN);
18034 +
18035 +               sess->state = CGI_STATE_READ_RESPONSE_HEADER;
18036 +
18037                 break;
18038         }
18039         }
18040 -       
18041 +
18042         return 0;
18043  #else
18044         return -1;
18045  #endif
18046  }
18047  
18048 -#define PATCH(x) \
18049 -       p->conf.x = s->x;
18050  static int mod_cgi_patch_connection(server *srv, connection *con, plugin_data *p) {
18051         size_t i, j;
18052         plugin_config *s = p->config_storage[0];
18053 -       
18054 -       PATCH(cgi);
18055 -       
18056 +
18057 +       PATCH_OPTION(cgi);
18058 +
18059         /* skip the first, the global context */
18060         for (i = 1; i < srv->config_context->used; i++) {
18061                 data_config *dc = (data_config *)srv->config_context->data[i];
18062                 s = p->config_storage[i];
18063 -               
18064 +
18065                 /* condition didn't match */
18066                 if (!config_check_cond(srv, con, dc)) continue;
18067 -               
18068 +
18069                 /* merge config */
18070                 for (j = 0; j < dc->value->used; j++) {
18071                         data_unset *du = dc->value->data[j];
18072 -                       
18073 +
18074                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.assign"))) {
18075 -                               PATCH(cgi);
18076 +                               PATCH_OPTION(cgi);
18077                         }
18078                 }
18079         }
18080 -       
18081 +
18082         return 0;
18083  }
18084 -#undef PATCH
18085  
18086  URIHANDLER_FUNC(cgi_is_handled) {
18087         size_t k, s_len;
18088         plugin_data *p = p_d;
18089         buffer *fn = con->physical.path;
18090 -       
18091 +
18092         if (fn->used == 0) return HANDLER_GO_ON;
18093 -       
18094 +
18095 +       TRACE("http-version: (%d)", con->request.http_version);
18096 +
18097         mod_cgi_patch_connection(srv, con, p);
18098 -       
18099 +
18100         s_len = fn->used - 1;
18101 -       
18102 +
18103         for (k = 0; k < p->conf.cgi->used; k++) {
18104                 data_string *ds = (data_string *)p->conf.cgi->data[k];
18105                 size_t ct_len = ds->key->used - 1;
18106 -               
18107 +
18108                 if (ds->key->used == 0) continue;
18109                 if (s_len < ct_len) continue;
18110 -               
18111 +
18112                 if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
18113                         if (cgi_create_env(srv, con, p, ds->value)) {
18114                                 con->http_status = 500;
18115 -                               
18116 +
18117                                 buffer_reset(con->physical.path);
18118                                 return HANDLER_FINISHED;
18119                         }
18120 @@ -1160,7 +1021,7 @@
18121                         break;
18122                 }
18123         }
18124 -       
18125 +
18126         return HANDLER_GO_ON;
18127  }
18128  
18129 @@ -1168,11 +1029,11 @@
18130         plugin_data *p = p_d;
18131         size_t ndx;
18132         /* the trigger handle only cares about lonely PID which we have to wait for */
18133 -#ifndef __WIN32
18134 +#ifndef _WIN32
18135  
18136         for (ndx = 0; ndx < p->cgi_pid.used; ndx++) {
18137                 int status;
18138 -               
18139 +
18140                 switch(waitpid(p->cgi_pid.ptr[ndx], &status, WNOHANG)) {
18141                 case 0:
18142                         /* not finished yet */
18143 @@ -1182,7 +1043,7 @@
18144                         break;
18145                 case -1:
18146                         log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
18147 -                       
18148 +
18149                         return HANDLER_ERROR;
18150                 default:
18151  
18152 @@ -1193,96 +1054,103 @@
18153                         } else {
18154                                 log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?");
18155                         }
18156 -                       
18157 +
18158                         cgi_pid_del(srv, p, p->cgi_pid.ptr[ndx]);
18159 -                       /* del modified the buffer structure 
18160 +                       /* del modified the buffer structure
18161                          * and copies the last entry to the current one
18162                          * -> recheck the current index
18163                          */
18164                         ndx--;
18165                 }
18166         }
18167 -#endif 
18168 +#endif
18169         return HANDLER_GO_ON;
18170  }
18171  
18172  SUBREQUEST_FUNC(mod_cgi_handle_subrequest) {
18173         int status;
18174         plugin_data *p = p_d;
18175 -       handler_ctx *hctx = con->plugin_ctx[p->id];
18176 -       
18177 +       cgi_session *sess = con->plugin_ctx[p->id];
18178 +
18179         if (con->mode != p->id) return HANDLER_GO_ON;
18180 -       if (NULL == hctx) return HANDLER_GO_ON;
18181 -       
18182 +       if (NULL == sess) return HANDLER_GO_ON;
18183 +
18184 +       switch (cgi_demux_response(srv, con, p)) {
18185 +       case 0:
18186 +               break;
18187 +       case 1:
18188 +               cgi_connection_close(srv, con, p);
18189 +
18190 +               /* if we get a IN|HUP and have read everything don't exec the close twice */
18191 +               return HANDLER_FINISHED;
18192 +       case -1:
18193 +               cgi_connection_close(srv, con, p);
18194 +
18195 +               if (0 == con->http_status) con->http_status = 500;
18196 +               connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
18197 +               con->mode = DIRECT;
18198 +
18199 +               return HANDLER_FINISHED;
18200 +       }
18201 +
18202  #if 0
18203 -       log_error_write(srv, __FILE__, __LINE__, "sdd", "subrequest, pid =", hctx, hctx->pid);
18204 -#endif 
18205 -       if (hctx->pid == 0) return HANDLER_FINISHED;
18206 -#ifndef __WIN32        
18207 -       switch(waitpid(hctx->pid, &status, WNOHANG)) {
18208 +       log_error_write(srv, __FILE__, __LINE__, "sdd", "subrequest, pid =", sess, sess->pid);
18209 +#endif
18210 +       if (sess->pid == 0) return HANDLER_FINISHED;
18211 +#ifndef _WIN32
18212 +       switch(waitpid(sess->pid, &status, WNOHANG)) {
18213         case 0:
18214                 /* we only have for events here if we don't have the header yet,
18215                  * otherwise the event-handler will send us the incoming data */
18216 -               if (con->file_started) return HANDLER_FINISHED;
18217  
18218 -               return HANDLER_WAIT_FOR_EVENT;
18219 +               if (!con->file_started) return HANDLER_WAIT_FOR_EVENT;
18220 +               if (con->file_finished) return HANDLER_FINISHED;
18221 +
18222 +               return HANDLER_GO_ON;
18223         case -1:
18224                 if (errno == EINTR) return HANDLER_WAIT_FOR_EVENT;
18225 -               
18226 +
18227                 if (errno == ECHILD && con->file_started == 0) {
18228                         /*
18229 -                        * second round but still not response 
18230 +                        * second round but still not response
18231                          */
18232 -                       return HANDLER_WAIT_FOR_EVENT; 
18233 +                       return HANDLER_WAIT_FOR_EVENT;
18234                 }
18235 -               
18236 +
18237                 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
18238                 con->mode = DIRECT;
18239                 con->http_status = 500;
18240 -               
18241 -               hctx->pid = 0;
18242 -               
18243 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
18244 -               fdevent_unregister(srv->ev, hctx->fd);
18245 -               
18246 -               if (close(hctx->fd)) {
18247 -                       log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
18248 -               }
18249 -               
18250 -               cgi_handler_ctx_free(hctx);
18251 -               
18252 +
18253 +               sess->pid = 0;
18254 +
18255 +               fdevent_event_del(srv->ev, sess->sock);
18256 +               fdevent_unregister(srv->ev, sess->sock);
18257 +
18258 +               cgi_session_free(sess);
18259 +
18260                 con->plugin_ctx[p->id] = NULL;
18261 -               
18262 +
18263                 return HANDLER_FINISHED;
18264         default:
18265 -               /* cgi process exited cleanly 
18266 -                * 
18267 -                * check if we already got the response 
18268 -                */
18269 -               
18270 -               if (!con->file_started) return HANDLER_WAIT_FOR_EVENT;
18271 -               
18272 +               con->file_finished = 1;
18273 +
18274                 if (WIFEXITED(status)) {
18275                         /* nothing */
18276                 } else {
18277                         log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?");
18278 -                       
18279 +
18280                         con->mode = DIRECT;
18281                         con->http_status = 500;
18282 -                       
18283 +
18284                 }
18285 -               
18286 -               hctx->pid = 0;
18287 -               
18288 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
18289 -               fdevent_unregister(srv->ev, hctx->fd);
18290 -               
18291 -               if (close(hctx->fd)) {
18292 -                       log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
18293 -               }
18294 -               
18295 -               cgi_handler_ctx_free(hctx);
18296 -               
18297 +
18298 +               sess->pid = 0;
18299 +
18300 +               fdevent_event_del(srv->ev, sess->sock);
18301 +               fdevent_unregister(srv->ev, sess->sock);
18302 +
18303 +               cgi_session_free(sess);
18304 +
18305                 con->plugin_ctx[p->id] = NULL;
18306                 return HANDLER_FINISHED;
18307         }
18308 @@ -1306,8 +1174,8 @@
18309         p->init           = mod_cgi_init;
18310         p->cleanup        = mod_cgi_free;
18311         p->set_defaults   = mod_fastcgi_set_defaults;
18312 -       
18313 +
18314         p->data        = NULL;
18315 -       
18316 +
18317         return 0;
18318  }
18319 --- ../lighttpd-1.4.11/src/mod_cml.c    2006-01-30 13:51:48.000000000 +0200
18320 +++ lighttpd-1.4.12/src/mod_cml.c       2006-07-16 00:26:03.000000000 +0300
18321 @@ -4,7 +4,6 @@
18322  #include <stdlib.h>
18323  #include <string.h>
18324  #include <errno.h>
18325 -#include <unistd.h>
18326  #include <stdio.h>
18327  
18328  #include "buffer.h"
18329 @@ -20,50 +19,50 @@
18330  /* init the plugin data */
18331  INIT_FUNC(mod_cml_init) {
18332         plugin_data *p;
18333 -       
18334 +
18335         p = calloc(1, sizeof(*p));
18336 -       
18337 +
18338         p->basedir         = buffer_init();
18339         p->baseurl         = buffer_init();
18340         p->trigger_handler = buffer_init();
18341 -       
18342 +
18343         return p;
18344  }
18345  
18346  /* detroy the plugin data */
18347  FREE_FUNC(mod_cml_free) {
18348         plugin_data *p = p_d;
18349 -       
18350 +
18351         UNUSED(srv);
18352  
18353         if (!p) return HANDLER_GO_ON;
18354 -       
18355 +
18356         if (p->config_storage) {
18357                 size_t i;
18358                 for (i = 0; i < srv->config_context->used; i++) {
18359                         plugin_config *s = p->config_storage[i];
18360 -                       
18361 +
18362                         buffer_free(s->ext);
18363 -                       
18364 +
18365                         buffer_free(s->mc_namespace);
18366                         buffer_free(s->power_magnet);
18367                         array_free(s->mc_hosts);
18368 -                       
18369 +
18370  #if defined(HAVE_MEMCACHE_H)
18371                         if (s->mc) mc_free(s->mc);
18372  #endif
18373 -                       
18374 +
18375                         free(s);
18376                 }
18377                 free(p->config_storage);
18378         }
18379 -       
18380 +
18381         buffer_free(p->trigger_handler);
18382         buffer_free(p->basedir);
18383         buffer_free(p->baseurl);
18384 -       
18385 +
18386         free(p);
18387 -       
18388 +
18389         return HANDLER_GO_ON;
18390  }
18391  
18392 @@ -72,22 +71,22 @@
18393  SETDEFAULTS_FUNC(mod_cml_set_defaults) {
18394         plugin_data *p = p_d;
18395         size_t i = 0;
18396 -       
18397 -       config_values_t cv[] = { 
18398 +
18399 +       config_values_t cv[] = {
18400                 { "cml.extension",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
18401                 { "cml.memcache-hosts",         NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },        /* 1 */
18402                 { "cml.memcache-namespace",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
18403                 { "cml.power-magnet",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
18404                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
18405         };
18406 -       
18407 +
18408         if (!p) return HANDLER_ERROR;
18409 -       
18410 +
18411         p->config_storage = malloc(srv->config_context->used * sizeof(specific_config *));
18412 -       
18413 +
18414         for (i = 0; i < srv->config_context->used; i++) {
18415                 plugin_config *s;
18416 -               
18417 +
18418                 s = malloc(sizeof(plugin_config));
18419                 s->ext    = buffer_init();
18420                 s->mc_hosts       = array_init();
18421 @@ -96,87 +95,84 @@
18422  #if defined(HAVE_MEMCACHE_H)
18423                 s->mc = NULL;
18424  #endif
18425 -               
18426 +
18427                 cv[0].destination = s->ext;
18428                 cv[1].destination = s->mc_hosts;
18429                 cv[2].destination = s->mc_namespace;
18430                 cv[3].destination = s->power_magnet;
18431 -               
18432 +
18433                 p->config_storage[i] = s;
18434 -       
18435 +
18436                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
18437                         return HANDLER_ERROR;
18438                 }
18439 -               
18440 +
18441                 if (s->mc_hosts->used) {
18442  #if defined(HAVE_MEMCACHE_H)
18443                         size_t k;
18444                         s->mc = mc_new();
18445 -               
18446 +
18447                         for (k = 0; k < s->mc_hosts->used; k++) {
18448                                 data_string *ds = (data_string *)s->mc_hosts->data[k];
18449 -                               
18450 +
18451                                 if (0 != mc_server_add4(s->mc, ds->value->ptr)) {
18452 -                                       log_error_write(srv, __FILE__, __LINE__, "sb", 
18453 -                                                       "connection to host failed:", 
18454 +                                       log_error_write(srv, __FILE__, __LINE__, "sb",
18455 +                                                       "connection to host failed:",
18456                                                         ds->value);
18457 -                                       
18458 +
18459                                         return HANDLER_ERROR;
18460                                 }
18461                         }
18462  #else
18463 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
18464 +                       log_error_write(srv, __FILE__, __LINE__, "s",
18465                                         "memcache support is not compiled in but cml.memcache-hosts is set, aborting");
18466                         return HANDLER_ERROR;
18467  #endif
18468                 }
18469         }
18470 -       
18471 +
18472         return HANDLER_GO_ON;
18473  }
18474  
18475 -#define PATCH(x) \
18476 -       p->conf.x = s->x;
18477  static int mod_cml_patch_connection(server *srv, connection *con, plugin_data *p) {
18478         size_t i, j;
18479         plugin_config *s = p->config_storage[0];
18480 -       
18481 -       PATCH(ext);
18482 +
18483 +       PATCH_OPTION(ext);
18484  #if defined(HAVE_MEMCACHE_H)
18485 -       PATCH(mc);
18486 +       PATCH_OPTION(mc);
18487  #endif
18488 -       PATCH(mc_namespace);
18489 -       PATCH(power_magnet);
18490 -       
18491 +       PATCH_OPTION(mc_namespace);
18492 +       PATCH_OPTION(power_magnet);
18493 +
18494         /* skip the first, the global context */
18495         for (i = 1; i < srv->config_context->used; i++) {
18496                 data_config *dc = (data_config *)srv->config_context->data[i];
18497                 s = p->config_storage[i];
18498 -               
18499 +
18500                 /* condition didn't match */
18501                 if (!config_check_cond(srv, con, dc)) continue;
18502 -               
18503 +
18504                 /* merge config */
18505                 for (j = 0; j < dc->value->used; j++) {
18506                         data_unset *du = dc->value->data[j];
18507 -                       
18508 +
18509                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.extension"))) {
18510 -                               PATCH(ext);
18511 +                               PATCH_OPTION(ext);
18512                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-hosts"))) {
18513  #if defined(HAVE_MEMCACHE_H)
18514 -                               PATCH(mc);
18515 +                               PATCH_OPTION(mc);
18516  #endif
18517                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-namespace"))) {
18518 -                               PATCH(mc_namespace);
18519 +                               PATCH_OPTION(mc_namespace);
18520                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.power-magnet"))) {
18521 -                               PATCH(power_magnet);
18522 +                               PATCH_OPTION(power_magnet);
18523                         }
18524                 }
18525         }
18526 -       
18527 +
18528         return 0;
18529  }
18530 -#undef PATCH
18531  
18532  int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *cml_file) {
18533         buffer *b;
18534 @@ -187,57 +183,57 @@
18535         b = p->baseurl;
18536         buffer_copy_string_buffer(b, con->uri.path);
18537         for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
18538 -       
18539 +
18540         if (*c == '/') {
18541                 b->used = c - b->ptr + 2;
18542                 *(c+1) = '\0';
18543         }
18544 -       
18545 +
18546         b = p->basedir;
18547         buffer_copy_string_buffer(b, con->physical.path);
18548         for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
18549 -       
18550 +
18551         if (*c == '/') {
18552                 b->used = c - b->ptr + 2;
18553                 *(c+1) = '\0';
18554         }
18555 -       
18556 +
18557  
18558         /* prepare variables
18559          *   - cookie-based
18560          *   - get-param-based
18561          */
18562 -       
18563 +
18564         return cache_parse_lua(srv, con, p, cml_file);
18565 -       
18566 +
18567  }
18568  
18569  URIHANDLER_FUNC(mod_cml_power_magnet) {
18570         plugin_data *p = p_d;
18571 -       
18572 +
18573         mod_cml_patch_connection(srv, con, p);
18574 -       
18575 +
18576         buffer_reset(p->basedir);
18577         buffer_reset(p->baseurl);
18578         buffer_reset(p->trigger_handler);
18579  
18580         if (buffer_is_empty(p->conf.power_magnet)) return HANDLER_GO_ON;
18581 -       
18582 -       /* 
18583 +
18584 +       /*
18585          * power-magnet:
18586          * cml.power-magnet = server.docroot + "/rewrite.cml"
18587          *
18588          * is called on EACH request, take the original REQUEST_URI and modifies the
18589 -        * request header as neccesary. 
18590 +        * request header as neccesary.
18591          *
18592          * First use:
18593          * if file_exists("/maintainance.html") {
18594          *   output_include = ( "/maintainance.html" )
18595 -        *   return CACHE_HIT 
18596 +        *   return CACHE_HIT
18597          * }
18598          *
18599          * as we only want to rewrite HTML like requests we should cover it in a conditional
18600 -        * 
18601 +        *
18602          * */
18603  
18604         switch(cache_call_lua(srv, con, p, p->conf.power_magnet)) {
18605 @@ -266,20 +262,20 @@
18606  
18607  URIHANDLER_FUNC(mod_cml_is_handled) {
18608         plugin_data *p = p_d;
18609 -       
18610 +
18611         if (buffer_is_empty(con->physical.path)) return HANDLER_ERROR;
18612 -       
18613 +
18614         mod_cml_patch_connection(srv, con, p);
18615 -       
18616 +
18617         buffer_reset(p->basedir);
18618         buffer_reset(p->baseurl);
18619         buffer_reset(p->trigger_handler);
18620  
18621         if (buffer_is_empty(p->conf.ext)) return HANDLER_GO_ON;
18622 -       
18623 +
18624         if (!buffer_is_equal_right_len(con->physical.path, p->conf.ext, p->conf.ext->used - 1)) {
18625                 return HANDLER_GO_ON;
18626 -       } 
18627 +       }
18628  
18629         switch(cache_call_lua(srv, con, p, con->physical.path)) {
18630         case -1:
18631 @@ -311,15 +307,15 @@
18632  int mod_cml_plugin_init(plugin *p) {
18633         p->version     = LIGHTTPD_VERSION_ID;
18634         p->name        = buffer_init_string("cache");
18635 -       
18636 +
18637         p->init        = mod_cml_init;
18638         p->cleanup     = mod_cml_free;
18639         p->set_defaults  = mod_cml_set_defaults;
18640 -       
18641 +
18642         p->handle_subrequest_start = mod_cml_is_handled;
18643         p->handle_physical         = mod_cml_power_magnet;
18644 -       
18645 +
18646         p->data        = NULL;
18647 -       
18648 +
18649         return 0;
18650  }
18651 --- ../lighttpd-1.4.11/src/mod_cml.h    2006-01-30 13:51:35.000000000 +0200
18652 +++ lighttpd-1.4.12/src/mod_cml.h       2006-07-16 00:26:03.000000000 +0300
18653 @@ -16,10 +16,10 @@
18654  
18655  typedef struct {
18656         buffer *ext;
18657 -       
18658 +
18659         array  *mc_hosts;
18660         buffer *mc_namespace;
18661 -#if defined(HAVE_MEMCACHE_H) 
18662 +#if defined(HAVE_MEMCACHE_H)
18663         struct memcache *mc;
18664  #endif
18665         buffer *power_magnet;
18666 @@ -27,15 +27,15 @@
18667  
18668  typedef struct {
18669         PLUGIN_DATA;
18670 -       
18671 +
18672         buffer *basedir;
18673         buffer *baseurl;
18674 -       
18675 +
18676         buffer *trigger_handler;
18677 -       
18678 +
18679         plugin_config **config_storage;
18680 -       
18681 -       plugin_config conf; 
18682 +
18683 +       plugin_config conf;
18684  } plugin_data;
18685  
18686  int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn);
18687 --- ../lighttpd-1.4.11/src/mod_cml_funcs.c      2005-11-17 16:15:08.000000000 +0200
18688 +++ lighttpd-1.4.12/src/mod_cml_funcs.c 2006-07-16 00:26:04.000000000 +0300
18689 @@ -4,8 +4,7 @@
18690  #include <stdlib.h>
18691  #include <string.h>
18692  #include <errno.h>
18693 -#include <unistd.h>
18694 -#include <dirent.h>
18695 +
18696  #include <stdio.h>
18697  
18698  #include "buffer.h"
18699 @@ -13,6 +12,7 @@
18700  #include "log.h"
18701  #include "plugin.h"
18702  #include "response.h"
18703 +#include "sys-files.h"
18704  
18705  #include "mod_cml.h"
18706  #include "mod_cml_funcs.h"
18707 @@ -30,7 +30,7 @@
18708  #ifdef USE_OPENSSL
18709  #define IN const
18710  #else
18711 -#define IN 
18712 +#define IN
18713  #endif
18714  #define OUT
18715  
18716 @@ -42,29 +42,29 @@
18717         buffer b;
18718         char hex[33];
18719         int n = lua_gettop(L);
18720 -       
18721 +
18722         b.ptr = hex;
18723         b.used = 0;
18724         b.size = sizeof(hex);
18725 -       
18726 +
18727         if (n != 1) {
18728                 lua_pushstring(L, "md5: expected one argument");
18729                 lua_error(L);
18730         }
18731 -       
18732 +
18733         if (!lua_isstring(L, 1)) {
18734                 lua_pushstring(L, "md5: argument has to be a string");
18735                 lua_error(L);
18736         }
18737 -       
18738 +
18739         MD5_Init(&Md5Ctx);
18740         MD5_Update(&Md5Ctx, (unsigned char *)lua_tostring(L, 1), lua_strlen(L, 1));
18741         MD5_Final(HA1, &Md5Ctx);
18742 -       
18743 +
18744         buffer_copy_string_hex(&b, (char *)HA1, 16);
18745 -       
18746 +
18747         lua_pushstring(L, b.ptr);
18748 -       
18749 +
18750         return 1;
18751  }
18752  
18753 @@ -72,37 +72,37 @@
18754  int f_file_mtime(lua_State *L) {
18755         struct stat st;
18756         int n = lua_gettop(L);
18757 -       
18758 +
18759         if (n != 1) {
18760                 lua_pushstring(L, "file_mtime: expected one argument");
18761                 lua_error(L);
18762         }
18763 -       
18764 +
18765         if (!lua_isstring(L, 1)) {
18766                 lua_pushstring(L, "file_mtime: argument has to be a string");
18767                 lua_error(L);
18768         }
18769 -       
18770 +
18771         if (-1 == stat(lua_tostring(L, 1), &st)) {
18772                 lua_pushnil(L);
18773                 return 1;
18774         }
18775 -       
18776 +
18777         lua_pushnumber(L, st.st_mtime);
18778 -       
18779 +
18780         return 1;
18781  }
18782 -
18783 +#ifndef _WIN32
18784  int f_dir_files_iter(lua_State *L) {
18785         DIR *d;
18786         struct dirent *de;
18787 -       
18788 +
18789         d = lua_touserdata(L, lua_upvalueindex(1));
18790 -       
18791 +
18792         if (NULL == (de = readdir(d))) {
18793                 /* EOF */
18794                 closedir(d);
18795 -               
18796 +
18797                 return 0;
18798         } else {
18799                 lua_pushstring(L, de->d_name);
18800 @@ -113,75 +113,75 @@
18801  int f_dir_files(lua_State *L) {
18802         DIR *d;
18803         int n = lua_gettop(L);
18804 -       
18805 +
18806         if (n != 1) {
18807                 lua_pushstring(L, "dir_files: expected one argument");
18808                 lua_error(L);
18809         }
18810 -       
18811 +
18812         if (!lua_isstring(L, 1)) {
18813                 lua_pushstring(L, "dir_files: argument has to be a string");
18814                 lua_error(L);
18815         }
18816 -       
18817 -       /* check if there is a valid DIR handle on the stack */ 
18818 +
18819 +       /* check if there is a valid DIR handle on the stack */
18820         if (NULL == (d = opendir(lua_tostring(L, 1)))) {
18821                 lua_pushnil(L);
18822                 return 1;
18823         }
18824 -       
18825 +
18826         /* push d into registry */
18827         lua_pushlightuserdata(L, d);
18828         lua_pushcclosure(L, f_dir_files_iter, 1);
18829 -       
18830 +
18831         return 1;
18832  }
18833 -
18834 +#endif
18835  int f_file_isreg(lua_State *L) {
18836         struct stat st;
18837         int n = lua_gettop(L);
18838 -       
18839 +
18840         if (n != 1) {
18841                 lua_pushstring(L, "file_isreg: expected one argument");
18842                 lua_error(L);
18843         }
18844 -       
18845 +
18846         if (!lua_isstring(L, 1)) {
18847                 lua_pushstring(L, "file_isreg: argument has to be a string");
18848                 lua_error(L);
18849         }
18850 -       
18851 +
18852         if (-1 == stat(lua_tostring(L, 1), &st)) {
18853                 lua_pushnil(L);
18854                 return 1;
18855         }
18856 -       
18857 +
18858         lua_pushnumber(L, S_ISREG(st.st_mode));
18859 -       
18860 +
18861         return 1;
18862  }
18863  
18864  int f_file_isdir(lua_State *L) {
18865         struct stat st;
18866         int n = lua_gettop(L);
18867 -       
18868 +
18869         if (n != 1) {
18870                 lua_pushstring(L, "file_isreg: expected one argument");
18871                 lua_error(L);
18872         }
18873 -       
18874 +
18875         if (!lua_isstring(L, 1)) {
18876                 lua_pushstring(L, "file_isreg: argument has to be a string");
18877                 lua_error(L);
18878         }
18879 -       
18880 +
18881         if (-1 == stat(lua_tostring(L, 1), &st)) {
18882                 lua_pushnil(L);
18883                 return 1;
18884         }
18885 -       
18886 +
18887         lua_pushnumber(L, S_ISDIR(st.st_mode));
18888 -       
18889 +
18890         return 1;
18891  }
18892  
18893 @@ -192,33 +192,33 @@
18894         char *r;
18895         int n = lua_gettop(L);
18896         struct memcache *mc;
18897 -       
18898 +
18899         if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
18900                 lua_pushstring(L, "where is my userdata ?");
18901                 lua_error(L);
18902         }
18903 -       
18904 +
18905         mc = lua_touserdata(L, lua_upvalueindex(1));
18906 -       
18907 +
18908         if (n != 1) {
18909                 lua_pushstring(L, "expected one argument");
18910                 lua_error(L);
18911         }
18912 -       
18913 +
18914         if (!lua_isstring(L, 1)) {
18915                 lua_pushstring(L, "argument has to be a string");
18916                 lua_error(L);
18917         }
18918 -       
18919 -       if (NULL == (r = mc_aget(mc, 
18920 +
18921 +       if (NULL == (r = mc_aget(mc,
18922                                  lua_tostring(L, 1), lua_strlen(L, 1)))) {
18923 -                               
18924 +
18925                 lua_pushboolean(L, 0);
18926                 return 1;
18927         }
18928 -       
18929 +
18930         free(r);
18931 -       
18932 +
18933         lua_pushboolean(L, 1);
18934         return 1;
18935  }
18936 @@ -226,74 +226,74 @@
18937  int f_memcache_get_string(lua_State *L) {
18938         char *r;
18939         int n = lua_gettop(L);
18940 -       
18941 +
18942         struct memcache *mc;
18943 -       
18944 +
18945         if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
18946                 lua_pushstring(L, "where is my userdata ?");
18947                 lua_error(L);
18948         }
18949 -       
18950 +
18951         mc = lua_touserdata(L, lua_upvalueindex(1));
18952 -       
18953 -       
18954 +
18955 +
18956         if (n != 1) {
18957                 lua_pushstring(L, "expected one argument");
18958                 lua_error(L);
18959         }
18960 -       
18961 +
18962         if (!lua_isstring(L, 1)) {
18963                 lua_pushstring(L, "argument has to be a string");
18964                 lua_error(L);
18965         }
18966 -       
18967 -       if (NULL == (r = mc_aget(mc, 
18968 +
18969 +       if (NULL == (r = mc_aget(mc,
18970                                  lua_tostring(L, 1), lua_strlen(L, 1)))) {
18971                 lua_pushnil(L);
18972                 return 1;
18973         }
18974 -       
18975 +
18976         lua_pushstring(L, r);
18977 -       
18978 +
18979         free(r);
18980 -       
18981 +
18982         return 1;
18983  }
18984  
18985  int f_memcache_get_long(lua_State *L) {
18986         char *r;
18987         int n = lua_gettop(L);
18988 -       
18989 +
18990         struct memcache *mc;
18991 -       
18992 +
18993         if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
18994                 lua_pushstring(L, "where is my userdata ?");
18995                 lua_error(L);
18996         }
18997 -       
18998 +
18999         mc = lua_touserdata(L, lua_upvalueindex(1));
19000 -       
19001 -       
19002 +
19003 +
19004         if (n != 1) {
19005                 lua_pushstring(L, "expected one argument");
19006                 lua_error(L);
19007         }
19008 -       
19009 +
19010         if (!lua_isstring(L, 1)) {
19011                 lua_pushstring(L, "argument has to be a string");
19012                 lua_error(L);
19013         }
19014 -       
19015 -       if (NULL == (r = mc_aget(mc, 
19016 +
19017 +       if (NULL == (r = mc_aget(mc,
19018                                  lua_tostring(L, 1), lua_strlen(L, 1)))) {
19019                 lua_pushnil(L);
19020                 return 1;
19021         }
19022 -       
19023 +
19024         lua_pushnumber(L, strtol(r, NULL, 10));
19025 -       
19026 +
19027         free(r);
19028 -       
19029 +
19030         return 1;
19031  }
19032  #endif
19033 --- ../lighttpd-1.4.11/src/mod_cml_lua.c        2006-01-30 13:56:40.000000000 +0200
19034 +++ lighttpd-1.4.12/src/mod_cml_lua.c   2006-07-16 00:26:04.000000000 +0300
19035 @@ -23,7 +23,7 @@
19036  #ifdef USE_OPENSSL
19037  #define IN const
19038  #else
19039 -#define IN 
19040 +#define IN
19041  #endif
19042  #define OUT
19043  
19044 @@ -31,6 +31,7 @@
19045  
19046  #include <lua.h>
19047  #include <lualib.h>
19048 +#include <lauxlib.h>
19049  
19050  typedef struct {
19051         stream st;
19052 @@ -39,11 +40,11 @@
19053  
19054  static const char * load_file(lua_State *L, void *data, size_t *size) {
19055         readme *rm = data;
19056 -       
19057 +
19058         UNUSED(L);
19059 -       
19060 +
19061         if (rm->done) return 0;
19062 -       
19063 +
19064         *size = rm->st.size;
19065         rm->done = 1;
19066         return rm->st.start;
19067 @@ -51,47 +52,47 @@
19068  
19069  static int lua_to_c_get_string(lua_State *L, const char *varname, buffer *b) {
19070         int curelem;
19071 -       
19072 +
19073         lua_pushstring(L, varname);
19074 -       
19075 +
19076         curelem = lua_gettop(L);
19077         lua_gettable(L, LUA_GLOBALSINDEX);
19078 -       
19079 +
19080         /* it should be a table */
19081         if (!lua_isstring(L, curelem)) {
19082                 lua_settop(L, curelem - 1);
19083 -               
19084 +
19085                 return -1;
19086         }
19087 -       
19088 +
19089         buffer_copy_string(b, lua_tostring(L, curelem));
19090 -       
19091 +
19092         lua_pop(L, 1);
19093 -       
19094 +
19095         assert(curelem - 1 == lua_gettop(L));
19096 -       
19097 +
19098         return 0;
19099  }
19100  
19101  static int lua_to_c_is_table(lua_State *L, const char *varname) {
19102         int curelem;
19103 -       
19104 +
19105         lua_pushstring(L, varname);
19106 -       
19107 +
19108         curelem = lua_gettop(L);
19109         lua_gettable(L, LUA_GLOBALSINDEX);
19110 -       
19111 +
19112         /* it should be a table */
19113         if (!lua_istable(L, curelem)) {
19114                 lua_settop(L, curelem - 1);
19115 -               
19116 +
19117                 return 0;
19118         }
19119 -       
19120 +
19121         lua_settop(L, curelem - 1);
19122 -       
19123 +
19124         assert(curelem - 1 == lua_gettop(L));
19125 -       
19126 +
19127         return 1;
19128  }
19129  
19130 @@ -99,7 +100,7 @@
19131         lua_pushlstring(L, key, key_len);
19132         lua_pushlstring(L, val, val_len);
19133         lua_settable(L, tbl);
19134 -       
19135 +
19136         return 0;
19137  }
19138  
19139 @@ -108,21 +109,21 @@
19140         size_t is_key = 1;
19141         size_t i;
19142         char *key = NULL, *val = NULL;
19143 -       
19144 +
19145         key = qrystr->ptr;
19146 -       
19147 +
19148         /* we need the \0 */
19149         for (i = 0; i < qrystr->used; i++) {
19150                 switch(qrystr->ptr[i]) {
19151                 case '=':
19152                         if (is_key) {
19153                                 val = qrystr->ptr + i + 1;
19154 -                               
19155 +
19156                                 qrystr->ptr[i] = '\0';
19157 -                               
19158 +
19159                                 is_key = 0;
19160                         }
19161 -                       
19162 +
19163                         break;
19164                 case '&':
19165                 case '\0': /* fin symbol */
19166 @@ -131,19 +132,19 @@
19167  
19168                                 /* terminate the value */
19169                                 qrystr->ptr[i] = '\0';
19170 -                               
19171 -                               c_to_lua_push(L, tbl, 
19172 +
19173 +                               c_to_lua_push(L, tbl,
19174                                               key, strlen(key),
19175                                               val, strlen(val));
19176                         }
19177 -                       
19178 +
19179                         key = qrystr->ptr + i + 1;
19180                         val = NULL;
19181                         is_key = 1;
19182                         break;
19183                 }
19184         }
19185 -       
19186 +
19187         return 0;
19188  }
19189  #if 0
19190 @@ -151,21 +152,21 @@
19191         data_unset *d;
19192  
19193         UNUSED(srv);
19194 -       
19195 +
19196         if (NULL != (d = array_get_element(con->request.headers, "Cookie"))) {
19197                 data_string *ds = (data_string *)d;
19198                 size_t key = 0, value = 0;
19199                 size_t is_key = 1, is_sid = 0;
19200                 size_t i;
19201 -               
19202 +
19203                 /* found COOKIE */
19204                 if (!DATA_IS_STRING(d)) return -1;
19205                 if (ds->value->used == 0) return -1;
19206 -                       
19207 +
19208                 if (ds->value->ptr[0] == '\0' ||
19209                     ds->value->ptr[0] == '=' ||
19210                     ds->value->ptr[0] == ';') return -1;
19211 -               
19212 +
19213                 buffer_reset(p->session_id);
19214                 for (i = 0; i < ds->value->used; i++) {
19215                         switch(ds->value->ptr[i]) {
19216 @@ -176,16 +177,16 @@
19217                                                 is_sid = 1;
19218                                         }
19219                                         value = i + 1;
19220 -                               
19221 +
19222                                         is_key = 0;
19223                                 }
19224 -                               
19225 +
19226                                 break;
19227                         case ';':
19228                                 if (is_sid) {
19229                                         buffer_copy_string_len(p->session_id, ds->value->ptr + value, i - value);
19230                                 }
19231 -                               
19232 +
19233                                 is_sid = 0;
19234                                 key = i + 1;
19235                                 value = 0;
19236 @@ -204,48 +205,43 @@
19237                         }
19238                 }
19239         }
19240 -       
19241 +
19242         return 0;
19243  }
19244  #endif
19245  
19246  int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
19247 -       lua_State *L; 
19248 +       lua_State *L;
19249         readme rm;
19250         int ret = -1;
19251         buffer *b = buffer_init();
19252         int header_tbl = 0;
19253 -       
19254 +
19255         rm.done = 0;
19256         stream_open(&rm.st, fn);
19257 -       
19258 +
19259         /* push the lua file to the interpreter and see what happends */
19260 -       L = lua_open();
19261 -       
19262 -       luaopen_base(L);
19263 -       luaopen_table(L);
19264 -       luaopen_string(L);
19265 -       luaopen_math(L);
19266 -       luaopen_io(L);
19267 -       
19268 +       L = luaL_newstate();
19269 +       luaL_openlibs(L);
19270 +
19271         /* register functions */
19272         lua_register(L, "md5", f_crypto_md5);
19273         lua_register(L, "file_mtime", f_file_mtime);
19274         lua_register(L, "file_isreg", f_file_isreg);
19275         lua_register(L, "file_isdir", f_file_isreg);
19276         lua_register(L, "dir_files", f_dir_files);
19277 -       
19278 +
19279  #ifdef HAVE_MEMCACHE_H
19280         lua_pushliteral(L, "memcache_get_long");
19281         lua_pushlightuserdata(L, p->conf.mc);
19282         lua_pushcclosure(L, f_memcache_get_long, 1);
19283         lua_settable(L, LUA_GLOBALSINDEX);
19284 -       
19285 +
19286         lua_pushliteral(L, "memcache_get_string");
19287         lua_pushlightuserdata(L, p->conf.mc);
19288         lua_pushcclosure(L, f_memcache_get_string, 1);
19289         lua_settable(L, LUA_GLOBALSINDEX);
19290 -       
19291 +
19292         lua_pushliteral(L, "memcache_exists");
19293         lua_pushlightuserdata(L, p->conf.mc);
19294         lua_pushcclosure(L, f_memcache_exists, 1);
19295 @@ -255,11 +251,11 @@
19296         lua_pushliteral(L, "request");
19297         lua_newtable(L);
19298         lua_settable(L, LUA_GLOBALSINDEX);
19299 -       
19300 +
19301         lua_pushliteral(L, "request");
19302         header_tbl = lua_gettop(L);
19303         lua_gettable(L, LUA_GLOBALSINDEX);
19304 -       
19305 +
19306         c_to_lua_push(L, header_tbl, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
19307         c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
19308         c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
19309 @@ -267,84 +263,84 @@
19310         if (!buffer_is_empty(con->request.pathinfo)) {
19311                 c_to_lua_push(L, header_tbl, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
19312         }
19313 -       
19314 +
19315         c_to_lua_push(L, header_tbl, CONST_STR_LEN("CWD"), CONST_BUF_LEN(p->basedir));
19316         c_to_lua_push(L, header_tbl, CONST_STR_LEN("BASEURL"), CONST_BUF_LEN(p->baseurl));
19317 -       
19318 +
19319         /* register GET parameter */
19320         lua_pushliteral(L, "get");
19321         lua_newtable(L);
19322         lua_settable(L, LUA_GLOBALSINDEX);
19323 -       
19324 +
19325         lua_pushliteral(L, "get");
19326         header_tbl = lua_gettop(L);
19327         lua_gettable(L, LUA_GLOBALSINDEX);
19328 -       
19329 +
19330         buffer_copy_string_buffer(b, con->uri.query);
19331         cache_export_get_params(L, header_tbl, b);
19332         buffer_reset(b);
19333  
19334 -       /* 2 default constants */       
19335 +       /* 2 default constants */
19336         lua_pushliteral(L, "CACHE_HIT");
19337         lua_pushboolean(L, 0);
19338         lua_settable(L, LUA_GLOBALSINDEX);
19339 -       
19340 +
19341         lua_pushliteral(L, "CACHE_MISS");
19342         lua_pushboolean(L, 1);
19343         lua_settable(L, LUA_GLOBALSINDEX);
19344 -       
19345 +
19346         /* load lua program */
19347         if (lua_load(L, load_file, &rm, fn->ptr) || lua_pcall(L,0,1,0)) {
19348                 log_error_write(srv, __FILE__, __LINE__, "s",
19349                                 lua_tostring(L,-1));
19350 -               
19351 +
19352                 goto error;
19353         }
19354 -       
19355 +
19356         /* get return value */
19357         ret = (int)lua_tonumber(L, -1);
19358         lua_pop(L, 1);
19359 -       
19360 -       /* fetch the data from lua */ 
19361 +
19362 +       /* fetch the data from lua */
19363         lua_to_c_get_string(L, "trigger_handler", p->trigger_handler);
19364 -       
19365 +
19366         if (0 == lua_to_c_get_string(L, "output_contenttype", b)) {
19367                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(b));
19368         }
19369 -       
19370 +
19371         if (ret == 0) {
19372                 /* up to now it is a cache-hit, check if all files exist */
19373 -               
19374 +
19375                 int curelem;
19376                 time_t mtime = 0;
19377 -       
19378 +
19379                 if (!lua_to_c_is_table(L, "output_include")) {
19380                         log_error_write(srv, __FILE__, __LINE__, "s",
19381                                 "output_include is missing or not a table");
19382                         ret = -1;
19383 -               
19384 +
19385                         goto error;
19386                 }
19387 -               
19388 +
19389                 lua_pushstring(L, "output_include");
19390 -               
19391 +
19392                 curelem = lua_gettop(L);
19393                 lua_gettable(L, LUA_GLOBALSINDEX);
19394  
19395                 /* HOW-TO build a etag ?
19396 -                * as we don't just have one file we have to take the stat() 
19397 +                * as we don't just have one file we have to take the stat()
19398                  * from all base files, merge them and build the etag from
19399                  * it later.
19400 -                * 
19401 +                *
19402                  * The mtime of the content is the mtime of the freshest base file
19403 -                * 
19404 +                *
19405                  * */
19406 -               
19407 +
19408                 lua_pushnil(L);  /* first key */
19409                 while (lua_next(L, curelem) != 0) {
19410                         stat_cache_entry *sce = NULL;
19411                         /* key' is at index -2 and value' at index -1 */
19412 -                       
19413 +
19414                         if (lua_isstring(L, -1)) {
19415                                 const char *s = lua_tostring(L, -1);
19416  
19417 @@ -364,18 +360,18 @@
19418                                                 /* a file is missing, call the handler to generate it */
19419                                                 if (!buffer_is_empty(p->trigger_handler)) {
19420                                                         ret = 1; /* cache-miss */
19421 -                                                       
19422 +
19423                                                         log_error_write(srv, __FILE__, __LINE__, "s",
19424                                                                         "a file is missing, calling handler");
19425 -                                                       
19426 +
19427                                                         break;
19428                                                 } else {
19429                                                         /* handler not set -> 500 */
19430                                                         ret = -1;
19431 -                                                       
19432 +
19433                                                         log_error_write(srv, __FILE__, __LINE__, "s",
19434                                                                         "a file missing and no handler set");
19435 -                                                       
19436 +
19437                                                         break;
19438                                                 }
19439                                                 break;
19440 @@ -393,12 +389,12 @@
19441                                                 "not a string");
19442                                 break;
19443                         }
19444 -               
19445 +
19446                         lua_pop(L, 1);  /* removes value'; keeps key' for next iteration */
19447                 }
19448 -               
19449 +
19450                 lua_settop(L, curelem - 1);
19451 -               
19452 +
19453                 if (ret == 0) {
19454                         data_string *ds;
19455                         char timebuf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
19456 @@ -410,9 +406,9 @@
19457  
19458                         /* no Last-Modified specified */
19459                         if ((mtime) && (NULL == ds)) {
19460 -               
19461 +
19462                                 strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&mtime));
19463 -                               
19464 +
19465                                 response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), timebuf, sizeof(timebuf) - 1);
19466  
19467  
19468 @@ -428,9 +424,9 @@
19469                                 tbuf.used = 0;
19470                                 tbuf.ptr = NULL;
19471                         }
19472 -                       
19473 +
19474                         if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, &tbuf)) {
19475 -                               /* ok, the client already has our content, 
19476 +                               /* ok, the client already has our content,
19477                                  * no need to send it again */
19478  
19479                                 chunkqueue_reset(con->write_queue);
19480 @@ -440,24 +436,24 @@
19481                         chunkqueue_reset(con->write_queue);
19482                 }
19483         }
19484 -       
19485 +
19486         if (ret == 1 && !buffer_is_empty(p->trigger_handler)) {
19487                 /* cache-miss */
19488                 buffer_copy_string_buffer(con->uri.path, p->baseurl);
19489                 buffer_append_string_buffer(con->uri.path, p->trigger_handler);
19490 -       
19491 +
19492                 buffer_copy_string_buffer(con->physical.path, p->basedir);
19493                 buffer_append_string_buffer(con->physical.path, p->trigger_handler);
19494 -               
19495 +
19496                 chunkqueue_reset(con->write_queue);
19497         }
19498 -       
19499 +
19500  error:
19501         lua_close(L);
19502 -       
19503 +
19504         stream_close(&rm.st);
19505         buffer_free(b);
19506 -       
19507 +
19508         return ret /* cache-error */;
19509  }
19510  #else
19511 --- ../lighttpd-1.4.11/src/mod_compress.c       2005-11-18 13:49:14.000000000 +0200
19512 +++ lighttpd-1.4.12/src/mod_compress.c  2006-07-16 00:26:04.000000000 +0300
19513 @@ -2,7 +2,6 @@
19514  #include <sys/stat.h>
19515  
19516  #include <fcntl.h>
19517 -#include <unistd.h>
19518  #include <ctype.h>
19519  #include <stdlib.h>
19520  #include <string.h>
19521 @@ -14,6 +13,7 @@
19522  #include "buffer.h"
19523  #include "response.h"
19524  #include "stat_cache.h"
19525 +#include "http_chunk.h"
19526  
19527  #include "plugin.h"
19528  
19529 @@ -33,6 +33,7 @@
19530  #endif
19531  
19532  #include "sys-mmap.h"
19533 +#include "sys-files.h"
19534  
19535  /* request: accept-encoding */
19536  #define HTTP_ACCEPT_ENCODING_IDENTITY BV(0)
19537 @@ -55,97 +56,127 @@
19538         PLUGIN_DATA;
19539         buffer *ofn;
19540         buffer *b;
19541 -       
19542 +
19543         plugin_config **config_storage;
19544 -       plugin_config conf; 
19545 +       plugin_config conf;
19546  } plugin_data;
19547  
19548  INIT_FUNC(mod_compress_init) {
19549         plugin_data *p;
19550 -       
19551 +
19552         p = calloc(1, sizeof(*p));
19553 -       
19554 +
19555         p->ofn = buffer_init();
19556         p->b = buffer_init();
19557 -       
19558 +
19559         return p;
19560  }
19561  
19562  FREE_FUNC(mod_compress_free) {
19563         plugin_data *p = p_d;
19564 -       
19565 +
19566         UNUSED(srv);
19567  
19568         if (!p) return HANDLER_GO_ON;
19569 -       
19570 +
19571         buffer_free(p->ofn);
19572         buffer_free(p->b);
19573 -       
19574 +
19575         if (p->config_storage) {
19576                 size_t i;
19577                 for (i = 0; i < srv->config_context->used; i++) {
19578                         plugin_config *s = p->config_storage[i];
19579  
19580                         if (!s) continue;
19581 -                       
19582 +
19583                         array_free(s->compress);
19584                         buffer_free(s->compress_cache_dir);
19585 -                       
19586 +
19587                         free(s);
19588                 }
19589                 free(p->config_storage);
19590         }
19591 -       
19592 -       
19593 +
19594 +
19595         free(p);
19596 -       
19597 +
19598         return HANDLER_GO_ON;
19599  }
19600  
19601 +void mkdir_recursive(const char *dir) {
19602 +
19603 +       char dir_copy[256];
19604 +       char *p = dir_copy;
19605 +
19606 +       if (!dir || !dir[0])
19607 +               return;
19608 +
19609 +       strncpy(dir_copy, dir, sizeof(dir_copy) / sizeof(dir_copy[0]));
19610 +
19611 +       while ((p = strchr(p + 1, '/')) != NULL) {
19612 +
19613 +               *p = '\0';
19614 +               if ((mkdir(dir_copy, 0700) != 0) && (errno != EEXIST))
19615 +                       return;
19616 +
19617 +               *p++ = '/';
19618 +       }
19619 +
19620 +       mkdir(dir, 0700);
19621 +}
19622 +
19623  SETDEFAULTS_FUNC(mod_compress_setdefaults) {
19624         plugin_data *p = p_d;
19625         size_t i = 0;
19626 -       
19627 -       config_values_t cv[] = { 
19628 +
19629 +       config_values_t cv[] = {
19630                 { "compress.cache-dir",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
19631                 { "compress.filetype",              NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
19632                 { "compress.max-filesize",          NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
19633                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
19634         };
19635 -       
19636 +
19637         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
19638 -       
19639 +
19640         for (i = 0; i < srv->config_context->used; i++) {
19641                 plugin_config *s;
19642 -               
19643 +
19644                 s = calloc(1, sizeof(plugin_config));
19645                 s->compress_cache_dir = buffer_init();
19646                 s->compress = array_init();
19647                 s->compress_max_filesize = 0;
19648 -               
19649 +
19650                 cv[0].destination = s->compress_cache_dir;
19651                 cv[1].destination = s->compress;
19652                 cv[2].destination = &(s->compress_max_filesize);
19653 -               
19654 +
19655                 p->config_storage[i] = s;
19656 -       
19657 +
19658                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
19659                         return HANDLER_ERROR;
19660                 }
19661 -               
19662 +
19663                 if (!buffer_is_empty(s->compress_cache_dir)) {
19664                         struct stat st;
19665                         if (0 != stat(s->compress_cache_dir->ptr, &st)) {
19666 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir", 
19667 +
19668 +                               log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir, attempting to create",
19669                                                 s->compress_cache_dir, strerror(errno));
19670 -                               
19671 -                               return HANDLER_ERROR;
19672 +                               mkdir_recursive(s->compress_cache_dir->ptr);
19673 +
19674 +                               if (0 != stat(s->compress_cache_dir->ptr, &st)) {
19675 +
19676 +                                       log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir, create failed",
19677 +                                                                       s->compress_cache_dir, strerror(errno));
19678 +
19679 +                                       return HANDLER_ERROR;
19680 +                               }
19681                         }
19682                 }
19683         }
19684 -       
19685 +
19686         return HANDLER_GO_ON;
19687 -       
19688 +
19689  }
19690  
19691  #ifdef USE_ZLIB
19692 @@ -153,32 +184,32 @@
19693         unsigned char *c;
19694         unsigned long crc;
19695         z_stream z;
19696 -       
19697 +
19698         UNUSED(srv);
19699         UNUSED(con);
19700  
19701         z.zalloc = Z_NULL;
19702         z.zfree = Z_NULL;
19703         z.opaque = Z_NULL;
19704 -       
19705 -       if (Z_OK != deflateInit2(&z, 
19706 +
19707 +       if (Z_OK != deflateInit2(&z,
19708                                  Z_DEFAULT_COMPRESSION,
19709 -                                Z_DEFLATED, 
19710 +                                Z_DEFLATED,
19711                                  -MAX_WBITS,  /* supress zlib-header */
19712                                  8,
19713                                  Z_DEFAULT_STRATEGY)) {
19714                 return -1;
19715         }
19716 -               
19717 +
19718         z.next_in = (unsigned char *)start;
19719         z.avail_in = st_size;
19720         z.total_in = 0;
19721 -               
19722 -                       
19723 +
19724 +
19725         buffer_prepare_copy(p->b, (z.avail_in * 1.1) + 12 + 18);
19726 -               
19727 +
19728         /* write gzip header */
19729 -               
19730 +
19731         c = (unsigned char *)p->b->ptr;
19732         c[0] = 0x1f;
19733         c[1] = 0x8b;
19734 @@ -190,24 +221,24 @@
19735         c[7] = (mtime >> 24) & 0xff;
19736         c[8] = 0x00; /* extra flags */
19737         c[9] = 0x03; /* UNIX */
19738 -       
19739 +
19740         p->b->used = 10;
19741         z.next_out = (unsigned char *)p->b->ptr + p->b->used;
19742         z.avail_out = p->b->size - p->b->used - 8;
19743         z.total_out = 0;
19744 -       
19745 +
19746         if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
19747                 deflateEnd(&z);
19748                 return -1;
19749         }
19750 -       
19751 +
19752         /* trailer */
19753         p->b->used += z.total_out;
19754 -       
19755 +
19756         crc = generate_crc32c(start, st_size);
19757 -               
19758 +
19759         c = (unsigned char *)p->b->ptr + p->b->used;
19760 -               
19761 +
19762         c[0] = (crc >>  0) & 0xff;
19763         c[1] = (crc >>  8) & 0xff;
19764         c[2] = (crc >> 16) & 0xff;
19765 @@ -221,51 +252,51 @@
19766         if (Z_OK != deflateEnd(&z)) {
19767                 return -1;
19768         }
19769 -       
19770 +
19771         return 0;
19772  }
19773  
19774  static int deflate_file_to_buffer_deflate(server *srv, connection *con, plugin_data *p, unsigned char *start, off_t st_size) {
19775         z_stream z;
19776 -       
19777 +
19778         UNUSED(srv);
19779         UNUSED(con);
19780  
19781         z.zalloc = Z_NULL;
19782         z.zfree = Z_NULL;
19783         z.opaque = Z_NULL;
19784 -       
19785 -       if (Z_OK != deflateInit2(&z, 
19786 +
19787 +       if (Z_OK != deflateInit2(&z,
19788                                  Z_DEFAULT_COMPRESSION,
19789 -                                Z_DEFLATED, 
19790 +                                Z_DEFLATED,
19791                                  -MAX_WBITS,  /* supress zlib-header */
19792                                  8,
19793                                  Z_DEFAULT_STRATEGY)) {
19794                 return -1;
19795         }
19796 -               
19797 +
19798         z.next_in = start;
19799         z.avail_in = st_size;
19800         z.total_in = 0;
19801 -               
19802 +
19803         buffer_prepare_copy(p->b, (z.avail_in * 1.1) + 12);
19804 -       
19805 +
19806         z.next_out = (unsigned char *)p->b->ptr;
19807         z.avail_out = p->b->size;
19808         z.total_out = 0;
19809 -       
19810 +
19811         if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
19812                 deflateEnd(&z);
19813                 return -1;
19814         }
19815 -       
19816 +
19817         /* trailer */
19818         p->b->used += z.total_out;
19819 -       
19820 +
19821         if (Z_OK != deflateEnd(&z)) {
19822                 return -1;
19823         }
19824 -       
19825 +
19826         return 0;
19827  }
19828  
19829 @@ -274,48 +305,48 @@
19830  #ifdef USE_BZ2LIB
19831  static int deflate_file_to_buffer_bzip2(server *srv, connection *con, plugin_data *p, unsigned char *start, off_t st_size) {
19832         bz_stream bz;
19833 -       
19834 +
19835         UNUSED(srv);
19836         UNUSED(con);
19837  
19838         bz.bzalloc = NULL;
19839         bz.bzfree = NULL;
19840         bz.opaque = NULL;
19841 -       
19842 -       if (BZ_OK != BZ2_bzCompressInit(&bz, 
19843 +
19844 +       if (BZ_OK != BZ2_bzCompressInit(&bz,
19845                                         9, /* blocksize = 900k */
19846                                         0, /* no output */
19847                                         0)) { /* workFactor: default */
19848                 return -1;
19849         }
19850 -               
19851 +
19852         bz.next_in = (char *)start;
19853         bz.avail_in = st_size;
19854         bz.total_in_lo32 = 0;
19855         bz.total_in_hi32 = 0;
19856 -               
19857 +
19858         buffer_prepare_copy(p->b, (bz.avail_in * 1.1) + 12);
19859 -       
19860 +
19861         bz.next_out = p->b->ptr;
19862         bz.avail_out = p->b->size;
19863         bz.total_out_lo32 = 0;
19864         bz.total_out_hi32 = 0;
19865 -       
19866 +
19867         if (BZ_STREAM_END != BZ2_bzCompress(&bz, BZ_FINISH)) {
19868                 BZ2_bzCompressEnd(&bz);
19869                 return -1;
19870         }
19871 -       
19872 +
19873         /* file is too large for now */
19874         if (bz.total_out_hi32) return -1;
19875 -       
19876 +
19877         /* trailer */
19878         p->b->used = bz.total_out_lo32;
19879 -       
19880 +
19881         if (BZ_OK != BZ2_bzCompressEnd(&bz)) {
19882                 return -1;
19883         }
19884 -       
19885 +
19886         return 0;
19887  }
19888  #endif
19889 @@ -326,47 +357,50 @@
19890         void *start;
19891         const char *filename = fn->ptr;
19892         ssize_t r;
19893 -       
19894 +       stat_cache_entry *compressed_sce = NULL;
19895 +
19896 +       if (buffer_is_empty(p->conf.compress_cache_dir)) return -1;
19897 +
19898         /* overflow */
19899         if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
19900 -       
19901 -       /* don't mmap files > 128Mb 
19902 -        * 
19903 +
19904 +       /* don't mmap files > 128Mb
19905 +        *
19906          * we could use a sliding window, but currently there is no need for it
19907          */
19908 -       
19909 +
19910         if (sce->st.st_size > 128 * 1024 * 1024) return -1;
19911 -       
19912 +
19913         buffer_reset(p->ofn);
19914         buffer_copy_string_buffer(p->ofn, p->conf.compress_cache_dir);
19915 -       BUFFER_APPEND_SLASH(p->ofn);
19916 -       
19917 +       PATHNAME_APPEND_SLASH(p->ofn);
19918 +
19919         if (0 == strncmp(con->physical.path->ptr, con->physical.doc_root->ptr, con->physical.doc_root->used-1)) {
19920                 size_t offset = p->ofn->used - 1;
19921                 char *dir, *nextdir;
19922 -               
19923 +
19924                 buffer_append_string(p->ofn, con->physical.path->ptr + con->physical.doc_root->used - 1);
19925 -               
19926 +
19927                 buffer_copy_string_buffer(p->b, p->ofn);
19928 -               
19929 +
19930                 /* mkdir -p ... */
19931                 for (dir = p->b->ptr + offset; NULL != (nextdir = strchr(dir, '/')); dir = nextdir + 1) {
19932                         *nextdir = '\0';
19933 -                       
19934 +
19935                         if (-1 == mkdir(p->b->ptr, 0700)) {
19936                                 if (errno != EEXIST) {
19937                                         log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cache-directory", p->b, "failed", strerror(errno));
19938 -                                       
19939 +
19940                                         return -1;
19941                                 }
19942                         }
19943 -                       
19944 +
19945                         *nextdir = '/';
19946                 }
19947         } else {
19948                 buffer_append_string_buffer(p->ofn, con->uri.path);
19949         }
19950 -       
19951 +
19952         switch(type) {
19953         case HTTP_ACCEPT_ENCODING_GZIP:
19954                 buffer_append_string(p->ofn, "-gzip-");
19955 @@ -381,55 +415,64 @@
19956                 log_error_write(srv, __FILE__, __LINE__, "sd", "unknown compression type", type);
19957                 return -1;
19958         }
19959 -       
19960 +
19961         buffer_append_string_buffer(p->ofn, sce->etag);
19962 -       
19963 +
19964 +
19965 +       if (HANDLER_ERROR != stat_cache_get_entry(srv, con, p->ofn, &compressed_sce)) {
19966 +               /* file exists */
19967 +
19968 +               http_chunk_append_file(srv, con, p->ofn, 0, compressed_sce->st.st_size);
19969 +               con->file_finished = 1;
19970 +
19971 +               return 0;
19972 +       }
19973 +
19974         if (-1 == (ofd = open(p->ofn->ptr, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0600))) {
19975                 if (errno == EEXIST) {
19976                         /* cache-entry exists */
19977 -#if 0
19978 -                       log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache hit");
19979 -#endif
19980 -                       buffer_copy_string_buffer(con->physical.path, p->ofn);
19981 -                       
19982 -                       return 0;
19983 +
19984                 }
19985 -               
19986 -               log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cachefile", p->ofn, "failed", strerror(errno));
19987 -               
19988 +
19989 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
19990 +                               "creating cachefile", p->ofn,
19991 +                               "failed", strerror(errno));
19992 +
19993                 return -1;
19994         }
19995 -#if 0
19996 -       log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache miss");
19997 -#endif 
19998 +
19999         if (-1 == (ifd = open(filename, O_RDONLY | O_BINARY))) {
20000 -               log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-file", fn, "failed", strerror(errno));
20001 -               
20002 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
20003 +                               "opening plain-file", fn,
20004 +                               "failed", strerror(errno));
20005 +
20006                 close(ofd);
20007 -               
20008 +
20009                 return -1;
20010         }
20011 -       
20012 -       
20013 +
20014 +
20015         if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
20016 -               log_error_write(srv, __FILE__, __LINE__, "sbss", "mmaping", fn, "failed", strerror(errno));
20017 -               
20018 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
20019 +                               "mmaping", fn,
20020 +                               "failed", strerror(errno));
20021 +
20022                 close(ofd);
20023                 close(ifd);
20024                 return -1;
20025         }
20026 -       
20027 +
20028         switch(type) {
20029  #ifdef USE_ZLIB
20030 -       case HTTP_ACCEPT_ENCODING_GZIP: 
20031 +       case HTTP_ACCEPT_ENCODING_GZIP:
20032                 ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime);
20033                 break;
20034 -       case HTTP_ACCEPT_ENCODING_DEFLATE: 
20035 +       case HTTP_ACCEPT_ENCODING_DEFLATE:
20036                 ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size);
20037                 break;
20038  #endif
20039  #ifdef USE_BZ2LIB
20040 -       case HTTP_ACCEPT_ENCODING_BZIP2: 
20041 +       case HTTP_ACCEPT_ENCODING_BZIP2:
20042                 ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
20043                 break;
20044  #endif
20045 @@ -437,26 +480,27 @@
20046                 ret = -1;
20047                 break;
20048         }
20049 -       
20050 +
20051         if (-1 == (r = write(ofd, p->b->ptr, p->b->used))) {
20052 -               munmap(start, sce->st.st_size); 
20053 +               munmap(start, sce->st.st_size);
20054                 close(ofd);
20055                 close(ifd);
20056                 return -1;
20057         }
20058 -       
20059 +
20060         if ((size_t)r != p->b->used) {
20061 -               
20062 +
20063         }
20064 -               
20065 +
20066         munmap(start, sce->st.st_size);
20067         close(ofd);
20068         close(ifd);
20069 -       
20070 +
20071         if (ret != 0) return -1;
20072 -       
20073 -       buffer_copy_string_buffer(con->physical.path, p->ofn);
20074 -       
20075 +
20076 +       http_chunk_append_file(srv, con, p->ofn, 0, r);
20077 +       con->file_finished = 1;
20078 +
20079         return 0;
20080  }
20081  
20082 @@ -465,43 +509,44 @@
20083         int ret = -1;
20084         void *start;
20085         buffer *b;
20086 -       
20087 +
20088         /* overflow */
20089         if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
20090 -       
20091 +
20092         /* don't mmap files > 128M
20093 -        * 
20094 +        *
20095          * we could use a sliding window, but currently there is no need for it
20096          */
20097 -       
20098 +
20099         if (sce->st.st_size > 128 * 1024 * 1024) return -1;
20100 -       
20101 -       
20102 +
20103         if (-1 == (ifd = open(fn->ptr, O_RDONLY | O_BINARY))) {
20104                 log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-file", fn, "failed", strerror(errno));
20105 -               
20106 +
20107                 return -1;
20108         }
20109 -       
20110 -       
20111 -       if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
20112 +
20113 +       start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0);
20114 +
20115 +       close(ifd);
20116 +
20117 +       if (MAP_FAILED == start) {
20118                 log_error_write(srv, __FILE__, __LINE__, "sbss", "mmaping", fn, "failed", strerror(errno));
20119 -               
20120 -               close(ifd);
20121 +
20122                 return -1;
20123         }
20124 -       
20125 +
20126         switch(type) {
20127  #ifdef USE_ZLIB
20128 -       case HTTP_ACCEPT_ENCODING_GZIP: 
20129 +       case HTTP_ACCEPT_ENCODING_GZIP:
20130                 ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime);
20131                 break;
20132 -       case HTTP_ACCEPT_ENCODING_DEFLATE: 
20133 +       case HTTP_ACCEPT_ENCODING_DEFLATE:
20134                 ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size);
20135                 break;
20136  #endif
20137  #ifdef USE_BZ2LIB
20138 -       case HTTP_ACCEPT_ENCODING_BZIP2: 
20139 +       case HTTP_ACCEPT_ENCODING_BZIP2:
20140                 ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
20141                 break;
20142  #endif
20143 @@ -509,69 +554,64 @@
20144                 ret = -1;
20145                 break;
20146         }
20147 -               
20148 +
20149         munmap(start, sce->st.st_size);
20150 -       close(ifd);
20151 -       
20152 +
20153         if (ret != 0) return -1;
20154 -       
20155 +
20156         chunkqueue_reset(con->write_queue);
20157         b = chunkqueue_get_append_buffer(con->write_queue);
20158         buffer_copy_memory(b, p->b->ptr, p->b->used + 1);
20159 -       
20160 +
20161         buffer_reset(con->physical.path);
20162 -       
20163 +
20164         con->file_finished = 1;
20165         con->file_started  = 1;
20166 -       
20167 +
20168         return 0;
20169  }
20170  
20171 -
20172 -#define PATCH(x) \
20173 -       p->conf.x = s->x;
20174  static int mod_compress_patch_connection(server *srv, connection *con, plugin_data *p) {
20175         size_t i, j;
20176         plugin_config *s = p->config_storage[0];
20177  
20178 -       PATCH(compress_cache_dir);
20179 -       PATCH(compress);
20180 -       PATCH(compress_max_filesize);
20181 -       
20182 +       PATCH_OPTION(compress_cache_dir);
20183 +       PATCH_OPTION(compress);
20184 +       PATCH_OPTION(compress_max_filesize);
20185 +
20186         /* skip the first, the global context */
20187         for (i = 1; i < srv->config_context->used; i++) {
20188                 data_config *dc = (data_config *)srv->config_context->data[i];
20189                 s = p->config_storage[i];
20190 -               
20191 +
20192                 /* condition didn't match */
20193                 if (!config_check_cond(srv, con, dc)) continue;
20194 -               
20195 +
20196                 /* merge config */
20197                 for (j = 0; j < dc->value->used; j++) {
20198                         data_unset *du = dc->value->data[j];
20199 -                       
20200 +
20201                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.cache-dir"))) {
20202 -                               PATCH(compress_cache_dir);
20203 +                               PATCH_OPTION(compress_cache_dir);
20204                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.filetype"))) {
20205 -                               PATCH(compress);
20206 +                               PATCH_OPTION(compress);
20207                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.max-filesize"))) {
20208 -                               PATCH(compress_max_filesize);
20209 +                               PATCH_OPTION(compress_max_filesize);
20210                         }
20211                 }
20212         }
20213 -       
20214 +
20215         return 0;
20216  }
20217 -#undef PATCH
20218  
20219  PHYSICALPATH_FUNC(mod_compress_physical) {
20220         plugin_data *p = p_d;
20221         size_t m;
20222         off_t max_fsize;
20223         stat_cache_entry *sce = NULL;
20224 -       
20225 +
20226         /* only GET and POST can get compressed */
20227 -       if (con->request.http_method != HTTP_METHOD_GET && 
20228 +       if (con->request.http_method != HTTP_METHOD_GET &&
20229             con->request.http_method != HTTP_METHOD_POST) {
20230                 return HANDLER_GO_ON;
20231         }
20232 @@ -579,46 +619,49 @@
20233         if (buffer_is_empty(con->physical.path)) {
20234                 return HANDLER_GO_ON;
20235         }
20236 -       
20237 +
20238         mod_compress_patch_connection(srv, con, p);
20239 -       
20240 +
20241         max_fsize = p->conf.compress_max_filesize;
20242  
20243         stat_cache_get_entry(srv, con, con->physical.path, &sce);
20244  
20245         /* don't compress files that are too large as we need to much time to handle them */
20246         if (max_fsize && (sce->st.st_size >> 10) > max_fsize) return HANDLER_GO_ON;
20247 -               
20248 +
20249 +       /* compressing the file might lead to larger files instead */
20250 +       if (sce->st.st_size < 128) return HANDLER_GO_ON;
20251 +
20252         /* check if mimetype is in compress-config */
20253         for (m = 0; m < p->conf.compress->used; m++) {
20254                 data_string *compress_ds = (data_string *)p->conf.compress->data[m];
20255 -                       
20256 +
20257                 if (!compress_ds) {
20258                         log_error_write(srv, __FILE__, __LINE__, "sbb", "evil", con->physical.path, con->uri.path);
20259 -                       
20260 +
20261                         return HANDLER_GO_ON;
20262                 }
20263 -               
20264 +
20265                 if (buffer_is_equal(compress_ds->value, sce->content_type)) {
20266                         /* mimetype found */
20267                         data_string *ds;
20268 -                               
20269 +
20270                         /* the response might change according to Accept-Encoding */
20271                         response_header_insert(srv, con, CONST_STR_LEN("Vary"), CONST_STR_LEN("Accept-Encoding"));
20272 -                               
20273 +
20274                         if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Accept-Encoding"))) {
20275                                 int accept_encoding = 0;
20276                                 char *value = ds->value->ptr;
20277                                 int srv_encodings = 0;
20278                                 int matched_encodings = 0;
20279 -                               
20280 +
20281                                 /* get client side support encodings */
20282                                 if (NULL != strstr(value, "gzip")) accept_encoding |= HTTP_ACCEPT_ENCODING_GZIP;
20283                                 if (NULL != strstr(value, "deflate")) accept_encoding |= HTTP_ACCEPT_ENCODING_DEFLATE;
20284                                 if (NULL != strstr(value, "compress")) accept_encoding |= HTTP_ACCEPT_ENCODING_COMPRESS;
20285                                 if (NULL != strstr(value, "bzip2")) accept_encoding |= HTTP_ACCEPT_ENCODING_BZIP2;
20286                                 if (NULL != strstr(value, "identity")) accept_encoding |= HTTP_ACCEPT_ENCODING_IDENTITY;
20287 -                               
20288 +
20289                                 /* get server side supported ones */
20290  #ifdef USE_BZ2LIB
20291                                 srv_encodings |= HTTP_ACCEPT_ENCODING_BZIP2;
20292 @@ -627,18 +670,31 @@
20293                                 srv_encodings |= HTTP_ACCEPT_ENCODING_GZIP;
20294                                 srv_encodings |= HTTP_ACCEPT_ENCODING_DEFLATE;
20295  #endif
20296 -                               
20297 +
20298                                 /* find matching entries */
20299                                 matched_encodings = accept_encoding & srv_encodings;
20300 -                               
20301 +
20302                                 if (matched_encodings) {
20303                                         const char *dflt_gzip = "gzip";
20304                                         const char *dflt_deflate = "deflate";
20305                                         const char *dflt_bzip2 = "bzip2";
20306 -                                       
20307 +
20308                                         const char *compression_name = NULL;
20309                                         int compression_type = 0;
20310 -                                       
20311 +                                       buffer *mtime;
20312 +
20313 +                                       mtime = strftime_cache_get(srv, sce->st.st_mtime);
20314 +                                       etag_mutate(con->physical.etag, sce->etag);
20315 +
20316 +                                       response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
20317 +                                       response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
20318 +
20319 +                                       /* perhaps we don't even have to compress the file as the browser still has the
20320 +                                        * current version */
20321 +                                       if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
20322 +                                               return HANDLER_FINISHED;
20323 +                                       }
20324 +
20325                                         /* select best matching encoding */
20326                                         if (matched_encodings & HTTP_ACCEPT_ENCODING_BZIP2) {
20327                                                 compression_type = HTTP_ACCEPT_ENCODING_BZIP2;
20328 @@ -650,31 +706,21 @@
20329                                                 compression_type = HTTP_ACCEPT_ENCODING_DEFLATE;
20330                                                 compression_name = dflt_deflate;
20331                                         }
20332 -                                       
20333 -                                       /* deflate it */
20334 -                                       if (p->conf.compress_cache_dir->used) {
20335 -                                               if (0 == deflate_file_to_file(srv, con, p,
20336 -                                                                             con->physical.path, sce, compression_type)) {
20337 -                                                       buffer *mtime;
20338 -                                                       
20339 -                                                       response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
20340 -                                                       
20341 -                                                       mtime = strftime_cache_get(srv, sce->st.st_mtime);
20342 -                                                       response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
20343 -
20344 -                                                       etag_mutate(con->physical.etag, sce->etag);
20345 -                                                       response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
20346 -
20347 -                                                       response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
20348 -
20349 -                                                       return HANDLER_GO_ON;
20350 -                                               }
20351 -                                       } else if (0 == deflate_file_to_buffer(srv, con, p,
20352 -                                                                              con->physical.path, sce, compression_type)) {
20353 -                                                       
20354 -                                               response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
20355 -                                               response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
20356 -                                               
20357 +
20358 +                                       /* deflate it to file (cached) or to memory */
20359 +                                       if (0 == deflate_file_to_file(srv, con, p,
20360 +                                                       con->physical.path, sce, compression_type) ||
20361 +                                           0 == deflate_file_to_buffer(srv, con, p,
20362 +                                                       con->physical.path, sce, compression_type)) {
20363 +
20364 +                                               response_header_overwrite(srv, con,
20365 +                                                               CONST_STR_LEN("Content-Encoding"),
20366 +                                                               compression_name, strlen(compression_name));
20367 +
20368 +                                               response_header_overwrite(srv, con,
20369 +                                                               CONST_STR_LEN("Content-Type"),
20370 +                                                               CONST_BUF_LEN(sce->content_type));
20371 +
20372                                                 return HANDLER_FINISHED;
20373                                         }
20374                                         break;
20375 @@ -682,20 +728,20 @@
20376                         }
20377                 }
20378         }
20379 -       
20380 +
20381         return HANDLER_GO_ON;
20382  }
20383  
20384  int mod_compress_plugin_init(plugin *p) {
20385         p->version     = LIGHTTPD_VERSION_ID;
20386         p->name        = buffer_init_string("compress");
20387 -       
20388 +
20389         p->init        = mod_compress_init;
20390         p->set_defaults = mod_compress_setdefaults;
20391         p->handle_subrequest_start  = mod_compress_physical;
20392         p->cleanup     = mod_compress_free;
20393 -       
20394 +
20395         p->data        = NULL;
20396 -       
20397 +
20398         return 0;
20399  }
20400 --- ../lighttpd-1.4.11/src/mod_dirlisting.c     2006-01-13 00:00:45.000000000 +0200
20401 +++ lighttpd-1.4.12/src/mod_dirlisting.c        2006-07-16 00:26:04.000000000 +0300
20402 @@ -1,11 +1,9 @@
20403  #include <ctype.h>
20404  #include <stdlib.h>
20405  #include <string.h>
20406 -#include <dirent.h>
20407  #include <assert.h>
20408  #include <errno.h>
20409  #include <stdio.h>
20410 -#include <unistd.h>
20411  #include <time.h>
20412  
20413  #include "base.h"
20414 @@ -17,6 +15,9 @@
20415  #include "response.h"
20416  #include "stat_cache.h"
20417  #include "stream.h"
20418 +#include "etag.h"
20419 +
20420 +#include "sys-strings.h"
20421  
20422  /**
20423   * this is a dirlisting for a lighttpd plugin
20424 @@ -27,10 +28,13 @@
20425  #include <sys/syslimits.h>
20426  #endif
20427  
20428 -#ifdef HAVE_ATTR_ATTRIBUTES_H
20429 +#ifdef HAVE_XATTR
20430  #include <attr/attributes.h>
20431  #endif
20432  
20433 +#include "sys-files.h"
20434 +#include "sys-strings.h"
20435 +
20436  /* plugin config for all request/connections */
20437  
20438  typedef struct {
20439 @@ -54,7 +58,7 @@
20440         unsigned short hide_readme_file;
20441         unsigned short show_header;
20442         unsigned short hide_header_file;
20443 -       
20444 +
20445         excludes_buffer *excludes;
20446  
20447         buffer *external_css;
20448 @@ -63,13 +67,14 @@
20449  
20450  typedef struct {
20451         PLUGIN_DATA;
20452 -       
20453 +
20454         buffer *tmp_buf;
20455         buffer *content_charset;
20456 -       
20457 +       buffer *path;
20458 +
20459         plugin_config **config_storage;
20460 -       
20461 -       plugin_config conf; 
20462 +
20463 +       plugin_config conf;
20464  } plugin_data;
20465  
20466  excludes_buffer *excludes_buffer_init(void) {
20467 @@ -146,44 +151,46 @@
20468  /* init the plugin data */
20469  INIT_FUNC(mod_dirlisting_init) {
20470         plugin_data *p;
20471 -       
20472 +
20473         p = calloc(1, sizeof(*p));
20474  
20475         p->tmp_buf = buffer_init();
20476         p->content_charset = buffer_init();
20477 -       
20478 +       p->path = buffer_init();
20479 +
20480         return p;
20481  }
20482  
20483  /* detroy the plugin data */
20484  FREE_FUNC(mod_dirlisting_free) {
20485         plugin_data *p = p_d;
20486 -       
20487 +
20488         UNUSED(srv);
20489  
20490         if (!p) return HANDLER_GO_ON;
20491 -       
20492 +
20493         if (p->config_storage) {
20494                 size_t i;
20495                 for (i = 0; i < srv->config_context->used; i++) {
20496                         plugin_config *s = p->config_storage[i];
20497 -                       
20498 +
20499                         if (!s) continue;
20500 -                       
20501 +
20502                         excludes_buffer_free(s->excludes);
20503                         buffer_free(s->external_css);
20504                         buffer_free(s->encoding);
20505 -                       
20506 +
20507                         free(s);
20508                 }
20509                 free(p->config_storage);
20510         }
20511 -       
20512 +
20513         buffer_free(p->tmp_buf);
20514 +       buffer_free(p->path);
20515         buffer_free(p->content_charset);
20516 -       
20517 +
20518         free(p);
20519 -       
20520 +
20521         return HANDLER_GO_ON;
20522  }
20523  
20524 @@ -215,10 +222,10 @@
20525                         if (0 != excludes_buffer_append(s->excludes,
20526                                     ((data_string *)(da->value->data[j]))->value)) {
20527  #ifdef HAVE_PCRE_H
20528 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
20529 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
20530                                                 "pcre-compile failed for", ((data_string *)(da->value->data[j]))->value);
20531  #else
20532 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
20533 +                               log_error_write(srv, __FILE__, __LINE__, "s",
20534                                                 "pcre support is missing, please install libpcre and the headers");
20535  #endif
20536                         }
20537 @@ -233,8 +240,8 @@
20538  SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
20539         plugin_data *p = p_d;
20540         size_t i = 0;
20541 -       
20542 -       config_values_t cv[] = { 
20543 +
20544 +       config_values_t cv[] = {
20545                 { "dir-listing.exclude",          NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },   /* 0 */
20546                 { "dir-listing.activate",         NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
20547                 { "dir-listing.hide-dotfiles",    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
20548 @@ -245,18 +252,18 @@
20549                 { "dir-listing.show-header",      NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
20550                 { "dir-listing.hide-header-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
20551                 { "server.dir-listing",           NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
20552 -               
20553 +
20554                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
20555         };
20556 -       
20557 +
20558         if (!p) return HANDLER_ERROR;
20559 -       
20560 +
20561         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
20562 -       
20563 +
20564         for (i = 0; i < srv->config_context->used; i++) {
20565                 plugin_config *s;
20566                 array *ca;
20567 -               
20568 +
20569                 s = calloc(1, sizeof(plugin_config));
20570                 s->excludes = excludes_buffer_init();
20571                 s->dir_listing = 0;
20572 @@ -267,7 +274,7 @@
20573                 s->show_header = 0;
20574                 s->hide_header_file = 0;
20575                 s->encoding = buffer_init();
20576 -               
20577 +
20578                 cv[0].destination = s->excludes;
20579                 cv[1].destination = &(s->dir_listing);
20580                 cv[2].destination = &(s->hide_dot_files);
20581 @@ -292,60 +299,57 @@
20582         return HANDLER_GO_ON;
20583  }
20584  
20585 -#define PATCH(x) \
20586 -       p->conf.x = s->x;
20587  static int mod_dirlisting_patch_connection(server *srv, connection *con, plugin_data *p) {
20588         size_t i, j;
20589         plugin_config *s = p->config_storage[0];
20590  
20591 -       PATCH(dir_listing);
20592 -       PATCH(external_css);
20593 -       PATCH(hide_dot_files);
20594 -       PATCH(encoding);
20595 -       PATCH(show_readme);
20596 -       PATCH(hide_readme_file);
20597 -       PATCH(show_header);
20598 -       PATCH(hide_header_file);
20599 -       PATCH(excludes);
20600 -       
20601 +       PATCH_OPTION(dir_listing);
20602 +       PATCH_OPTION(external_css);
20603 +       PATCH_OPTION(hide_dot_files);
20604 +       PATCH_OPTION(encoding);
20605 +       PATCH_OPTION(show_readme);
20606 +       PATCH_OPTION(hide_readme_file);
20607 +       PATCH_OPTION(show_header);
20608 +       PATCH_OPTION(hide_header_file);
20609 +       PATCH_OPTION(excludes);
20610 +
20611         /* skip the first, the global context */
20612         for (i = 1; i < srv->config_context->used; i++) {
20613                 data_config *dc = (data_config *)srv->config_context->data[i];
20614                 s = p->config_storage[i];
20615 -               
20616 +
20617                 /* condition didn't match */
20618                 if (!config_check_cond(srv, con, dc)) continue;
20619 -               
20620 +
20621                 /* merge config */
20622                 for (j = 0; j < dc->value->used; j++) {
20623                         data_unset *du = dc->value->data[j];
20624 -                       
20625 +
20626                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.activate")) ||
20627                             buffer_is_equal_string(du->key, CONST_STR_LEN("server.dir-listing"))) {
20628 -                               PATCH(dir_listing);
20629 +                               PATCH_OPTION(dir_listing);
20630                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-dotfiles"))) {
20631 -                               PATCH(hide_dot_files);
20632 +                               PATCH_OPTION(hide_dot_files);
20633                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.external-css"))) {
20634 -                               PATCH(external_css);
20635 +                               PATCH_OPTION(external_css);
20636                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.encoding"))) {
20637 -                               PATCH(encoding);
20638 +                               PATCH_OPTION(encoding);
20639                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-readme"))) {
20640 -                               PATCH(show_readme);
20641 +                               PATCH_OPTION(show_readme);
20642                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-readme-file"))) {
20643 -                               PATCH(hide_readme_file);
20644 +                               PATCH_OPTION(hide_readme_file);
20645                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-header"))) {
20646 -                               PATCH(show_header);
20647 +                               PATCH_OPTION(show_header);
20648                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-header-file"))) {
20649 -                               PATCH(hide_header_file);
20650 +                               PATCH_OPTION(hide_header_file);
20651                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.excludes"))) {
20652 -                               PATCH(excludes);
20653 +                               PATCH_OPTION(excludes);
20654                         }
20655                 }
20656         }
20657 -       
20658 +
20659         return 0;
20660  }
20661 -#undef PATCH
20662  
20663  typedef struct {
20664         size_t  namelen;
20665 @@ -432,7 +436,7 @@
20666  
20667  static void http_list_directory_header(server *srv, connection *con, plugin_data *p, buffer *out) {
20668         UNUSED(srv);
20669 -       
20670 +
20671         BUFFER_APPEND_STRING_CONST(out,
20672                 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
20673                 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n"
20674 @@ -492,11 +496,11 @@
20675         if (p->conf.show_header) {
20676                 stream s;
20677                 /* if we have a HEADER file, display it in <pre class="header"></pre> */
20678 -               
20679 +
20680                 buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
20681 -               BUFFER_APPEND_SLASH(p->tmp_buf);
20682 +               PATHNAME_APPEND_SLASH(p->tmp_buf);
20683                 BUFFER_APPEND_STRING_CONST(p->tmp_buf, "HEADER.txt");
20684 -               
20685 +
20686                 if (-1 != stream_open(&s, p->tmp_buf)) {
20687                         BUFFER_APPEND_STRING_CONST(out, "<pre class=\"header\">");
20688                         buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
20689 @@ -531,21 +535,21 @@
20690  
20691  static void http_list_directory_footer(server *srv, connection *con, plugin_data *p, buffer *out) {
20692         UNUSED(srv);
20693 -       
20694 +
20695         BUFFER_APPEND_STRING_CONST(out,
20696                 "</tbody>\n"
20697                 "</table>\n"
20698                 "</div>\n"
20699         );
20700 -       
20701 +
20702         if (p->conf.show_readme) {
20703                 stream s;
20704                 /* if we have a README file, display it in <pre class="readme"></pre> */
20705 -               
20706 +
20707                 buffer_copy_string_buffer(p->tmp_buf,  con->physical.path);
20708 -               BUFFER_APPEND_SLASH(p->tmp_buf);
20709 +               PATHNAME_APPEND_SLASH(p->tmp_buf);
20710                 BUFFER_APPEND_STRING_CONST(p->tmp_buf, "README.txt");
20711 -               
20712 +
20713                 if (-1 != stream_open(&s, p->tmp_buf)) {
20714                         BUFFER_APPEND_STRING_CONST(out, "<pre class=\"readme\">");
20715                         buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
20716 @@ -553,7 +557,7 @@
20717                 }
20718                 stream_close(&s);
20719         }
20720 -       
20721 +
20722         BUFFER_APPEND_STRING_CONST(out,
20723                 "<div class=\"foot\">"
20724         );
20725 @@ -576,7 +580,6 @@
20726         buffer *out;
20727         struct dirent *dent;
20728         struct stat st;
20729 -       char *path, *path_file;
20730         size_t i;
20731         int hide_dotfiles = p->conf.hide_dot_files;
20732         dirls_list_t dirs, files, *list;
20733 @@ -586,6 +589,7 @@
20734         size_t k;
20735         const char *content_type;
20736         long name_max;
20737 +
20738  #ifdef HAVE_XATTR
20739         char attrval[128];
20740         int attrlen;
20741 @@ -594,10 +598,10 @@
20742         struct tm tm;
20743  #endif
20744  
20745 -       if (dir->used == 0) return -1;
20746 -       
20747 -       i = dir->used - 1;
20748 +       /* empty pathname, never ... */
20749 +       if (buffer_is_empty(dir)) return -1;
20750  
20751 +       /* max-length for the opendir */
20752  #ifdef HAVE_PATHCONF
20753         if (-1 == (name_max = pathconf(dir->ptr, _PC_NAME_MAX))) {
20754  #ifdef NAME_MAX
20755 @@ -606,22 +610,24 @@
20756                 name_max = 256; /* stupid default */
20757  #endif
20758         }
20759 -#elif defined __WIN32
20760 +#elif defined _WIN32
20761         name_max = FILENAME_MAX;
20762  #else
20763         name_max = NAME_MAX;
20764  #endif
20765 -       
20766 -       path = malloc(dir->used + name_max);
20767 -       assert(path);
20768 -       strcpy(path, dir->ptr);
20769 -       path_file = path + i;
20770  
20771 -       if (NULL == (dp = opendir(path))) {
20772 -               log_error_write(srv, __FILE__, __LINE__, "sbs", 
20773 +       buffer_copy_string_buffer(p->path, dir);
20774 +       PATHNAME_APPEND_SLASH(p->path);
20775 +
20776 +#ifdef _WIN32
20777 +       /* append *.* to the path */
20778 +       buffer_append_string(path, "*.*");
20779 +#endif
20780 +
20781 +       if (NULL == (dp = opendir(p->path->ptr))) {
20782 +               log_error_write(srv, __FILE__, __LINE__, "sbs",
20783                         "opendir failed:", dir, strerror(errno));
20784  
20785 -               free(path);
20786                 return -1;
20787         }
20788  
20789 @@ -633,7 +639,7 @@
20790         assert(files.ent);
20791         files.size = DIRLIST_BLOB_SIZE;
20792         files.used = 0;
20793 -       
20794 +
20795         while ((dent = readdir(dp)) != NULL) {
20796                 unsigned short exclude_match = 0;
20797  
20798 @@ -686,15 +692,21 @@
20799  #endif
20800  
20801                 i = strlen(dent->d_name);
20802 -               
20803 +
20804                 /* NOTE: the manual says, d_name is never more than NAME_MAX
20805                  *       so this should actually not be a buffer-overflow-risk
20806                  */
20807                 if (i > (size_t)name_max) continue;
20808 -               
20809 -               memcpy(path_file, dent->d_name, i + 1);
20810 -               if (stat(path, &st) != 0)
20811 +
20812 +               /* build the dirname */
20813 +               buffer_copy_string_buffer(p->path, dir);
20814 +               PATHNAME_APPEND_SLASH(p->path);
20815 +               buffer_append_string(p->path, dent->d_name);
20816 +
20817 +               if (stat(p->path->ptr, &st) != 0) {
20818 +                       fprintf(stderr, "%s.%d: %s, %s\r\n", __FILE__, __LINE__, p->path->ptr, strerror(errno));
20819                         continue;
20820 +               }
20821  
20822                 list = &files;
20823                 if (S_ISDIR(st.st_mode))
20824 @@ -740,7 +752,7 @@
20825  #else
20826                 strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime)));
20827  #endif
20828 -               
20829 +
20830                 BUFFER_APPEND_STRING_CONST(out, "<tr><td class=\"n\"><a href=\"");
20831                 buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART);
20832                 BUFFER_APPEND_STRING_CONST(out, "/\">");
20833 @@ -757,18 +769,22 @@
20834                 tmp = files.ent[i];
20835  
20836                 content_type = NULL;
20837 +
20838  #ifdef HAVE_XATTR
20839 -               
20840                 if (con->conf.use_xattr) {
20841 -                       memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1);
20842 +                       /* build the dirname */
20843 +                       buffer_copy_string_buffer(p->path, dir);
20844 +                       PATHNAME_APPEND_SLASH(p->path);
20845 +                       buffer_append_string_len(p->path, DIRLIST_ENT_NAME(tmp), tmp->namelen);
20846 +
20847                         attrlen = sizeof(attrval) - 1;
20848 -                       if (attr_get(path, "Content-Type", attrval, &attrlen, 0) == 0) {
20849 +                       if (attr_get(p->path->ptr, "Content-Type", attrval, &attrlen, 0) == 0) {
20850                                 attrval[attrlen] = '\0';
20851                                 content_type = attrval;
20852                         }
20853                 }
20854  #endif
20855 -               
20856 +
20857                 if (content_type == NULL) {
20858                         content_type = "application/octet-stream";
20859                         for (k = 0; k < con->conf.mimetypes->used; k++) {
20860 @@ -788,7 +804,7 @@
20861                                 }
20862                         }
20863                 }
20864 -                       
20865 +
20866  #ifdef HAVE_LOCALTIME_R
20867                 localtime_r(&(tmp->mtime), &tm);
20868                 strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm);
20869 @@ -814,7 +830,6 @@
20870  
20871         free(files.ent);
20872         free(dirs.ent);
20873 -       free(path);
20874  
20875         http_list_directory_footer(srv, con, p, out);
20876  
20877 @@ -837,36 +852,55 @@
20878  URIHANDLER_FUNC(mod_dirlisting_subrequest) {
20879         plugin_data *p = p_d;
20880         stat_cache_entry *sce = NULL;
20881 -       
20882 -       UNUSED(srv);
20883 -       
20884 -       if (con->physical.path->used == 0) return HANDLER_GO_ON;
20885 -       if (con->uri.path->used == 0) return HANDLER_GO_ON;
20886 +       buffer *mtime;
20887 +       data_string *ds;
20888 +
20889 +       if (con->uri.path->used < 2) return HANDLER_GO_ON;
20890         if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
20891 -       
20892 +       if (con->physical.path->used == 0) return HANDLER_GO_ON;
20893 +
20894         mod_dirlisting_patch_connection(srv, con, p);
20895  
20896         if (!p->conf.dir_listing) return HANDLER_GO_ON;
20897 -       
20898 +
20899 +       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
20900 +               /* just a second ago the file was still there */
20901 +               return HANDLER_GO_ON;
20902 +       }
20903 +
20904 +       if (!S_ISDIR(sce->st.st_mode)) return HANDLER_GO_ON;
20905 +
20906         if (con->conf.log_request_handling) {
20907                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling the request as Dir-Listing");
20908                 log_error_write(srv, __FILE__, __LINE__,  "sb", "URI          :", con->uri.path);
20909         }
20910 -       
20911 -       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
20912 -               fprintf(stderr, "%s.%d: %s\n", __FILE__, __LINE__, con->physical.path->ptr);
20913 -               SEGFAULT();
20914 +
20915 +       /* perhaps this a cachable request
20916 +        * - we use the etag of the directory
20917 +        * */
20918 +
20919 +       etag_mutate(con->physical.etag, sce->etag);
20920 +       response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
20921 +
20922 +       /* prepare header */
20923 +       if (NULL == (ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"))) {
20924 +               mtime = strftime_cache_get(srv, sce->st.st_mtime);
20925 +               response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
20926 +       } else {
20927 +               mtime = ds->value;
20928         }
20929 -       
20930 -       if (!S_ISDIR(sce->st.st_mode)) return HANDLER_GO_ON;
20931 -       
20932 +
20933 +       if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
20934 +               return HANDLER_FINISHED;
20935 +       }
20936 +
20937         if (http_list_directory(srv, con, p, con->physical.path)) {
20938                 /* dirlisting failed */
20939                 con->http_status = 403;
20940         }
20941 -       
20942 +
20943         buffer_reset(con->physical.path);
20944 -       
20945 +
20946         /* not found */
20947         return HANDLER_FINISHED;
20948  }
20949 @@ -876,13 +910,13 @@
20950  int mod_dirlisting_plugin_init(plugin *p) {
20951         p->version     = LIGHTTPD_VERSION_ID;
20952         p->name        = buffer_init_string("dirlisting");
20953 -       
20954 +
20955         p->init        = mod_dirlisting_init;
20956         p->handle_subrequest_start  = mod_dirlisting_subrequest;
20957         p->set_defaults  = mod_dirlisting_set_defaults;
20958         p->cleanup     = mod_dirlisting_free;
20959 -       
20960 +
20961         p->data        = NULL;
20962 -       
20963 +
20964         return 0;
20965  }
20966 --- ../lighttpd-1.4.11/src/mod_evasive.c        2006-01-04 15:24:51.000000000 +0200
20967 +++ lighttpd-1.4.12/src/mod_evasive.c   2006-07-16 00:26:04.000000000 +0300
20968 @@ -31,100 +31,97 @@
20969  
20970  typedef struct {
20971         PLUGIN_DATA;
20972 -       
20973 +
20974         plugin_config **config_storage;
20975 -       
20976 -       plugin_config conf; 
20977 +
20978 +       plugin_config conf;
20979  } plugin_data;
20980  
20981  INIT_FUNC(mod_evasive_init) {
20982         plugin_data *p;
20983 -       
20984 +
20985         p = calloc(1, sizeof(*p));
20986 -       
20987 +
20988         return p;
20989  }
20990  
20991  FREE_FUNC(mod_evasive_free) {
20992         plugin_data *p = p_d;
20993 -       
20994 +
20995         UNUSED(srv);
20996  
20997         if (!p) return HANDLER_GO_ON;
20998 -       
20999 +
21000         if (p->config_storage) {
21001                 size_t i;
21002                 for (i = 0; i < srv->config_context->used; i++) {
21003                         plugin_config *s = p->config_storage[i];
21004 -                                               
21005 +
21006                         free(s);
21007                 }
21008                 free(p->config_storage);
21009         }
21010 -       
21011 +
21012         free(p);
21013 -       
21014 +
21015         return HANDLER_GO_ON;
21016  }
21017  
21018  SETDEFAULTS_FUNC(mod_evasive_set_defaults) {
21019         plugin_data *p = p_d;
21020         size_t i = 0;
21021 -       
21022 -       config_values_t cv[] = { 
21023 +
21024 +       config_values_t cv[] = {
21025                 { "evasive.max-conns-per-ip",    NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
21026                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
21027         };
21028 -       
21029 +
21030         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
21031 -       
21032 +
21033         for (i = 0; i < srv->config_context->used; i++) {
21034                 plugin_config *s;
21035 -               
21036 +
21037                 s = calloc(1, sizeof(plugin_config));
21038                 s->max_conns       = 0;
21039 -               
21040 +
21041                 cv[0].destination = &(s->max_conns);
21042 -               
21043 +
21044                 p->config_storage[i] = s;
21045 -       
21046 +
21047                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
21048                         return HANDLER_ERROR;
21049                 }
21050         }
21051 -       
21052 +
21053         return HANDLER_GO_ON;
21054  }
21055  
21056 -#define PATCH(x) \
21057 -       p->conf.x = s->x;
21058  static int mod_evasive_patch_connection(server *srv, connection *con, plugin_data *p) {
21059         size_t i, j;
21060         plugin_config *s = p->config_storage[0];
21061  
21062 -       PATCH(max_conns);
21063 -       
21064 +       PATCH_OPTION(max_conns);
21065 +
21066         /* skip the first, the global context */
21067         for (i = 1; i < srv->config_context->used; i++) {
21068                 data_config *dc = (data_config *)srv->config_context->data[i];
21069                 s = p->config_storage[i];
21070 -               
21071 +
21072                 /* condition didn't match */
21073                 if (!config_check_cond(srv, con, dc)) continue;
21074 -               
21075 +
21076                 /* merge config */
21077                 for (j = 0; j < dc->value->used; j++) {
21078                         data_unset *du = dc->value->data[j];
21079 -                       
21080 +
21081                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("evasive.max-conns-per-ip"))) {
21082 -                               PATCH(max_conns);
21083 +                               PATCH_OPTION(max_conns);
21084                         }
21085                 }
21086         }
21087 -       
21088 +
21089         return 0;
21090  }
21091 -#undef PATCH
21092  
21093  URIHANDLER_FUNC(mod_evasive_uri_handler) {
21094         plugin_data *p = p_d;
21095 @@ -132,10 +129,10 @@
21096         size_t j;
21097  
21098         if (con->uri.path->used == 0) return HANDLER_GO_ON;
21099 -       
21100 +
21101         mod_evasive_patch_connection(srv, con, p);
21102 -       
21103 -       /* no limit set, nothing to block */    
21104 +
21105 +       /* no limit set, nothing to block */
21106         if (p->conf.max_conns == 0) return HANDLER_GO_ON;
21107  
21108         for (j = 0; j < srv->conns->used; j++) {
21109 @@ -147,7 +144,7 @@
21110                 if (c->dst_addr.ipv4.sin_addr.s_addr == con->dst_addr.ipv4.sin_addr.s_addr &&
21111                     c->state > CON_STATE_REQUEST_END) {
21112                         conns_by_ip++;
21113 -       
21114 +
21115                         if (conns_by_ip > p->conf.max_conns) {
21116                                 log_error_write(srv, __FILE__, __LINE__, "ss",
21117                                         inet_ntop_cache_get_ip(srv, &(con->dst_addr)),
21118 @@ -158,7 +155,7 @@
21119                         }
21120                 }
21121         }
21122 -       
21123 +
21124         return HANDLER_GO_ON;
21125  }
21126  
21127 @@ -166,13 +163,13 @@
21128  int mod_evasive_plugin_init(plugin *p) {
21129         p->version     = LIGHTTPD_VERSION_ID;
21130         p->name        = buffer_init_string("evasive");
21131 -       
21132 +
21133         p->init        = mod_evasive_init;
21134         p->set_defaults = mod_evasive_set_defaults;
21135         p->handle_uri_clean  = mod_evasive_uri_handler;
21136         p->cleanup     = mod_evasive_free;
21137 -       
21138 +
21139         p->data        = NULL;
21140 -       
21141 +
21142         return 0;
21143  }
21144 --- ../lighttpd-1.4.11/src/mod_evhost.c 2005-08-17 10:42:03.000000000 +0300
21145 +++ lighttpd-1.4.12/src/mod_evhost.c    2006-07-16 00:26:03.000000000 +0300
21146 @@ -7,10 +7,12 @@
21147  #include "response.h"
21148  #include "stat_cache.h"
21149  
21150 +#include "sys-files.h"
21151 +
21152  typedef struct {
21153         /* unparsed pieces */
21154         buffer *path_pieces_raw;
21155 -       
21156 +
21157         /* pieces for path creation */
21158         size_t len;
21159         buffer **path_pieces;
21160 @@ -21,14 +23,14 @@
21161         buffer *tmp_buf;
21162  
21163         plugin_config **config_storage;
21164 -       plugin_config conf; 
21165 +       plugin_config conf;
21166  } plugin_data;
21167  
21168  INIT_FUNC(mod_evhost_init) {
21169         plugin_data *p;
21170 -       
21171 +
21172         p = calloc(1, sizeof(*p));
21173 -       
21174 +
21175         p->tmp_buf = buffer_init();
21176  
21177         return p;
21178 @@ -36,34 +38,34 @@
21179  
21180  FREE_FUNC(mod_evhost_free) {
21181         plugin_data *p = p_d;
21182 -       
21183 +
21184         UNUSED(srv);
21185  
21186         if (!p) return HANDLER_GO_ON;
21187 -       
21188 +
21189         if (p->config_storage) {
21190                 size_t i;
21191                 for (i = 0; i < srv->config_context->used; i++) {
21192                         plugin_config *s = p->config_storage[i];
21193  
21194                         if (!s) continue;
21195 -                       
21196 +
21197                         if(s->path_pieces) {
21198                                 size_t j;
21199                                 for (j = 0; j < s->len; j++) {
21200                                         buffer_free(s->path_pieces[j]);
21201                                 }
21202 -                               
21203 +
21204                                 free(s->path_pieces);
21205                         }
21206 -                       
21207 +
21208                         buffer_free(s->path_pieces_raw);
21209 -                       
21210 +
21211                         free(s);
21212                 }
21213                 free(p->config_storage);
21214         }
21215 -       
21216 +
21217         buffer_free(p->tmp_buf);
21218  
21219         free(p);
21220 @@ -73,30 +75,30 @@
21221  
21222  static void mod_evhost_parse_pattern(plugin_config *s) {
21223         char *ptr = s->path_pieces_raw->ptr,*pos;
21224 -       
21225 +
21226         s->path_pieces = NULL;
21227 -       
21228 +
21229         for(pos=ptr;*ptr;ptr++) {
21230                 if(*ptr == '%') {
21231                         s->path_pieces = realloc(s->path_pieces,(s->len+2) * sizeof(*s->path_pieces));
21232                         s->path_pieces[s->len] = buffer_init();
21233                         s->path_pieces[s->len+1] = buffer_init();
21234 -                       
21235 +
21236                         buffer_copy_string_len(s->path_pieces[s->len],pos,ptr-pos);
21237                         pos = ptr + 2;
21238 -                       
21239 +
21240                         buffer_copy_string_len(s->path_pieces[s->len+1],ptr++,2);
21241 -                       
21242 +
21243                         s->len += 2;
21244                 }
21245         }
21246 -       
21247 +
21248         if(*pos != '\0') {
21249                 s->path_pieces = realloc(s->path_pieces,(s->len+1) * sizeof(*s->path_pieces));
21250                 s->path_pieces[s->len] = buffer_init();
21251 -               
21252 +
21253                 buffer_append_memory(s->path_pieces[s->len],pos,ptr-pos);
21254 -               
21255 +
21256                 s->len += 1;
21257         }
21258  }
21259 @@ -104,9 +106,9 @@
21260  SETDEFAULTS_FUNC(mod_evhost_set_defaults) {
21261         plugin_data *p = p_d;
21262         size_t i;
21263 -       
21264 +
21265         /**
21266 -        * 
21267 +        *
21268          * #
21269          * # define a pattern for the host url finding
21270          * # %% => % sign
21271 @@ -117,39 +119,39 @@
21272          * # %4 => subdomain 2 name
21273          * #
21274          * evhost.path-pattern = "/home/ckruse/dev/www/%3/htdocs/"
21275 -        * 
21276 +        *
21277          */
21278 -       
21279 -       config_values_t cv[] = { 
21280 +
21281 +       config_values_t cv[] = {
21282                 { "evhost.path-pattern",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
21283                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
21284         };
21285 -       
21286 +
21287         if (!p) return HANDLER_ERROR;
21288 -       
21289 +
21290         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
21291 -       
21292 +
21293         for (i = 0; i < srv->config_context->used; i++) {
21294                 plugin_config *s;
21295 -               
21296 +
21297                 s = calloc(1, sizeof(plugin_config));
21298                 s->path_pieces_raw = buffer_init();
21299                 s->path_pieces     = NULL;
21300                 s->len             = 0;
21301 -       
21302 +
21303                 cv[0].destination = s->path_pieces_raw;
21304 -               
21305 +
21306                 p->config_storage[i] = s;
21307 -               
21308 +
21309                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value,  cv)) {
21310                         return HANDLER_ERROR;
21311                 }
21312 -               
21313 +
21314                 if (s->path_pieces_raw->used != 0) {
21315                         mod_evhost_parse_pattern(s);
21316                 }
21317         }
21318 -       
21319 +
21320         return HANDLER_GO_ON;
21321  }
21322  
21323 @@ -158,7 +160,7 @@
21324   * - %0 - full hostname (authority w/o port)
21325   * - %1 - tld
21326   * - %2 - domain.tld
21327 - * - %3 - 
21328 + * - %3 -
21329   */
21330  
21331  static int mod_evhost_parse_host(connection *con,array *host) {
21332 @@ -168,7 +170,7 @@
21333         int first = 1;
21334         data_string *ds;
21335         int i;
21336 -       
21337 +
21338         /* first, find the domain + tld */
21339         for(;ptr > con->uri.authority->ptr;ptr--) {
21340                 if(*ptr == '.') {
21341 @@ -179,18 +181,18 @@
21342                         first = 1;
21343                 }
21344         }
21345 -       
21346 +
21347         ds = data_string_init();
21348         buffer_copy_string(ds->key,"%0");
21349 -       
21350 +
21351         /* if we stopped at a dot, skip the dot */
21352         if (*ptr == '.') ptr++;
21353         buffer_copy_string_len(ds->value, ptr, colon-ptr);
21354 -       
21355 +
21356         array_insert_unique(host,(data_unset *)ds);
21357 -       
21358 +
21359         /* if the : is not the start of the authority, go on parsing the hostname */
21360 -       
21361 +
21362         if (colon != con->uri.authority->ptr) {
21363                 for(ptr = colon - 1, i = 1; ptr > con->uri.authority->ptr; ptr--) {
21364                         if(*ptr == '.') {
21365 @@ -200,59 +202,55 @@
21366                                         buffer_copy_string(ds->key,"%");
21367                                         buffer_append_long(ds->key, i++);
21368                                         buffer_copy_string_len(ds->value,ptr+1,colon-ptr-1);
21369 -                                       
21370 +
21371                                         array_insert_unique(host,(data_unset *)ds);
21372                                 }
21373                                 colon = ptr;
21374                         }
21375                 }
21376 -               
21377 +
21378                 /* if the . is not the first charactor of the hostname */
21379                 if (colon != ptr) {
21380                         ds = data_string_init();
21381                         buffer_copy_string(ds->key,"%");
21382                         buffer_append_long(ds->key, i++);
21383                         buffer_copy_string_len(ds->value,ptr,colon-ptr);
21384 -                       
21385 +
21386                         array_insert_unique(host,(data_unset *)ds);
21387                 }
21388         }
21389 -       
21390 +
21391         return 0;
21392  }
21393  
21394 -#define PATCH(x) \
21395 -       p->conf.x = s->x;
21396  static int mod_evhost_patch_connection(server *srv, connection *con, plugin_data *p) {
21397         size_t i, j;
21398         plugin_config *s = p->config_storage[0];
21399 -       
21400 -       PATCH(path_pieces);
21401 -       PATCH(len);
21402 -       
21403 +
21404 +       PATCH_OPTION(path_pieces);
21405 +       PATCH_OPTION(len);
21406 +
21407         /* skip the first, the global context */
21408         for (i = 1; i < srv->config_context->used; i++) {
21409                 data_config *dc = (data_config *)srv->config_context->data[i];
21410                 s = p->config_storage[i];
21411 -               
21412 +
21413                 /* condition didn't match */
21414                 if (!config_check_cond(srv, con, dc)) continue;
21415 -               
21416 +
21417                 /* merge config */
21418                 for (j = 0; j < dc->value->used; j++) {
21419                         data_unset *du = dc->value->data[j];
21420 -                       
21421 +
21422                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("evhost.path-pattern"))) {
21423 -                               PATCH(path_pieces);
21424 -                               PATCH(len);
21425 +                               PATCH_OPTION(path_pieces);
21426 +                               PATCH_OPTION(len);
21427                         }
21428                 }
21429         }
21430 -       
21431 +
21432         return 0;
21433  }
21434 -#undef PATCH
21435 -
21436  
21437  static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d) {
21438         plugin_data *p = p_d;
21439 @@ -261,29 +259,29 @@
21440         register char *ptr;
21441         int not_good = 0;
21442         stat_cache_entry *sce = NULL;
21443 -       
21444 +
21445         /* not authority set */
21446         if (con->uri.authority->used == 0) return HANDLER_GO_ON;
21447 -       
21448 +
21449         mod_evhost_patch_connection(srv, con, p);
21450 -       
21451 +
21452         /* missing even default(global) conf */
21453         if (0 == p->conf.len) {
21454                 return HANDLER_GO_ON;
21455         }
21456  
21457         parsed_host = array_init();
21458 -       
21459 +
21460         mod_evhost_parse_host(con, parsed_host);
21461 -       
21462 +
21463         /* build document-root */
21464         buffer_reset(p->tmp_buf);
21465 -       
21466 +
21467         for (i = 0; i < p->conf.len; i++) {
21468                 ptr = p->conf.path_pieces[i]->ptr;
21469                 if (*ptr == '%') {
21470                         data_string *ds;
21471 -                       
21472 +
21473                         if (*(ptr+1) == '%') {
21474                                 /* %% */
21475                                 BUFFER_APPEND_STRING_CONST(p->tmp_buf,"%");
21476 @@ -298,11 +296,11 @@
21477                         buffer_append_string_buffer(p->tmp_buf,p->conf.path_pieces[i]);
21478                 }
21479         }
21480 -       
21481 -       BUFFER_APPEND_SLASH(p->tmp_buf);
21482 -       
21483 +
21484 +       PATHNAME_APPEND_SLASH(p->tmp_buf);
21485 +
21486         array_free(parsed_host);
21487 -       
21488 +
21489         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
21490                 log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
21491                 not_good = 1;
21492 @@ -310,11 +308,11 @@
21493                 log_error_write(srv, __FILE__, __LINE__, "sb", "not a directory:", p->tmp_buf);
21494                 not_good = 1;
21495         }
21496 -       
21497 +
21498         if (!not_good) {
21499                 buffer_copy_string_buffer(con->physical.doc_root, p->tmp_buf);
21500         }
21501 -       
21502 +
21503         return HANDLER_GO_ON;
21504  }
21505  
21506 @@ -325,9 +323,9 @@
21507         p->set_defaults            = mod_evhost_set_defaults;
21508         p->handle_docroot          = mod_evhost_uri_handler;
21509         p->cleanup                 = mod_evhost_free;
21510 -       
21511 +
21512         p->data                    = NULL;
21513 -       
21514 +
21515         return 0;
21516  }
21517  
21518 --- ../lighttpd-1.4.11/src/mod_expire.c 2005-11-03 09:52:13.000000000 +0200
21519 +++ lighttpd-1.4.12/src/mod_expire.c    2006-07-16 00:26:04.000000000 +0300
21520 @@ -12,8 +12,8 @@
21521  #include "stat_cache.h"
21522  
21523  /**
21524 - * this is a expire module for a lighttpd 
21525 - * 
21526 + * this is a expire module for a lighttpd
21527 + *
21528   * set 'Expires:' HTTP Headers on demand
21529   */
21530  
21531 @@ -27,51 +27,51 @@
21532  
21533  typedef struct {
21534         PLUGIN_DATA;
21535 -       
21536 +
21537         buffer *expire_tstmp;
21538 -       
21539 +
21540         plugin_config **config_storage;
21541 -       
21542 -       plugin_config conf; 
21543 +
21544 +       plugin_config conf;
21545  } plugin_data;
21546  
21547  /* init the plugin data */
21548  INIT_FUNC(mod_expire_init) {
21549         plugin_data *p;
21550 -       
21551 +
21552         p = calloc(1, sizeof(*p));
21553 -       
21554 +
21555         p->expire_tstmp = buffer_init();
21556 -       
21557 +
21558         buffer_prepare_copy(p->expire_tstmp, 255);
21559 -       
21560 +
21561         return p;
21562  }
21563  
21564  /* detroy the plugin data */
21565  FREE_FUNC(mod_expire_free) {
21566         plugin_data *p = p_d;
21567 -       
21568 +
21569         UNUSED(srv);
21570  
21571         if (!p) return HANDLER_GO_ON;
21572 -       
21573 +
21574         buffer_free(p->expire_tstmp);
21575 -       
21576 +
21577         if (p->config_storage) {
21578                 size_t i;
21579                 for (i = 0; i < srv->config_context->used; i++) {
21580                         plugin_config *s = p->config_storage[i];
21581 -                       
21582 +
21583                         array_free(s->expire_url);
21584 -                       
21585 +
21586                         free(s);
21587                 }
21588                 free(p->config_storage);
21589         }
21590 -       
21591 +
21592         free(p);
21593 -       
21594 +
21595         return HANDLER_GO_ON;
21596  }
21597  
21598 @@ -79,25 +79,25 @@
21599         char *ts;
21600         int type = -1;
21601         int retts = 0;
21602 -               
21603 +
21604         UNUSED(p);
21605  
21606 -       /* 
21607 +       /*
21608          * parse
21609 -        * 
21610 +        *
21611          * '(access|modification) [plus] {<num> <type>}*'
21612 -        * 
21613 +        *
21614          * e.g. 'access 1 years'
21615          */
21616 -       
21617 +
21618         if (expire->used == 0) {
21619 -               log_error_write(srv, __FILE__, __LINE__, "s", 
21620 +               log_error_write(srv, __FILE__, __LINE__, "s",
21621                                 "empty:");
21622                 return -1;
21623         }
21624 -       
21625 +
21626         ts = expire->ptr;
21627 -       
21628 +
21629         if (0 == strncmp(ts, "access ", 7)) {
21630                 type  = 0;
21631                 ts   += 7;
21632 @@ -110,39 +110,39 @@
21633                                 "invalid <base>:", ts);
21634                 return -1;
21635         }
21636 -       
21637 +
21638         if (0 == strncmp(ts, "plus ", 5)) {
21639                 /* skip the optional plus */
21640                 ts   += 5;
21641         }
21642 -       
21643 +
21644         /* the rest is just <number> (years|months|days|hours|minutes|seconds) */
21645         while (1) {
21646                 char *space, *err;
21647                 int num;
21648 -               
21649 +
21650                 if (NULL == (space = strchr(ts, ' '))) {
21651 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
21652 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
21653                                         "missing space after <num>:", ts);
21654                         return -1;
21655                 }
21656 -               
21657 +
21658                 num = strtol(ts, &err, 10);
21659                 if (*err != ' ') {
21660 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
21661 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
21662                                         "missing <type> after <num>:", ts);
21663                         return -1;
21664                 }
21665 -               
21666 +
21667                 ts = space + 1;
21668 -               
21669 +
21670                 if (NULL != (space = strchr(ts, ' '))) {
21671                         int slen;
21672                         /* */
21673 -                       
21674 +
21675                         slen = space - ts;
21676 -                       
21677 -                       if (slen == 5 && 
21678 +
21679 +                       if (slen == 5 &&
21680                             0 == strncmp(ts, "years", slen)) {
21681                                 num *= 60 * 60 * 24 * 30 * 12;
21682                         } else if (slen == 6 &&
21683 @@ -161,13 +161,13 @@
21684                                    0 == strncmp(ts, "seconds", slen)) {
21685                                 num *= 1;
21686                         } else {
21687 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
21688 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
21689                                                 "unknown type:", ts);
21690                                 return -1;
21691                         }
21692 -                       
21693 +
21694                         retts += num;
21695 -                       
21696 +
21697                         ts = space + 1;
21698                 } else {
21699                         if (0 == strcmp(ts, "years")) {
21700 @@ -183,19 +183,19 @@
21701                         } else if (0 == strcmp(ts, "seconds")) {
21702                                 num *= 1;
21703                         } else {
21704 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
21705 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
21706                                                 "unknown type:", ts);
21707                                 return -1;
21708                         }
21709 -                       
21710 +
21711                         retts += num;
21712 -                       
21713 +
21714                         break;
21715                 }
21716         }
21717 -       
21718 +
21719         if (offset != NULL) *offset = retts;
21720 -       
21721 +
21722         return type;
21723  }
21724  
21725 @@ -205,102 +205,99 @@
21726  SETDEFAULTS_FUNC(mod_expire_set_defaults) {
21727         plugin_data *p = p_d;
21728         size_t i = 0, k;
21729 -       
21730 -       config_values_t cv[] = { 
21731 +
21732 +       config_values_t cv[] = {
21733                 { "expire.url",                 NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
21734                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
21735         };
21736 -       
21737 +
21738         if (!p) return HANDLER_ERROR;
21739 -       
21740 +
21741         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
21742 -       
21743 +
21744         for (i = 0; i < srv->config_context->used; i++) {
21745                 plugin_config *s;
21746 -               
21747 +
21748                 s = calloc(1, sizeof(plugin_config));
21749                 s->expire_url    = array_init();
21750 -               
21751 +
21752                 cv[0].destination = s->expire_url;
21753 -               
21754 +
21755                 p->config_storage[i] = s;
21756 -       
21757 +
21758                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
21759                         return HANDLER_ERROR;
21760                 }
21761 -       
21762 +
21763                 for (k = 0; k < s->expire_url->used; k++) {
21764                         data_string *ds = (data_string *)s->expire_url->data[k];
21765 -                       
21766 +
21767                         /* parse lines */
21768                         if (-1 == mod_expire_get_offset(srv, p, ds->value, NULL)) {
21769 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
21770 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
21771                                                 "parsing expire.url failed:", ds->value);
21772                                 return HANDLER_ERROR;
21773                         }
21774                 }
21775         }
21776 -       
21777 -       
21778 +
21779 +
21780         return HANDLER_GO_ON;
21781  }
21782  
21783 -#define PATCH(x) \
21784 -       p->conf.x = s->x;
21785  static int mod_expire_patch_connection(server *srv, connection *con, plugin_data *p) {
21786         size_t i, j;
21787         plugin_config *s = p->config_storage[0];
21788 -       
21789 -       PATCH(expire_url);
21790 -       
21791 +
21792 +       PATCH_OPTION(expire_url);
21793 +
21794         /* skip the first, the global context */
21795         for (i = 1; i < srv->config_context->used; i++) {
21796                 data_config *dc = (data_config *)srv->config_context->data[i];
21797                 s = p->config_storage[i];
21798 -               
21799 +
21800                 /* condition didn't match */
21801                 if (!config_check_cond(srv, con, dc)) continue;
21802 -               
21803 +
21804                 /* merge config */
21805                 for (j = 0; j < dc->value->used; j++) {
21806                         data_unset *du = dc->value->data[j];
21807 -                       
21808 +
21809                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("expire.url"))) {
21810 -                               PATCH(expire_url);
21811 +                               PATCH_OPTION(expire_url);
21812                         }
21813                 }
21814         }
21815 -       
21816 +
21817         return 0;
21818  }
21819 -#undef PATCH
21820  
21821  URIHANDLER_FUNC(mod_expire_path_handler) {
21822         plugin_data *p = p_d;
21823         int s_len;
21824         size_t k;
21825 -       
21826 +
21827         if (con->uri.path->used == 0) return HANDLER_GO_ON;
21828 -       
21829 +
21830         mod_expire_patch_connection(srv, con, p);
21831 -       
21832 +
21833         s_len = con->uri.path->used - 1;
21834 -       
21835 +
21836         for (k = 0; k < p->conf.expire_url->used; k++) {
21837                 data_string *ds = (data_string *)p->conf.expire_url->data[k];
21838                 int ct_len = ds->key->used - 1;
21839 -               
21840 +
21841                 if (ct_len > s_len) continue;
21842                 if (ds->key->used == 0) continue;
21843 -               
21844 +
21845                 if (0 == strncmp(con->uri.path->ptr, ds->key->ptr, ct_len)) {
21846                         int ts;
21847                         time_t t;
21848                         size_t len;
21849                         stat_cache_entry *sce = NULL;
21850 -               
21851 +
21852                         stat_cache_get_entry(srv, con, con->physical.path, &sce);
21853 -                       
21854 +
21855                         switch(mod_expire_get_offset(srv, p, ds->value, &ts)) {
21856                         case 0:
21857                                 /* access */
21858 @@ -308,38 +305,38 @@
21859                                 break;
21860                         case 1:
21861                                 /* modification */
21862 -                               
21863 +
21864                                 t = (ts + sce->st.st_mtime);
21865                                 break;
21866                         default:
21867                                 /* -1 is handled at parse-time */
21868                                 break;
21869                         }
21870 -                       
21871 -                       
21872 -                       if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1, 
21873 +
21874 +
21875 +                       if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1,
21876                                            "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(t))))) {
21877                                 /* could not set expire header, out of mem */
21878 -                               
21879 +
21880                                 return HANDLER_GO_ON;
21881 -                               
21882 +
21883                         }
21884 -                           
21885 +
21886                         p->expire_tstmp->used = len + 1;
21887 -               
21888 -                       /* HTTP/1.0 */  
21889 +
21890 +                       /* HTTP/1.0 */
21891                         response_header_overwrite(srv, con, CONST_STR_LEN("Expires"), CONST_BUF_LEN(p->expire_tstmp));
21892  
21893 -                       /* HTTP/1.1 */  
21894 +                       /* HTTP/1.1 */
21895                         buffer_copy_string(p->expire_tstmp, "max-age=");
21896                         buffer_append_long(p->expire_tstmp, ts);
21897 -                       
21898 +
21899                         response_header_overwrite(srv, con, CONST_STR_LEN("Cache-Control"), CONST_BUF_LEN(p->expire_tstmp));
21900 -                       
21901 +
21902                         return HANDLER_GO_ON;
21903                 }
21904         }
21905 -       
21906 +
21907         /* not found */
21908         return HANDLER_GO_ON;
21909  }
21910 @@ -349,13 +346,13 @@
21911  int mod_expire_plugin_init(plugin *p) {
21912         p->version     = LIGHTTPD_VERSION_ID;
21913         p->name        = buffer_init_string("expire");
21914 -       
21915 +
21916         p->init        = mod_expire_init;
21917         p->handle_subrequest_start = mod_expire_path_handler;
21918         p->set_defaults  = mod_expire_set_defaults;
21919         p->cleanup     = mod_expire_free;
21920 -       
21921 +
21922         p->data        = NULL;
21923 -       
21924 +
21925         return 0;
21926  }
21927 --- ../lighttpd-1.4.11/src/mod_fastcgi.c        2006-03-09 13:18:39.000000000 +0200
21928 +++ lighttpd-1.4.12/src/mod_fastcgi.c   2006-07-18 13:03:40.000000000 +0300
21929 @@ -1,5 +1,4 @@
21930  #include <sys/types.h>
21931 -#include <unistd.h>
21932  #include <errno.h>
21933  #include <fcntl.h>
21934  #include <string.h>
21935 @@ -24,7 +23,7 @@
21936  #include "inet_ntop_cache.h"
21937  #include "stat_cache.h"
21938  
21939 -#include <fastcgi.h>
21940 +#include "fastcgi.h"
21941  #include <stdio.h>
21942  
21943  #ifdef HAVE_SYS_FILIO_H
21944 @@ -32,7 +31,11 @@
21945  #endif
21946  
21947  #include "sys-socket.h"
21948 +#include "sys-files.h"
21949 +#include "sys-strings.h"
21950 +#include "sys-process.h"
21951  
21952 +#include "http_resp.h"
21953  
21954  #ifndef UNIX_PATH_MAX
21955  # define UNIX_PATH_MAX 108
21956 @@ -45,14 +48,13 @@
21957  #include <sys/wait.h>
21958  #endif
21959  
21960 -
21961  /*
21962 - * 
21963 + *
21964   * TODO:
21965 - * 
21966 + *
21967   * - add timeout for a connect to a non-fastcgi process
21968   *   (use state_timestamp + state)
21969 - * 
21970 + *
21971   */
21972  
21973  typedef struct fcgi_proc {
21974 @@ -61,7 +63,7 @@
21975         unsigned port;  /* config.port + pno */
21976  
21977         buffer *connection_name; /* either tcp:<host>:<port> or unix:<socket> for debuggin purposes */
21978 -       
21979 +
21980         pid_t pid;   /* PID of the spawned process (0 if not spawned locally) */
21981  
21982  
21983 @@ -70,20 +72,20 @@
21984         time_t last_used; /* see idle_timeout */
21985         size_t requests;  /* see max_requests */
21986         struct fcgi_proc *prev, *next; /* see first */
21987 -       
21988 +
21989         time_t disabled_until; /* this proc is disabled until, use something else until than */
21990 -       
21991 +
21992         int is_local;
21993  
21994 -       enum { 
21995 +       enum {
21996                 PROC_STATE_UNSET,    /* init-phase */
21997                 PROC_STATE_RUNNING,  /* alive */
21998 -               PROC_STATE_OVERLOADED, /* listen-queue is full, 
21999 +               PROC_STATE_OVERLOADED, /* listen-queue is full,
22000                                           don't send something to this proc for the next 2 seconds */
22001                 PROC_STATE_DIED_WAIT_FOR_PID, /* */
22002                 PROC_STATE_DIED,     /* marked as dead, should be restarted */
22003                 PROC_STATE_KILLED    /* was killed as we don't have the load anymore */
22004 -       } state; 
22005 +       } state;
22006  } fcgi_proc;
22007  
22008  typedef struct {
22009 @@ -94,20 +96,20 @@
22010          * sorted by lowest load
22011          *
22012          * whenever a job is done move it up in the list
22013 -        * until it is sorted, move it down as soon as the 
22014 +        * until it is sorted, move it down as soon as the
22015          * job is started
22016          */
22017 -       fcgi_proc *first; 
22018 -       fcgi_proc *unused_procs; 
22019 +       fcgi_proc *first;
22020 +       fcgi_proc *unused_procs;
22021  
22022 -       /* 
22023 +       /*
22024          * spawn at least min_procs, at max_procs.
22025          *
22026 -        * as soon as the load of the first entry 
22027 +        * as soon as the load of the first entry
22028          * is max_load_per_proc we spawn a new one
22029 -        * and add it to the first entry and give it 
22030 +        * and add it to the first entry and give it
22031          * the load
22032 -        * 
22033 +        *
22034          */
22035  
22036         unsigned short min_procs;
22037 @@ -119,44 +121,44 @@
22038  
22039         /*
22040          * kick the process from the list if it was not
22041 -        * used for idle_timeout until min_procs is 
22042 +        * used for idle_timeout until min_procs is
22043          * reached. this helps to get the processlist
22044          * small again we had a small peak load.
22045          *
22046          */
22047 -       
22048 +
22049         unsigned short idle_timeout;
22050 -       
22051 +
22052         /*
22053          * time after a disabled remote connection is tried to be re-enabled
22054 -        * 
22055 -        * 
22056 +        *
22057 +        *
22058          */
22059 -       
22060 +
22061         unsigned short disable_time;
22062  
22063         /*
22064          * same fastcgi processes get a little bit larger
22065 -        * than wanted. max_requests_per_proc kills a 
22066 +        * than wanted. max_requests_per_proc kills a
22067          * process after a number of handled requests.
22068          *
22069          */
22070         size_t max_requests_per_proc;
22071 -       
22072 +
22073  
22074         /* config */
22075  
22076 -       /* 
22077 -        * host:port 
22078 +       /*
22079 +        * host:port
22080          *
22081 -        * if host is one of the local IP adresses the 
22082 +        * if host is one of the local IP adresses the
22083          * whole connection is local
22084          *
22085          * if tcp/ip should be used host AND port have
22086 -        * to be specified 
22087 -        * 
22088 -        */ 
22089 -       buffer *host; 
22090 +        * to be specified
22091 +        *
22092 +        */
22093 +       buffer *host;
22094         unsigned short port;
22095  
22096         /*
22097 @@ -169,7 +171,7 @@
22098          */
22099         buffer *unixsocket;
22100  
22101 -       /* if socket is local we can start the fastcgi 
22102 +       /* if socket is local we can start the fastcgi
22103          * process ourself
22104          *
22105          * bin-path is the path to the binary
22106 @@ -177,19 +179,19 @@
22107          * check min_procs and max_procs for the number
22108          * of process to start-up
22109          */
22110 -       buffer *bin_path; 
22111 -       
22112 -       /* bin-path is set bin-environment is taken to 
22113 +       buffer *bin_path;
22114 +
22115 +       /* bin-path is set bin-environment is taken to
22116          * create the environement before starting the
22117          * FastCGI process
22118 -        * 
22119 +        *
22120          */
22121         array *bin_env;
22122 -       
22123 +
22124         array *bin_env_copy;
22125 -       
22126 +
22127         /*
22128 -        * docroot-translation between URL->phys and the 
22129 +        * docroot-translation between URL->phys and the
22130          * remote host
22131          *
22132          * reasons:
22133 @@ -208,7 +210,7 @@
22134         unsigned short mode;
22135  
22136         /*
22137 -        * check_local tell you if the phys file is stat()ed 
22138 +        * check_local tell you if the phys file is stat()ed
22139          * or not. FastCGI doesn't care if the service is
22140          * remote. If the web-server side doesn't contain
22141          * the fastcgi-files we should not stat() for them
22142 @@ -218,11 +220,11 @@
22143  
22144         /*
22145          * append PATH_INFO to SCRIPT_FILENAME
22146 -        * 
22147 +        *
22148          * php needs this if cgi.fix_pathinfo is provied
22149 -        * 
22150 +        *
22151          */
22152 -       
22153 +
22154         unsigned short break_scriptfilename_for_php;
22155  
22156         /*
22157 @@ -231,12 +233,12 @@
22158          *
22159          */
22160         unsigned short allow_xsendfile;
22161 -               
22162 +
22163         ssize_t load; /* replace by host->load */
22164  
22165         size_t max_id; /* corresponds most of the time to
22166         num_procs.
22167 -       
22168 +
22169         only if a process is killed max_id waits for the process itself
22170         to die and decrements its afterwards */
22171  
22172 @@ -245,17 +247,17 @@
22173  
22174  /*
22175   * one extension can have multiple hosts assigned
22176 - * one host can spawn additional processes on the same 
22177 + * one host can spawn additional processes on the same
22178   *   socket (if we control it)
22179   *
22180   * ext -> host -> procs
22181   *    1:n     1:n
22182   *
22183 - * if the fastcgi process is remote that whole goes down 
22184 + * if the fastcgi process is remote that whole goes down
22185   * to
22186   *
22187   * ext -> host -> procs
22188 - *    1:n     1:1 
22189 + *    1:n     1:1
22190   *
22191   * in case of PHP and FCGI_CHILDREN we have again a procs
22192   * but we don't control it directly.
22193 @@ -268,7 +270,7 @@
22194         int note_is_sent;
22195  
22196         fcgi_extension_host **hosts;
22197 -       
22198 +
22199         size_t used;
22200         size_t size;
22201  } fcgi_extension;
22202 @@ -282,10 +284,10 @@
22203  
22204  
22205  typedef struct {
22206 -       fcgi_exts *exts; 
22207 +       fcgi_exts *exts;
22208  
22209         array *ext_mapping;
22210 -       
22211 +
22212         int debug;
22213  } plugin_config;
22214  
22215 @@ -297,7 +299,7 @@
22216  
22217  typedef struct {
22218         char **ptr;
22219 -       
22220 +
22221         size_t size;
22222         size_t used;
22223  } char_array;
22224 @@ -306,55 +308,54 @@
22225  typedef struct {
22226         PLUGIN_DATA;
22227         buffer_uint fcgi_request_id;
22228 -       
22229 +
22230         buffer *fcgi_env;
22231 -       
22232 +
22233         buffer *path;
22234 -       buffer *parse_response;
22235  
22236         buffer *statuskey;
22237 -       
22238 +
22239 +       http_resp *resp;
22240 +
22241         plugin_config **config_storage;
22242 -       
22243 +
22244         plugin_config conf; /* this is only used as long as no handler_ctx is setup */
22245  } plugin_data;
22246  
22247  /* connection specific data */
22248 -typedef enum { 
22249 +typedef enum {
22250         FCGI_STATE_UNSET,
22251 -       FCGI_STATE_INIT, 
22252 -       FCGI_STATE_CONNECT_DELAYED, 
22253 -       FCGI_STATE_PREPARE_WRITE, 
22254 -       FCGI_STATE_WRITE, 
22255 -       FCGI_STATE_READ 
22256 +       FCGI_STATE_INIT,
22257 +       FCGI_STATE_CONNECT_DELAYED,
22258 +       FCGI_STATE_PREPARE_WRITE,
22259 +       FCGI_STATE_WRITE,
22260 +       FCGI_STATE_READ
22261  } fcgi_connection_state_t;
22262  
22263  typedef struct {
22264         fcgi_proc *proc;
22265         fcgi_extension_host *host;
22266         fcgi_extension *ext;
22267 -       
22268 +
22269         fcgi_connection_state_t state;
22270         time_t   state_timestamp;
22271 -       
22272 +
22273         int      reconnects; /* number of reconnect attempts */
22274 -       
22275 -       chunkqueue *rb; /* read queue */
22276 +
22277 +       chunkqueue *rb; /* the raw fcgi read-queue */
22278 +       chunkqueue *http_rb; /* the decoded read-queue for http-parsing */
22279         chunkqueue *wb; /* write queue */
22280 -       
22281 -       buffer   *response_header;
22282 -       
22283 +
22284         size_t    request_id;
22285 -       int       fd;        /* fd to the fastcgi process */
22286 -       int       fde_ndx;   /* index into the fd-event buffer */
22287 +       iosocket *sock;
22288  
22289         pid_t     pid;
22290         int       got_proc;
22291  
22292         int       send_content_body;
22293 -       
22294 +
22295         plugin_config conf;
22296 -       
22297 +
22298         connection *remote_conn;  /* dumb pointer */
22299         plugin_data *plugin_data; /* dumb pointer */
22300  } handler_ctx;
22301 @@ -380,7 +381,7 @@
22302         return di;
22303  }
22304  
22305 -/* dummies of the statistic framework functions 
22306 +/* dummies of the statistic framework functions
22307   * they will be moved to a statistics.c later */
22308  int status_counter_inc(server *srv, const char *s, size_t len) {
22309         data_integer *di = status_counter_get_counter(srv, s, len);
22310 @@ -429,7 +430,7 @@
22311         CLEAN(".connected");
22312         CLEAN(".load");
22313  
22314 -#undef CLEAN   
22315 +#undef CLEAN
22316  
22317  #define CLEAN(x) \
22318         fastcgi_status_copy_procname(b, host, NULL); \
22319 @@ -438,33 +439,30 @@
22320  
22321         CLEAN(".load");
22322  
22323 -#undef CLEAN   
22324 +#undef CLEAN
22325  
22326         return 0;
22327  }
22328  
22329  static handler_ctx * handler_ctx_init() {
22330         handler_ctx * hctx;
22331 -       
22332 +
22333         hctx = calloc(1, sizeof(*hctx));
22334         assert(hctx);
22335 -       
22336 -       hctx->fde_ndx = -1;
22337 -       
22338 -       hctx->response_header = buffer_init();
22339 -       
22340 +
22341         hctx->request_id = 0;
22342         hctx->state = FCGI_STATE_INIT;
22343         hctx->proc = NULL;
22344 -       
22345 -       hctx->fd = -1;
22346 -       
22347 +
22348 +       hctx->sock = iosocket_init();
22349 +
22350         hctx->reconnects = 0;
22351         hctx->send_content_body = 1;
22352  
22353         hctx->rb = chunkqueue_init();
22354 +       hctx->http_rb = chunkqueue_init();
22355         hctx->wb = chunkqueue_init();
22356 -       
22357 +
22358         return hctx;
22359  }
22360  
22361 @@ -473,12 +471,13 @@
22362                 hctx->host->load--;
22363                 hctx->host = NULL;
22364         }
22365 -       
22366 -       buffer_free(hctx->response_header);
22367  
22368         chunkqueue_free(hctx->rb);
22369 +       chunkqueue_free(hctx->http_rb);
22370         chunkqueue_free(hctx->wb);
22371  
22372 +       iosocket_free(hctx->sock);
22373 +
22374         free(hctx);
22375  }
22376  
22377 @@ -488,21 +487,21 @@
22378         f = calloc(1, sizeof(*f));
22379         f->unixsocket = buffer_init();
22380         f->connection_name = buffer_init();
22381 -       
22382 +
22383         f->prev = NULL;
22384         f->next = NULL;
22385 -       
22386 +
22387         return f;
22388  }
22389  
22390  void fastcgi_process_free(fcgi_proc *f) {
22391         if (!f) return;
22392 -       
22393 +
22394         fastcgi_process_free(f->next);
22395 -       
22396 +
22397         buffer_free(f->unixsocket);
22398         buffer_free(f->connection_name);
22399 -       
22400 +
22401         free(f);
22402  }
22403  
22404 @@ -519,13 +518,13 @@
22405         f->bin_env = array_init();
22406         f->bin_env_copy = array_init();
22407         f->strip_request_uri = buffer_init();
22408 -       
22409 +
22410         return f;
22411  }
22412  
22413  void fastcgi_host_free(fcgi_extension_host *h) {
22414         if (!h) return;
22415 -       
22416 +
22417         buffer_free(h->id);
22418         buffer_free(h->host);
22419         buffer_free(h->unixsocket);
22420 @@ -534,49 +533,49 @@
22421         buffer_free(h->strip_request_uri);
22422         array_free(h->bin_env);
22423         array_free(h->bin_env_copy);
22424 -       
22425 +
22426         fastcgi_process_free(h->first);
22427         fastcgi_process_free(h->unused_procs);
22428 -       
22429 +
22430         free(h);
22431 -       
22432 +
22433  }
22434  
22435  fcgi_exts *fastcgi_extensions_init() {
22436         fcgi_exts *f;
22437  
22438         f = calloc(1, sizeof(*f));
22439 -       
22440 +
22441         return f;
22442  }
22443  
22444  void fastcgi_extensions_free(fcgi_exts *f) {
22445         size_t i;
22446 -       
22447 +
22448         if (!f) return;
22449 -       
22450 +
22451         for (i = 0; i < f->used; i++) {
22452                 fcgi_extension *fe;
22453                 size_t j;
22454 -               
22455 +
22456                 fe = f->exts[i];
22457 -               
22458 +
22459                 for (j = 0; j < fe->used; j++) {
22460                         fcgi_extension_host *h;
22461 -                       
22462 +
22463                         h = fe->hosts[j];
22464 -                       
22465 +
22466                         fastcgi_host_free(h);
22467                 }
22468 -               
22469 +
22470                 buffer_free(fe->key);
22471                 free(fe->hosts);
22472 -               
22473 +
22474                 free(fe);
22475         }
22476 -       
22477 +
22478         free(f->exts);
22479 -       
22480 +
22481         free(f);
22482  }
22483  
22484 @@ -625,24 +624,25 @@
22485                 assert(fe->hosts);
22486         }
22487  
22488 -       fe->hosts[fe->used++] = fh; 
22489 +       fe->hosts[fe->used++] = fh;
22490  
22491         return 0;
22492 -       
22493 +
22494  }
22495  
22496  INIT_FUNC(mod_fastcgi_init) {
22497         plugin_data *p;
22498 -       
22499 +
22500         p = calloc(1, sizeof(*p));
22501 -       
22502 +
22503         p->fcgi_env = buffer_init();
22504 -       
22505 +
22506         p->path = buffer_init();
22507 -       p->parse_response = buffer_init();
22508 +
22509 +       p->resp = http_response_init();
22510  
22511         p->statuskey = buffer_init();
22512 -       
22513 +
22514         return p;
22515  }
22516  
22517 @@ -650,81 +650,82 @@
22518  FREE_FUNC(mod_fastcgi_free) {
22519         plugin_data *p = p_d;
22520         buffer_uint *r = &(p->fcgi_request_id);
22521 -       
22522 +
22523         UNUSED(srv);
22524  
22525         if (r->ptr) free(r->ptr);
22526 -       
22527 +
22528         buffer_free(p->fcgi_env);
22529         buffer_free(p->path);
22530 -       buffer_free(p->parse_response);
22531         buffer_free(p->statuskey);
22532 -       
22533 +
22534 +       http_response_free(p->resp);
22535 +
22536         if (p->config_storage) {
22537                 size_t i, j, n;
22538                 for (i = 0; i < srv->config_context->used; i++) {
22539                         plugin_config *s = p->config_storage[i];
22540                         fcgi_exts *exts;
22541 -                       
22542 +
22543                         if (!s) continue;
22544 -                       
22545 +
22546                         exts = s->exts;
22547  
22548                         for (j = 0; j < exts->used; j++) {
22549                                 fcgi_extension *ex;
22550 -                               
22551 +
22552                                 ex = exts->exts[j];
22553 -                               
22554 +
22555                                 for (n = 0; n < ex->used; n++) {
22556                                         fcgi_proc *proc;
22557                                         fcgi_extension_host *host;
22558 -                                       
22559 +
22560                                         host = ex->hosts[n];
22561 -                                       
22562 +
22563                                         for (proc = host->first; proc; proc = proc->next) {
22564                                                 if (proc->pid != 0) kill(proc->pid, SIGTERM);
22565 -                                               
22566 -                                               if (proc->is_local && 
22567 +
22568 +                                               if (proc->is_local &&
22569                                                     !buffer_is_empty(proc->unixsocket)) {
22570                                                         unlink(proc->unixsocket->ptr);
22571                                                 }
22572                                         }
22573 -                                       
22574 +
22575                                         for (proc = host->unused_procs; proc; proc = proc->next) {
22576                                                 if (proc->pid != 0) kill(proc->pid, SIGTERM);
22577 -                                               
22578 -                                               if (proc->is_local && 
22579 +
22580 +                                               if (proc->is_local &&
22581                                                     !buffer_is_empty(proc->unixsocket)) {
22582                                                         unlink(proc->unixsocket->ptr);
22583                                                 }
22584                                         }
22585                                 }
22586                         }
22587 -                       
22588 +
22589                         fastcgi_extensions_free(s->exts);
22590                         array_free(s->ext_mapping);
22591 -                       
22592 +
22593                         free(s);
22594                 }
22595                 free(p->config_storage);
22596         }
22597 -       
22598 +
22599         free(p);
22600 -       
22601 +
22602         return HANDLER_GO_ON;
22603  }
22604  
22605  static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
22606         char *dst;
22607 -       
22608 +
22609         if (!key || !val) return -1;
22610 -       
22611 +
22612         dst = malloc(key_len + val_len + 3);
22613         memcpy(dst, key, key_len);
22614         dst[key_len] = '=';
22615         /* add the \0 from the value */
22616         memcpy(dst + key_len + 1, val, val_len + 1);
22617 -       
22618 +
22619         if (env->size == 0) {
22620                 env->size = 16;
22621                 env->ptr = malloc(env->size * sizeof(*env->ptr));
22622 @@ -732,9 +733,9 @@
22623                 env->size += 16;
22624                 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
22625         }
22626 -       
22627 +
22628         env->ptr[env->used++] = dst;
22629 -       
22630 +
22631         return 0;
22632  }
22633  
22634 @@ -753,15 +754,15 @@
22635                         if (env->size == 0) {
22636                                 env->size = 16;
22637                                 env->ptr = malloc(env->size * sizeof(*env->ptr));
22638 -                       } else if (env->size == env->used) { 
22639 +                       } else if (env->size == env->used) {
22640                                 env->size += 16;
22641                                 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
22642                         }
22643 -                       
22644 +
22645                         b->ptr[i] = '\0';
22646  
22647                         env->ptr[env->used++] = start;
22648 -                       
22649 +
22650                         start = b->ptr + i + 1;
22651                         break;
22652                 default:
22653 @@ -794,7 +795,7 @@
22654         return 0;
22655  }
22656  
22657 -static int fcgi_spawn_connection(server *srv, 
22658 +static int fcgi_spawn_connection(server *srv,
22659                                  plugin_data *p,
22660                                  fcgi_extension_host *host,
22661                                  fcgi_proc *proc) {
22662 @@ -806,31 +807,27 @@
22663  #endif
22664         struct sockaddr_in fcgi_addr_in;
22665         struct sockaddr *fcgi_addr;
22666 -       
22667 +
22668         socklen_t servlen;
22669 -       
22670 +
22671  #ifndef HAVE_FORK
22672         return -1;
22673  #endif
22674 -       
22675 +
22676         if (p->conf.debug) {
22677                 log_error_write(srv, __FILE__, __LINE__, "sdb",
22678                                 "new proc, socket:", proc->port, proc->unixsocket);
22679         }
22680 -               
22681 +
22682         if (!buffer_is_empty(proc->unixsocket)) {
22683                 memset(&fcgi_addr, 0, sizeof(fcgi_addr));
22684 -               
22685 +
22686  #ifdef HAVE_SYS_UN_H
22687                 fcgi_addr_un.sun_family = AF_UNIX;
22688                 strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
22689 -               
22690 -#ifdef SUN_LEN
22691 +
22692                 servlen = SUN_LEN(&fcgi_addr_un);
22693 -#else
22694 -               /* stevens says: */
22695 -               servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
22696 -#endif
22697 +
22698                 socket_type = AF_UNIX;
22699                 fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
22700  
22701 @@ -844,108 +841,108 @@
22702  #endif
22703         } else {
22704                 fcgi_addr_in.sin_family = AF_INET;
22705 -               
22706 +
22707                 if (buffer_is_empty(host->host)) {
22708                         fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
22709                 } else {
22710                         struct hostent *he;
22711 -                       
22712 +
22713                         /* set a usefull default */
22714                         fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
22715 -                       
22716 -                       
22717 +
22718 +
22719                         if (NULL == (he = gethostbyname(host->host->ptr))) {
22720 -                               log_error_write(srv, __FILE__, __LINE__, 
22721 -                                               "sdb", "gethostbyname failed: ", 
22722 +                               log_error_write(srv, __FILE__, __LINE__,
22723 +                                               "sdb", "gethostbyname failed: ",
22724                                                 h_errno, host->host);
22725                                 return -1;
22726                         }
22727 -                       
22728 +
22729                         if (he->h_addrtype != AF_INET) {
22730                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
22731                                 return -1;
22732                         }
22733 -                       
22734 +
22735                         if (he->h_length != sizeof(struct in_addr)) {
22736                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
22737                                 return -1;
22738                         }
22739 -                       
22740 +
22741                         memcpy(&(fcgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
22742 -                       
22743 +
22744                 }
22745                 fcgi_addr_in.sin_port = htons(proc->port);
22746                 servlen = sizeof(fcgi_addr_in);
22747 -               
22748 +
22749                 socket_type = AF_INET;
22750                 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
22751 -               
22752 +
22753                 buffer_copy_string(proc->connection_name, "tcp:");
22754                 buffer_append_string_buffer(proc->connection_name, host->host);
22755                 buffer_append_string(proc->connection_name, ":");
22756                 buffer_append_long(proc->connection_name, proc->port);
22757         }
22758 -       
22759 +
22760         if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
22761 -               log_error_write(srv, __FILE__, __LINE__, "ss", 
22762 +               log_error_write(srv, __FILE__, __LINE__, "ss",
22763                                 "failed:", strerror(errno));
22764                 return -1;
22765         }
22766 -       
22767 +
22768         if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
22769                 /* server is not up, spawn in  */
22770                 pid_t child;
22771                 int val;
22772 -               
22773 -               if (errno != ENOENT && 
22774 +
22775 +               if (errno != ENOENT &&
22776                     !buffer_is_empty(proc->unixsocket)) {
22777                         unlink(proc->unixsocket->ptr);
22778                 }
22779 -               
22780 +
22781                 close(fcgi_fd);
22782 -               
22783 +
22784                 /* reopen socket */
22785                 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
22786 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
22787 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
22788                                 "socket failed:", strerror(errno));
22789                         return -1;
22790                 }
22791 -               
22792 +
22793                 val = 1;
22794                 if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
22795 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
22796 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
22797                                         "socketsockopt failed:", strerror(errno));
22798                         return -1;
22799                 }
22800 -               
22801 +
22802                 /* create socket */
22803                 if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
22804 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
22805 -                               "bind failed for:", 
22806 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
22807 +                               "bind failed for:",
22808                                 proc->connection_name,
22809                                 strerror(errno));
22810                         return -1;
22811                 }
22812 -               
22813 +
22814                 if (-1 == listen(fcgi_fd, 1024)) {
22815 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
22816 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
22817                                 "listen failed:", strerror(errno));
22818                         return -1;
22819                 }
22820 -               
22821 -#ifdef HAVE_FORK       
22822 +
22823 +#ifndef _WIN32
22824                 switch ((child = fork())) {
22825                 case 0: {
22826                         size_t i = 0;
22827                         char *c;
22828                         char_array env;
22829                         char_array arg;
22830 -                       
22831 +
22832                         /* create environment */
22833                         env.ptr = NULL;
22834                         env.size = 0;
22835                         env.used = 0;
22836 -                       
22837 +
22838                         arg.ptr = NULL;
22839                         arg.size = 0;
22840                         arg.used = 0;
22841 @@ -955,18 +952,18 @@
22842                                 dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
22843                                 close(fcgi_fd);
22844                         }
22845 -                       
22846 +
22847                         /* we don't need the client socket */
22848                         for (i = 3; i < 256; i++) {
22849                                 close(i);
22850                         }
22851 -                       
22852 +
22853                         /* build clean environment */
22854                         if (host->bin_env_copy->used) {
22855                                 for (i = 0; i < host->bin_env_copy->used; i++) {
22856                                         data_string *ds = (data_string *)host->bin_env_copy->data[i];
22857                                         char *ge;
22858 -                                       
22859 +
22860                                         if (NULL != (ge = getenv(ds->value->ptr))) {
22861                                                 env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge));
22862                                         }
22863 @@ -974,39 +971,39 @@
22864                         } else {
22865                                 for (i = 0; environ[i]; i++) {
22866                                         char *eq;
22867 -                                       
22868 +
22869                                         if (NULL != (eq = strchr(environ[i], '='))) {
22870                                                 env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));
22871                                         }
22872                                 }
22873                         }
22874 -                       
22875 +
22876                         /* create environment */
22877                         for (i = 0; i < host->bin_env->used; i++) {
22878                                 data_string *ds = (data_string *)host->bin_env->data[i];
22879 -                               
22880 +
22881                                 env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
22882                         }
22883 -                       
22884 +
22885                         for (i = 0; i < env.used; i++) {
22886                                 /* search for PHP_FCGI_CHILDREN */
22887                                 if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break;
22888                         }
22889 -                       
22890 +
22891                         /* not found, add a default */
22892                         if (i == env.used) {
22893                                 env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1"));
22894                         }
22895 -                       
22896 +
22897                         env.ptr[env.used] = NULL;
22898  
22899                         parse_binpath(&arg, host->bin_path);
22900 -                       
22901 +
22902                         /* chdir into the base of the bin-path,
22903                          * search for the last / */
22904                         if (NULL != (c = strrchr(arg.ptr[0], '/'))) {
22905                                 *c = '\0';
22906 -                       
22907 +
22908                                 /* change to the physical directory */
22909                                 if (-1 == chdir(arg.ptr[0])) {
22910                                         *c = '/';
22911 @@ -1018,12 +1015,12 @@
22912  
22913                         /* exec the cgi */
22914                         execve(arg.ptr[0], arg.ptr, env.ptr);
22915 -                       
22916 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
22917 +
22918 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
22919                                         "execve failed for:", host->bin_path, strerror(errno));
22920 -                       
22921 +
22922                         exit(errno);
22923 -                       
22924 +
22925                         break;
22926                 }
22927                 case -1:
22928 @@ -1031,17 +1028,17 @@
22929                         break;
22930                 default:
22931                         /* father */
22932 -                       
22933 +
22934                         /* wait */
22935                         select(0, NULL, NULL, NULL, &tv);
22936 -                       
22937 +
22938                         switch (waitpid(child, &status, WNOHANG)) {
22939                         case 0:
22940                                 /* child still running after timeout, good */
22941                                 break;
22942                         case -1:
22943                                 /* no PID found ? should never happen */
22944 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
22945 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
22946                                                 "pid not found:", strerror(errno));
22947                                 return -1;
22948                         default:
22949 @@ -1049,10 +1046,10 @@
22950                                                 "the fastcgi-backend", host->bin_path, "failed to start:");
22951                                 /* the child should not terminate at all */
22952                                 if (WIFEXITED(status)) {
22953 -                                       log_error_write(srv, __FILE__, __LINE__, "sdb", 
22954 -                                                       "child exited with status", 
22955 +                                       log_error_write(srv, __FILE__, __LINE__, "sdb",
22956 +                                                       "child exited with status",
22957                                                         WEXITSTATUS(status), host->bin_path);
22958 -                                       log_error_write(srv, __FILE__, __LINE__, "s", 
22959 +                                       log_error_write(srv, __FILE__, __LINE__, "s",
22960                                                         "if you try do run PHP as FastCGI backend make sure you use the FastCGI enabled version.\n"
22961                                                         "You can find out if it is the right one by executing 'php -v' and it should display '(cgi-fcgi)' "
22962                                                         "in the output, NOT (cgi) NOR (cli)\n"
22963 @@ -1060,8 +1057,8 @@
22964                                         log_error_write(srv, __FILE__, __LINE__, "s",
22965                                                         "If this is PHP on Gentoo add fastcgi to the USE flags");
22966                                 } else if (WIFSIGNALED(status)) {
22967 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
22968 -                                                       "terminated by signal:", 
22969 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
22970 +                                                       "terminated by signal:",
22971                                                         WTERMSIG(status));
22972  
22973                                         if (WTERMSIG(status) == 11) {
22974 @@ -1071,8 +1068,8 @@
22975                                                                 "If this is PHP try to remove the byte-code caches for now and try again.");
22976                                         }
22977                                 } else {
22978 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
22979 -                                                       "child died somehow:", 
22980 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
22981 +                                                       "child died somehow:",
22982                                                         status);
22983                                 }
22984                                 return -1;
22985 @@ -1082,26 +1079,26 @@
22986                         proc->pid = child;
22987                         proc->last_used = srv->cur_ts;
22988                         proc->is_local = 1;
22989 -                                               
22990 +
22991                         break;
22992                 }
22993  #endif
22994         } else {
22995                 proc->is_local = 0;
22996                 proc->pid = 0;
22997 -               
22998 +
22999                 if (p->conf.debug) {
23000                         log_error_write(srv, __FILE__, __LINE__, "sb",
23001                                         "(debug) socket is already used, won't spawn:",
23002                                         proc->connection_name);
23003                 }
23004         }
23005 -       
23006 +
23007         proc->state = PROC_STATE_RUNNING;
23008         host->active_procs++;
23009 -       
23010 +
23011         close(fcgi_fd);
23012 -       
23013 +
23014         return 0;
23015  }
23016  
23017 @@ -1111,93 +1108,93 @@
23018         data_unset *du;
23019         size_t i = 0;
23020         buffer *fcgi_mode = buffer_init();
23021 -       
23022 -       config_values_t cv[] = { 
23023 +
23024 +       config_values_t cv[] = {
23025                 { "fastcgi.server",              NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
23026                 { "fastcgi.debug",               NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
23027                 { "fastcgi.map-extensions",      NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
23028                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
23029         };
23030 -       
23031 +
23032         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
23033 -       
23034 +
23035         for (i = 0; i < srv->config_context->used; i++) {
23036                 plugin_config *s;
23037                 array *ca;
23038 -               
23039 +
23040                 s = malloc(sizeof(plugin_config));
23041                 s->exts          = fastcgi_extensions_init();
23042                 s->debug         = 0;
23043                 s->ext_mapping   = array_init();
23044 -               
23045 +
23046                 cv[0].destination = s->exts;
23047                 cv[1].destination = &(s->debug);
23048                 cv[2].destination = s->ext_mapping;
23049 -               
23050 +
23051                 p->config_storage[i] = s;
23052                 ca = ((data_config *)srv->config_context->data[i])->value;
23053 -       
23054 +
23055                 if (0 != config_insert_values_global(srv, ca, cv)) {
23056                         return HANDLER_ERROR;
23057                 }
23058 -               
23059 -               /* 
23060 +
23061 +               /*
23062                  * <key> = ( ... )
23063                  */
23064 -               
23065 +
23066                 if (NULL != (du = array_get_element(ca, "fastcgi.server"))) {
23067                         size_t j;
23068                         data_array *da = (data_array *)du;
23069 -                       
23070 +
23071                         if (du->type != TYPE_ARRAY) {
23072 -                               log_error_write(srv, __FILE__, __LINE__, "sss", 
23073 +                               log_error_write(srv, __FILE__, __LINE__, "sss",
23074                                                 "unexpected type for key: ", "fastcgi.server", "array of strings");
23075 -                               
23076 +
23077                                 return HANDLER_ERROR;
23078                         }
23079 -                       
23080 -                       
23081 -                       /* 
23082 -                        * fastcgi.server = ( "<ext>" => ( ... ), 
23083 +
23084 +
23085 +                       /*
23086 +                        * fastcgi.server = ( "<ext>" => ( ... ),
23087                          *                    "<ext>" => ( ... ) )
23088                          */
23089 -                       
23090 +
23091                         for (j = 0; j < da->value->used; j++) {
23092                                 size_t n;
23093                                 data_array *da_ext = (data_array *)da->value->data[j];
23094 -                               
23095 +
23096                                 if (da->value->data[j]->type != TYPE_ARRAY) {
23097 -                                       log_error_write(srv, __FILE__, __LINE__, "sssbs", 
23098 -                                                       "unexpected type for key: ", "fastcgi.server", 
23099 +                                       log_error_write(srv, __FILE__, __LINE__, "sssbs",
23100 +                                                       "unexpected type for key: ", "fastcgi.server",
23101                                                         "[", da->value->data[j]->key, "](string)");
23102 -                                       
23103 +
23104                                         return HANDLER_ERROR;
23105                                 }
23106 -                               
23107 -                               /* 
23108 -                                * da_ext->key == name of the extension 
23109 +
23110 +                               /*
23111 +                                * da_ext->key == name of the extension
23112                                  */
23113 -                               
23114 -                               /* 
23115 -                                * fastcgi.server = ( "<ext>" => 
23116 -                                *                     ( "<host>" => ( ... ), 
23117 +
23118 +                               /*
23119 +                                * fastcgi.server = ( "<ext>" =>
23120 +                                *                     ( "<host>" => ( ... ),
23121                                  *                       "<host>" => ( ... )
23122 -                                *                     ), 
23123 +                                *                     ),
23124                                  *                    "<ext>" => ... )
23125                                  */
23126 -                                       
23127 +
23128                                 for (n = 0; n < da_ext->value->used; n++) {
23129                                         data_array *da_host = (data_array *)da_ext->value->data[n];
23130 -                                       
23131 +
23132                                         fcgi_extension_host *host;
23133 -                                       
23134 -                                       config_values_t fcv[] = { 
23135 +
23136 +                                       config_values_t fcv[] = {
23137                                                 { "host",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
23138                                                 { "docroot",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
23139                                                 { "mode",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
23140                                                 { "socket",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
23141                                                 { "bin-path",          NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 4 */
23142 -                                               
23143 +
23144                                                 { "check-local",       NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 5 */
23145                                                 { "port",              NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 6 */
23146                                                 { "min-procs-not-working",         NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 7 this is broken for now */
23147 @@ -1205,28 +1202,28 @@
23148                                                 { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 9 */
23149                                                 { "idle-timeout",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 10 */
23150                                                 { "disable-time",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 11 */
23151 -                                               
23152 +
23153                                                 { "bin-environment",   NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },        /* 12 */
23154                                                 { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },     /* 13 */
23155 -                                               
23156 +
23157                                                 { "broken-scriptfilename", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },  /* 14 */
23158                                                 { "allow-x-send-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 15 */
23159                                                 { "strip-request-uri",  NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 16 */
23160 -                                               
23161 +
23162                                                 { NULL,                NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
23163                                         };
23164 -                                       
23165 +
23166                                         if (da_host->type != TYPE_ARRAY) {
23167 -                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS", 
23168 -                                                               "unexpected type for key:", 
23169 -                                                               "fastcgi.server", 
23170 +                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS",
23171 +                                                               "unexpected type for key:",
23172 +                                                               "fastcgi.server",
23173                                                                 "[", da_host->key, "](string)");
23174 -                                               
23175 +
23176                                                 return HANDLER_ERROR;
23177                                         }
23178 -                                       
23179 +
23180                                         host = fastcgi_host_init();
23181 -                                       
23182 +
23183                                         buffer_copy_string_buffer(host->id, da_host->key);
23184  
23185                                         host->check_local  = 1;
23186 @@ -1238,13 +1235,13 @@
23187                                         host->disable_time = 60;
23188                                         host->break_scriptfilename_for_php = 0;
23189                                         host->allow_xsendfile = 0; /* handle X-LIGHTTPD-send-file */
23190 -                                       
23191 +
23192                                         fcv[0].destination = host->host;
23193                                         fcv[1].destination = host->docroot;
23194                                         fcv[2].destination = fcgi_mode;
23195                                         fcv[3].destination = host->unixsocket;
23196                                         fcv[4].destination = host->bin_path;
23197 -                                       
23198 +
23199                                         fcv[5].destination = &(host->check_local);
23200                                         fcv[6].destination = &(host->port);
23201                                         fcv[7].destination = &(host->min_procs);
23202 @@ -1252,35 +1249,35 @@
23203                                         fcv[9].destination = &(host->max_load_per_proc);
23204                                         fcv[10].destination = &(host->idle_timeout);
23205                                         fcv[11].destination = &(host->disable_time);
23206 -                                       
23207 +
23208                                         fcv[12].destination = host->bin_env;
23209                                         fcv[13].destination = host->bin_env_copy;
23210                                         fcv[14].destination = &(host->break_scriptfilename_for_php);
23211                                         fcv[15].destination = &(host->allow_xsendfile);
23212                                         fcv[16].destination = host->strip_request_uri;
23213 -                                       
23214 +
23215                                         if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
23216                                                 return HANDLER_ERROR;
23217                                         }
23218 -                                                       
23219 -                                       if ((!buffer_is_empty(host->host) || host->port) && 
23220 +
23221 +                                       if ((!buffer_is_empty(host->host) || host->port) &&
23222                                             !buffer_is_empty(host->unixsocket)) {
23223 -                                               log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", 
23224 +                                               log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23225                                                                 "either host/port or socket have to be set in:",
23226 -                                                               da->key, "= (", 
23227 +                                                               da->key, "= (",
23228                                                                 da_ext->key, " => (",
23229                                                                 da_host->key, " ( ...");
23230  
23231                                                 return HANDLER_ERROR;
23232                                         }
23233 -                                       
23234 +
23235                                         if (!buffer_is_empty(host->unixsocket)) {
23236                                                 /* unix domain socket */
23237 -                                               
23238 +
23239                                                 if (host->unixsocket->used > UNIX_PATH_MAX - 2) {
23240 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", 
23241 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23242                                                                         "unixsocket is too long in:",
23243 -                                                                       da->key, "= (", 
23244 +                                                                       da->key, "= (",
23245                                                                         da_ext->key, " => (",
23246                                                                         da_host->key, " ( ...");
23247  
23248 @@ -1288,37 +1285,37 @@
23249                                                 }
23250                                         } else {
23251                                                 /* tcp/ip */
23252 -                                               
23253 -                                               if (buffer_is_empty(host->host) && 
23254 +
23255 +                                               if (buffer_is_empty(host->host) &&
23256                                                     buffer_is_empty(host->bin_path)) {
23257 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", 
23258 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23259                                                                         "host or binpath have to be set in:",
23260 -                                                                       da->key, "= (", 
23261 +                                                                       da->key, "= (",
23262                                                                         da_ext->key, " => (",
23263                                                                         da_host->key, " ( ...");
23264 -                                                       
23265 +
23266                                                         return HANDLER_ERROR;
23267                                                 } else if (host->port == 0) {
23268 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", 
23269 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23270                                                                         "port has to be set in:",
23271 -                                                                       da->key, "= (", 
23272 +                                                                       da->key, "= (",
23273                                                                         da_ext->key, " => (",
23274                                                                         da_host->key, " ( ...");
23275  
23276                                                         return HANDLER_ERROR;
23277                                                 }
23278                                         }
23279 -                                               
23280 -                                       if (!buffer_is_empty(host->bin_path)) { 
23281 +
23282 +                                       if (!buffer_is_empty(host->bin_path)) {
23283                                                 /* a local socket + self spawning */
23284                                                 size_t pno;
23285  
23286                                                 /* HACK:  just to make sure the adaptive spawing is disabled */
23287                                                 host->min_procs = host->max_procs;
23288 -                                               
23289 +
23290                                                 if (host->min_procs > host->max_procs) host->max_procs = host->min_procs;
23291                                                 if (host->max_load_per_proc < 1) host->max_load_per_proc = 0;
23292 -                                               
23293 +
23294                                                 if (s->debug) {
23295                                                         log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
23296                                                                         "--- fastcgi spawning local",
23297 @@ -1328,7 +1325,7 @@
23298                                                                         "\n\tmin-procs:", host->min_procs,
23299                                                                         "\n\tmax-procs:", host->max_procs);
23300                                                 }
23301 -                                               
23302 +
23303                                                 for (pno = 0; pno < host->min_procs; pno++) {
23304                                                         fcgi_proc *proc;
23305  
23306 @@ -1343,7 +1340,7 @@
23307                                                                 buffer_append_string(proc->unixsocket, "-");
23308                                                                 buffer_append_long(proc->unixsocket, pno);
23309                                                         }
23310 -                                                       
23311 +
23312                                                         if (s->debug) {
23313                                                                 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
23314                                                                                 "--- fastcgi spawning",
23315 @@ -1351,7 +1348,7 @@
23316                                                                                 "\n\tsocket", host->unixsocket,
23317                                                                                 "\n\tcurrent:", pno, "/", host->min_procs);
23318                                                         }
23319 -                                                       
23320 +
23321                                                         if (fcgi_spawn_connection(srv, p, host, proc)) {
23322                                                                 log_error_write(srv, __FILE__, __LINE__, "s",
23323                                                                                 "[ERROR]: spawning fcgi failed.");
23324 @@ -1359,35 +1356,35 @@
23325                                                         }
23326  
23327                                                         fastcgi_status_init(srv, p->statuskey, host, proc);
23328 -                                                       
23329 +
23330                                                         proc->next = host->first;
23331                                                         if (host->first)        host->first->prev = proc;
23332 -                                                       
23333 +
23334                                                         host->first = proc;
23335                                                 }
23336                                         } else {
23337                                                 fcgi_proc *proc;
23338 -                                               
23339 +
23340                                                 proc = fastcgi_process_init();
23341                                                 proc->id = host->num_procs++;
23342                                                 host->max_id++;
23343                                                 host->active_procs++;
23344                                                 proc->state = PROC_STATE_RUNNING;
23345 -                                               
23346 +
23347                                                 if (buffer_is_empty(host->unixsocket)) {
23348                                                         proc->port = host->port;
23349                                                 } else {
23350                                                         buffer_copy_string_buffer(proc->unixsocket, host->unixsocket);
23351                                                 }
23352 -                                               
23353 +
23354                                                 fastcgi_status_init(srv, p->statuskey, host, proc);
23355  
23356                                                 host->first = proc;
23357 -                                               
23358 +
23359                                                 host->min_procs = 1;
23360                                                 host->max_procs = 1;
23361                                         }
23362 -                                       
23363 +
23364                                         if (!buffer_is_empty(fcgi_mode)) {
23365                                                 if (strcmp(fcgi_mode->ptr, "responder") == 0) {
23366                                                         host->mode = FCGI_RESPONDER;
23367 @@ -1411,16 +1408,16 @@
23368                         }
23369                 }
23370         }
23371 -       
23372 +
23373         buffer_free(fcgi_mode);
23374 -       
23375 +
23376         return HANDLER_GO_ON;
23377  }
23378  
23379  static int fcgi_set_state(server *srv, handler_ctx *hctx, fcgi_connection_state_t state) {
23380         hctx->state = state;
23381         hctx->state_timestamp = srv->cur_ts;
23382 -       
23383 +
23384         return 0;
23385  }
23386  
23387 @@ -1429,13 +1426,13 @@
23388         size_t m = 0;
23389         size_t i;
23390         buffer_uint *r = &(p->fcgi_request_id);
23391 -       
23392 +
23393         UNUSED(srv);
23394  
23395         for (i = 0; i < r->used; i++) {
23396                 if (r->ptr[i] > m) m = r->ptr[i];
23397         }
23398 -       
23399 +
23400         if (r->size == 0) {
23401                 r->size = 16;
23402                 r->ptr = malloc(sizeof(*r->ptr) * r->size);
23403 @@ -1443,54 +1440,55 @@
23404                 r->size += 16;
23405                 r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
23406         }
23407 -       
23408 +
23409         r->ptr[r->used++] = ++m;
23410 -       
23411 +
23412         return m;
23413  }
23414  
23415  static int fcgi_requestid_del(server *srv, plugin_data *p, size_t request_id) {
23416         size_t i;
23417         buffer_uint *r = &(p->fcgi_request_id);
23418 -       
23419 +
23420         UNUSED(srv);
23421  
23422         for (i = 0; i < r->used; i++) {
23423                 if (r->ptr[i] == request_id) break;
23424         }
23425 -       
23426 +
23427         if (i != r->used) {
23428                 /* found */
23429 -               
23430 +
23431                 if (i != r->used - 1) {
23432                         r->ptr[i] = r->ptr[r->used - 1];
23433                 }
23434                 r->used--;
23435         }
23436 -       
23437 +
23438         return 0;
23439  }
23440  void fcgi_connection_close(server *srv, handler_ctx *hctx) {
23441         plugin_data *p;
23442         connection  *con;
23443 -       
23444 +
23445         if (NULL == hctx) return;
23446 -       
23447 +
23448         p    = hctx->plugin_data;
23449         con  = hctx->remote_conn;
23450 -       
23451 +
23452         if (con->mode != p->id) {
23453 -               WP();
23454                 return;
23455         }
23456 -       
23457 -       if (hctx->fd != -1) {
23458 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
23459 -               fdevent_unregister(srv->ev, hctx->fd);
23460 -               close(hctx->fd);
23461 -               srv->cur_fds--;
23462 +
23463 +       if (hctx->sock->fd != -1) {
23464 +               fdevent_event_del(srv->ev, hctx->sock);
23465 +               fdevent_unregister(srv->ev, hctx->sock);
23466 +               closesocket(hctx->sock->fd);
23467 +               hctx->sock->fd = -1;
23468 +
23469 +               srv->cur_fds--;
23470         }
23471 -       
23472 +
23473         if (hctx->request_id != 0) {
23474                 fcgi_requestid_del(srv, p, hctx->request_id);
23475         }
23476 @@ -1499,7 +1497,7 @@
23477                 if (hctx->got_proc) {
23478                         /* after the connect the process gets a load */
23479                         hctx->proc->load--;
23480 -                       
23481 +
23482                         status_counter_dec(srv, CONST_STR_LEN("fastcgi.active-requests"));
23483  
23484                         fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
23485 @@ -1509,101 +1507,101 @@
23486  
23487                         if (p->conf.debug) {
23488                                 log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
23489 -                                               "released proc:", 
23490 -                                               "pid:", hctx->proc->pid, 
23491 -                                               "socket:", hctx->proc->connection_name, 
23492 +                                               "released proc:",
23493 +                                               "pid:", hctx->proc->pid,
23494 +                                               "socket:", hctx->proc->connection_name,
23495                                                 "load:", hctx->proc->load);
23496                         }
23497                 }
23498         }
23499  
23500 -       
23501 +
23502         handler_ctx_free(hctx);
23503 -       con->plugin_ctx[p->id] = NULL;  
23504 +       con->plugin_ctx[p->id] = NULL;
23505  }
23506  
23507  static int fcgi_reconnect(server *srv, handler_ctx *hctx) {
23508         plugin_data *p    = hctx->plugin_data;
23509 -       
23510 -       /* child died 
23511 -        * 
23512 -        * 1. 
23513 -        * 
23514 +
23515 +       /* child died
23516 +        *
23517 +        * 1.
23518 +        *
23519          * connect was ok, connection was accepted
23520          * but the php accept loop checks after the accept if it should die or not.
23521 -        * 
23522 -        * if yes we can only detect it at a write() 
23523 -        * 
23524 +        *
23525 +        * if yes we can only detect it at a write()
23526 +        *
23527          * next step is resetting this attemp and setup a connection again
23528 -        * 
23529 +        *
23530          * if we have more then 5 reconnects for the same request, die
23531 -        * 
23532 -        * 2. 
23533 -        * 
23534 +        *
23535 +        * 2.
23536 +        *
23537          * we have a connection but the child died by some other reason
23538 -        * 
23539 +        *
23540          */
23541  
23542 -       if (hctx->fd != -1) {
23543 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
23544 -               fdevent_unregister(srv->ev, hctx->fd);
23545 -               close(hctx->fd);
23546 +       if (hctx->sock->fd != -1) {
23547 +               fdevent_event_del(srv->ev, hctx->sock);
23548 +               fdevent_unregister(srv->ev, hctx->sock);
23549 +               close(hctx->sock->fd);
23550                 srv->cur_fds--;
23551 -               hctx->fd = -1;
23552 +               hctx->sock->fd = -1;
23553         }
23554 -       
23555 +
23556         fcgi_requestid_del(srv, p, hctx->request_id);
23557 -       
23558 +
23559         fcgi_set_state(srv, hctx, FCGI_STATE_INIT);
23560 -       
23561 +
23562         hctx->request_id = 0;
23563         hctx->reconnects++;
23564 -       
23565 +
23566         if (p->conf.debug > 2) {
23567                 if (hctx->proc) {
23568                         log_error_write(srv, __FILE__, __LINE__, "sdb",
23569 -                                       "release proc for reconnect:", 
23570 +                                       "release proc for reconnect:",
23571                                         hctx->proc->pid, hctx->proc->connection_name);
23572                 } else {
23573                         log_error_write(srv, __FILE__, __LINE__, "sb",
23574 -                                       "release proc for reconnect:", 
23575 +                                       "release proc for reconnect:",
23576                                         hctx->host->unixsocket);
23577                 }
23578         }
23579  
23580 -       if (hctx->proc && hctx->got_proc) {     
23581 +       if (hctx->proc && hctx->got_proc) {
23582                 hctx->proc->load--;
23583         }
23584  
23585         /* perhaps another host gives us more luck */
23586         hctx->host->load--;
23587         hctx->host = NULL;
23588 -       
23589 +
23590         return 0;
23591  }
23592  
23593  
23594  static handler_t fcgi_connection_reset(server *srv, connection *con, void *p_d) {
23595         plugin_data *p = p_d;
23596 -       
23597 +
23598         fcgi_connection_close(srv, con->plugin_ctx[p->id]);
23599 -       
23600 +
23601         return HANDLER_GO_ON;
23602  }
23603  
23604  
23605  static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
23606         size_t len;
23607 -       
23608 +
23609         if (!key || !val) return -1;
23610 -       
23611 +
23612         len = key_len + val_len;
23613 -       
23614 +
23615         len += key_len > 127 ? 4 : 1;
23616         len += val_len > 127 ? 4 : 1;
23617 -       
23618 +
23619         buffer_prepare_append(env, len);
23620 -       
23621 +
23622         if (key_len > 127) {
23623                 env->ptr[env->used++] = ((key_len >> 24) & 0xff) | 0x80;
23624                 env->ptr[env->used++] = (key_len >> 16) & 0xff;
23625 @@ -1612,7 +1610,7 @@
23626         } else {
23627                 env->ptr[env->used++] = (key_len >> 0) & 0xff;
23628         }
23629 -       
23630 +
23631         if (val_len > 127) {
23632                 env->ptr[env->used++] = ((val_len >> 24) & 0xff) | 0x80;
23633                 env->ptr[env->used++] = (val_len >> 16) & 0xff;
23634 @@ -1621,12 +1619,12 @@
23635         } else {
23636                 env->ptr[env->used++] = (val_len >> 0) & 0xff;
23637         }
23638 -       
23639 +
23640         memcpy(env->ptr + env->used, key, key_len);
23641         env->used += key_len;
23642         memcpy(env->ptr + env->used, val, val_len);
23643         env->used += val_len;
23644 -       
23645 +
23646         return 0;
23647  }
23648  
23649 @@ -1639,11 +1637,11 @@
23650         header->contentLengthB1 = (contentLength >> 8) & 0xff;
23651         header->paddingLength = paddingLength;
23652         header->reserved = 0;
23653 -       
23654 +
23655         return 0;
23656  }
23657  /**
23658 - * 
23659 + *
23660   * returns
23661   *   -1 error
23662   *    0 connected
23663 @@ -1665,26 +1663,23 @@
23664         struct sockaddr_un fcgi_addr_un;
23665  #endif
23666         socklen_t servlen;
23667 -       
23668 +
23669         fcgi_extension_host *host = hctx->host;
23670         fcgi_proc *proc   = hctx->proc;
23671 -       int fcgi_fd       = hctx->fd;
23672 -       
23673 +       int fcgi_fd       = hctx->sock->fd;
23674 +
23675         memset(&fcgi_addr, 0, sizeof(fcgi_addr));
23676 -       
23677 +
23678         if (!buffer_is_empty(proc->unixsocket)) {
23679  #ifdef HAVE_SYS_UN_H
23680                 /* use the unix domain socket */
23681                 fcgi_addr_un.sun_family = AF_UNIX;
23682                 strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
23683 -#ifdef SUN_LEN
23684 +
23685                 servlen = SUN_LEN(&fcgi_addr_un);
23686 -#else
23687 -               /* stevens says: */
23688 -               servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
23689 -#endif
23690 +
23691                 fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
23692 -       
23693 +
23694                 if (buffer_is_empty(proc->connection_name)) {
23695                         /* on remote spawing we have to set the connection-name now */
23696                         buffer_copy_string(proc->connection_name, "unix:");
23697 @@ -1695,16 +1690,18 @@
23698  #endif
23699         } else {
23700                 fcgi_addr_in.sin_family = AF_INET;
23701 +
23702                 if (0 == inet_aton(host->host->ptr, &(fcgi_addr_in.sin_addr))) {
23703 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
23704 -                                       "converting IP-adress failed for", host->host, 
23705 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
23706 +                                       "converting IP-adress failed for", host->host,
23707                                         "\nBe sure to specify an IP address here");
23708 -                       
23709 +
23710                         return -1;
23711                 }
23712 +
23713                 fcgi_addr_in.sin_port = htons(proc->port);
23714                 servlen = sizeof(fcgi_addr_in);
23715 -               
23716 +
23717                 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
23718  
23719                 if (buffer_is_empty(proc->connection_name)) {
23720 @@ -1715,20 +1712,20 @@
23721                         buffer_append_long(proc->connection_name, proc->port);
23722                 }
23723         }
23724 -       
23725 +
23726         if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
23727 -               if (errno == EINPROGRESS || 
23728 +               if (errno == EINPROGRESS ||
23729                     errno == EALREADY ||
23730                     errno == EINTR) {
23731                         if (hctx->conf.debug > 2) {
23732 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
23733 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
23734                                         "connect delayed, will continue later:", proc->connection_name);
23735                         }
23736 -                       
23737 +
23738                         return CONNECTION_DELAYED;
23739                 } else if (errno == EAGAIN) {
23740                         if (hctx->conf.debug) {
23741 -                               log_error_write(srv, __FILE__, __LINE__, "sbsd", 
23742 +                               log_error_write(srv, __FILE__, __LINE__, "sbsd",
23743                                         "This means that the you have more incoming requests than your fastcgi-backend can handle in parallel. "
23744                                         "Perhaps it helps to spawn more fastcgi backend or php-children, if not decrease server.max-connections."
23745                                         "The load for this fastcgi backend", proc->connection_name, "is", proc->load);
23746 @@ -1736,8 +1733,8 @@
23747  
23748                         return CONNECTION_OVERLOADED;
23749                 } else {
23750 -                       log_error_write(srv, __FILE__, __LINE__, "sssb", 
23751 -                                       "connect failed:", 
23752 +                       log_error_write(srv, __FILE__, __LINE__, "sssb",
23753 +                                       "connect failed:",
23754                                         strerror(errno), "on",
23755                                         proc->connection_name);
23756  
23757 @@ -1747,7 +1744,7 @@
23758  
23759         hctx->reconnects = 0;
23760         if (hctx->conf.debug > 1) {
23761 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
23762 +               log_error_write(srv, __FILE__, __LINE__, "sd",
23763                                 "connect succeeded: ", fcgi_fd);
23764         }
23765  
23766 @@ -1756,21 +1753,21 @@
23767  
23768  static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
23769         size_t i;
23770 -       
23771 +
23772         for (i = 0; i < con->request.headers->used; i++) {
23773                 data_string *ds;
23774 -               
23775 +
23776                 ds = (data_string *)con->request.headers->data[i];
23777 -               
23778 +
23779                 if (ds->value->used && ds->key->used) {
23780                         size_t j;
23781                         buffer_reset(srv->tmp_buf);
23782 -                       
23783 +
23784                         if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
23785                                 BUFFER_COPY_STRING_CONST(srv->tmp_buf, "HTTP_");
23786                                 srv->tmp_buf->used--;
23787                         }
23788 -                       
23789 +
23790                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
23791                         for (j = 0; j < ds->key->used - 1; j++) {
23792                                 char c = '_';
23793 @@ -1784,20 +1781,20 @@
23794                                 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
23795                         }
23796                         srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
23797 -                       
23798 +
23799                         fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
23800                 }
23801         }
23802 -       
23803 +
23804         for (i = 0; i < con->environment->used; i++) {
23805                 data_string *ds;
23806 -               
23807 +
23808                 ds = (data_string *)con->environment->data[i];
23809 -               
23810 +
23811                 if (ds->value->used && ds->key->used) {
23812                         size_t j;
23813                         buffer_reset(srv->tmp_buf);
23814 -                       
23815 +
23816                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
23817                         for (j = 0; j < ds->key->used - 1; j++) {
23818                                 char c = '_';
23819 @@ -1811,11 +1808,11 @@
23820                                 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
23821                         }
23822                         srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
23823 -                       
23824 +
23825                         fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
23826                 }
23827         }
23828 -       
23829 +
23830         return 0;
23831  }
23832  
23833 @@ -1824,24 +1821,24 @@
23834         FCGI_BeginRequestRecord beginRecord;
23835         FCGI_Header header;
23836         buffer *b;
23837 -       
23838 +
23839         char buf[32];
23840         const char *s;
23841  #ifdef HAVE_IPV6
23842         char b2[INET6_ADDRSTRLEN + 1];
23843  #endif
23844 -       
23845 +
23846         plugin_data *p    = hctx->plugin_data;
23847         fcgi_extension_host *host= hctx->host;
23848  
23849         connection *con   = hctx->remote_conn;
23850         server_socket *srv_sock = con->srv_socket;
23851 -       
23852 +
23853         sock_addr our_addr;
23854         socklen_t our_addr_len;
23855 -       
23856 +
23857         /* send FCGI_BEGIN_REQUEST */
23858 -       
23859 +
23860         fcgi_header(&(beginRecord.header), FCGI_BEGIN_REQUEST, request_id, sizeof(beginRecord.body), 0);
23861         beginRecord.body.roleB0 = host->mode;
23862         beginRecord.body.roleB1 = 0;
23863 @@ -1849,21 +1846,21 @@
23864         memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved));
23865  
23866         b = chunkqueue_get_append_buffer(hctx->wb);
23867 -       
23868 +
23869         buffer_copy_memory(b, (const char *)&beginRecord, sizeof(beginRecord));
23870 -       
23871 +
23872         /* send FCGI_PARAMS */
23873         buffer_prepare_copy(p->fcgi_env, 1024);
23874  
23875  
23876         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
23877 -       
23878 +
23879         if (con->server_name->used) {
23880                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
23881         } else {
23882  #ifdef HAVE_IPV6
23883 -               s = inet_ntop(srv_sock->addr.plain.sa_family, 
23884 -                             srv_sock->addr.plain.sa_family == AF_INET6 ? 
23885 +               s = inet_ntop(srv_sock->addr.plain.sa_family,
23886 +                             srv_sock->addr.plain.sa_family == AF_INET6 ?
23887                               (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
23888                               (const void *) &(srv_sock->addr.ipv4.sin_addr),
23889                               b2, sizeof(b2)-1);
23890 @@ -1872,50 +1869,50 @@
23891  #endif
23892                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
23893         }
23894 -       
23895 +
23896         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
23897 -       
23898 -       ltostr(buf, 
23899 +
23900 +       ltostr(buf,
23901  #ifdef HAVE_IPV6
23902                ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
23903  #else
23904                ntohs(srv_sock->addr.ipv4.sin_port)
23905  #endif
23906                );
23907 -       
23908 +
23909         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
23910 -       
23911 +
23912         /* get the server-side of the connection to the client */
23913         our_addr_len = sizeof(our_addr);
23914 -       
23915 -       if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
23916 +
23917 +       if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
23918                 s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
23919         } else {
23920                 s = inet_ntop_cache_get_ip(srv, &(our_addr));
23921         }
23922         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
23923 -       
23924 -       ltostr(buf, 
23925 +
23926 +       ltostr(buf,
23927  #ifdef HAVE_IPV6
23928                ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
23929  #else
23930                ntohs(con->dst_addr.ipv4.sin_port)
23931  #endif
23932                );
23933 -       
23934 +
23935         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
23936 -       
23937 +
23938         s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
23939         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
23940 -       
23941 +
23942         if (!buffer_is_empty(con->authed_user)) {
23943                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_USER"),
23944                              CONST_BUF_LEN(con->authed_user));
23945         }
23946 -       
23947 +
23948         if (con->request.content_length > 0 && host->mode != FCGI_AUTHORIZER) {
23949                 /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
23950 -               
23951 +
23952                 /* request.content_length < SSIZE_MAX, see request.c */
23953                 ltostr(buf, con->request.content_length);
23954                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
23955 @@ -1930,12 +1927,12 @@
23956                  */
23957  
23958                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
23959 -               
23960 +
23961                 if (!buffer_is_empty(con->request.pathinfo)) {
23962                         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
23963 -                       
23964 +
23965                         /* PATH_TRANSLATED is only defined if PATH_INFO is set */
23966 -                       
23967 +
23968                         if (!buffer_is_empty(host->docroot)) {
23969                                 buffer_copy_string_buffer(p->path, host->docroot);
23970                         } else {
23971 @@ -1957,27 +1954,27 @@
23972          */
23973  
23974         if (!buffer_is_empty(host->docroot)) {
23975 -               /* 
23976 -                * rewrite SCRIPT_FILENAME 
23977 -                * 
23978 +               /*
23979 +                * rewrite SCRIPT_FILENAME
23980 +                *
23981                  */
23982 -               
23983 +
23984                 buffer_copy_string_buffer(p->path, host->docroot);
23985                 buffer_append_string_buffer(p->path, con->uri.path);
23986 -               
23987 +
23988                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
23989                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot));
23990         } else {
23991                 buffer_copy_string_buffer(p->path, con->physical.path);
23992 -               
23993 -               /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself 
23994 -                * 
23995 +
23996 +               /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself
23997 +                *
23998                  * see src/sapi/cgi_main.c, init_request_info()
23999                  */
24000                 if (host->break_scriptfilename_for_php) {
24001                         buffer_append_string_buffer(p->path, con->request.pathinfo);
24002                 }
24003 -               
24004 +
24005                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
24006                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
24007         }
24008 @@ -1987,7 +1984,7 @@
24009                 /**
24010                  * /app1/index/list
24011                  *
24012 -                * stripping /app1 or /app1/ should lead to 
24013 +                * stripping /app1 or /app1/ should lead to
24014                  *
24015                  * /index/list
24016                  *
24017 @@ -2001,7 +1998,7 @@
24018                     0 == strncmp(con->request.orig_uri->ptr, host->strip_request_uri->ptr, host->strip_request_uri->used - 1)) {
24019                         /* the left is the same */
24020  
24021 -                       fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), 
24022 +                       fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"),
24023                                         con->request.orig_uri->ptr + (host->strip_request_uri->used - 2),
24024                                         con->request.orig_uri->used - (host->strip_request_uri->used - 2));
24025                 } else {
24026 @@ -2018,26 +2015,26 @@
24027         } else {
24028                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
24029         }
24030 -       
24031 +
24032         s = get_http_method_name(con->request.http_method);
24033         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
24034         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
24035         s = get_http_version_name(con->request.http_version);
24036         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
24037 -       
24038 +
24039  #ifdef USE_OPENSSL
24040         if (srv_sock->is_ssl) {
24041                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
24042         }
24043  #endif
24044 -       
24045 -       
24046 +
24047 +
24048         fcgi_env_add_request_headers(srv, con, p);
24049 -       
24050 +
24051         fcgi_header(&(header), FCGI_PARAMS, request_id, p->fcgi_env->used, 0);
24052         buffer_append_memory(b, (const char *)&header, sizeof(header));
24053         buffer_append_memory(b, (const char *)p->fcgi_env->ptr, p->fcgi_env->used);
24054 -       
24055 +
24056         fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0);
24057         buffer_append_memory(b, (const char *)&header, sizeof(header));
24058  
24059 @@ -2057,7 +2054,7 @@
24060  
24061                         /* we announce toWrite octects
24062                          * now take all the request_content chunk that we need to fill this request
24063 -                        * */   
24064 +                        * */
24065  
24066                         b = chunkqueue_get_append_buffer(hctx->wb);
24067                         fcgi_header(&(header), FCGI_STDIN, request_id, weWant, 0);
24068 @@ -2080,16 +2077,16 @@
24069                                         if (weHave > weWant - written) weHave = weWant - written;
24070  
24071                                         if (p->conf.debug > 10) {
24072 -                                               fprintf(stderr, "%s.%d: sending %lld bytes from (%lld / %lld) %s\n", 
24073 -                                                               __FILE__, __LINE__, 
24074 -                                                               weHave, 
24075 -                                                               req_c->offset, 
24076 -                                                               req_c->file.length, 
24077 +                                               fprintf(stderr, "%s.%d: sending %lld bytes from (%lld / %lld) %s\n",
24078 +                                                               __FILE__, __LINE__,
24079 +                                                               weHave,
24080 +                                                               req_c->offset,
24081 +                                                               req_c->file.length,
24082                                                                 req_c->file.name->ptr);
24083                                         }
24084  
24085                                         assert(weHave != 0);
24086 -                                       
24087 +
24088                                         chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave);
24089  
24090                                         req_c->offset += weHave;
24091 @@ -2104,7 +2101,7 @@
24092                                          * - we reference the tempfile from the request-content-queue several times
24093                                          *   if the req_c is larger than FCGI_MAX_LENGTH
24094                                          * - we can't simply cleanup the request-content-queue as soon as possible
24095 -                                        *   as it would remove the tempfiles 
24096 +                                        *   as it would remove the tempfiles
24097                                          * - the idea is to 'steal' the tempfiles and attach the is_temp flag to the last
24098                                          *   referencing chunk of the fastcgi-write-queue
24099                                          *
24100 @@ -2141,7 +2138,7 @@
24101                                         req_c->offset += weHave;
24102                                         req_cq->bytes_out += weHave;
24103                                         written += weHave;
24104 -                                       
24105 +
24106                                         hctx->wb->bytes_in += weHave;
24107  
24108                                         if (req_c->offset == req_c->mem->used - 1) {
24109 @@ -2155,12 +2152,12 @@
24110                                         break;
24111                                 }
24112                         }
24113 -                       
24114 +
24115                         b->used++; /* add virtual \0 */
24116                         offset += weWant;
24117                 }
24118         }
24119 -       
24120 +
24121         b = chunkqueue_get_append_buffer(hctx->wb);
24122         /* terminate STDIN */
24123         fcgi_header(&(header), FCGI_STDIN, request_id, 0, 0);
24124 @@ -2175,118 +2172,19 @@
24125                 if ((i+1) % 16 == 0) {
24126                         size_t j;
24127                         for (j = i-15; j <= i; j++) {
24128 -                               fprintf(stderr, "%c", 
24129 +                               fprintf(stderr, "%c",
24130                                         isprint((unsigned char)hctx->write_buffer->ptr[j]) ? hctx->write_buffer->ptr[j] : '.');
24131                         }
24132                         fprintf(stderr, "\n");
24133                 }
24134         }
24135  #endif
24136 -       
24137 -       return 0;
24138 -}
24139 -
24140 -static int fcgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
24141 -       char *s, *ns;
24142 -       
24143 -       handler_ctx *hctx = con->plugin_ctx[p->id];
24144 -       fcgi_extension_host *host= hctx->host;
24145 -       
24146 -       UNUSED(srv);
24147  
24148 -       buffer_copy_string_buffer(p->parse_response, in);
24149 -       
24150 -       /* search for \n */
24151 -       for (s = p->parse_response->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1) {
24152 -               char *key, *value;
24153 -               int key_len;
24154 -               data_string *ds;
24155 -               
24156 -               /* a good day. Someone has read the specs and is sending a \r\n to us */
24157 -               
24158 -               if (ns > p->parse_response->ptr &&
24159 -                   *(ns-1) == '\r') {
24160 -                       *(ns-1) = '\0';
24161 -               }
24162 -               
24163 -               ns[0] = '\0';
24164 -               
24165 -               key = s;
24166 -               if (NULL == (value = strchr(s, ':'))) {
24167 -                       /* we expect: "<key>: <value>\n" */
24168 -                       continue;
24169 -               }
24170 -               
24171 -               key_len = value - key;
24172 -               
24173 -               value++;
24174 -               /* strip WS */
24175 -               while (*value == ' ' || *value == '\t') value++;
24176 -               
24177 -               if (host->mode != FCGI_AUTHORIZER ||
24178 -                   !(con->http_status == 0 ||
24179 -                     con->http_status == 200)) {
24180 -                       /* authorizers shouldn't affect the response headers sent back to the client */
24181 -                       
24182 -                       /* don't forward Status: */
24183 -                       if (0 != strncasecmp(key, "Status", key_len)) {
24184 -                               if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
24185 -                                       ds = data_response_init();
24186 -                               }
24187 -                               buffer_copy_string_len(ds->key, key, key_len);
24188 -                               buffer_copy_string(ds->value, value);
24189 -                               
24190 -                               array_insert_unique(con->response.headers, (data_unset *)ds);
24191 -                       }
24192 -               }
24193 -               
24194 -               switch(key_len) {
24195 -               case 4:
24196 -                       if (0 == strncasecmp(key, "Date", key_len)) {
24197 -                               con->parsed_response |= HTTP_DATE;
24198 -                       }
24199 -                       break;
24200 -               case 6:
24201 -                       if (0 == strncasecmp(key, "Status", key_len)) {
24202 -                               con->http_status = strtol(value, NULL, 10);
24203 -                               con->parsed_response |= HTTP_STATUS;
24204 -                       }
24205 -                       break;
24206 -               case 8:
24207 -                       if (0 == strncasecmp(key, "Location", key_len)) {
24208 -                               con->parsed_response |= HTTP_LOCATION;
24209 -                       }
24210 -                       break;
24211 -               case 10:
24212 -                       if (0 == strncasecmp(key, "Connection", key_len)) {
24213 -                               con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
24214 -                               con->parsed_response |= HTTP_CONNECTION;
24215 -                       }
24216 -                       break;
24217 -               case 14:
24218 -                       if (0 == strncasecmp(key, "Content-Length", key_len)) {
24219 -                               con->response.content_length = strtol(value, NULL, 10);
24220 -                               con->parsed_response |= HTTP_CONTENT_LENGTH;
24221 -                               
24222 -                               if (con->response.content_length < 0) con->response.content_length = 0;
24223 -                       }
24224 -                       break;
24225 -               default:
24226 -                       break;
24227 -               }
24228 -       }
24229 -       
24230 -       /* CGI/1.1 rev 03 - 7.2.1.2 */
24231 -       if ((con->parsed_response & HTTP_LOCATION) &&
24232 -           !(con->parsed_response & HTTP_STATUS)) {
24233 -               con->http_status = 302;
24234 -       }
24235 -       
24236         return 0;
24237  }
24238  
24239  typedef struct {
24240 -       buffer  *b; 
24241 +       buffer  *b;
24242         size_t   len;
24243         int      type;
24244         int      padding;
24245 @@ -2327,9 +2225,9 @@
24246                 return -1;
24247         }
24248  
24249 -       /* we have at least a header, now check how much me have to fetch */ 
24250 +       /* we have at least a header, now check how much me have to fetch */
24251         header = (FCGI_Header *)(packet->b->ptr);
24252 -                       
24253 +
24254         packet->len = (header->contentLengthB0 | (header->contentLengthB1 << 8)) + header->paddingLength;
24255         packet->request_id = (header->requestIdB0 | (header->requestIdB1 << 8));
24256         packet->type = header->type;
24257 @@ -2348,7 +2246,7 @@
24258                         size_t weHave = c->mem->used - c->offset - offset - 1;
24259  
24260                         if (weHave > weWant) weHave = weWant;
24261 -                                               
24262 +
24263                         buffer_append_string_len(packet->b, c->mem->ptr + c->offset + offset, weHave);
24264  
24265                         /* we only skipped the first 8 bytes as they are the fcgi header */
24266 @@ -2380,65 +2278,42 @@
24267         }
24268  
24269         chunkqueue_remove_finished_chunks(hctx->rb);
24270 -       
24271 +
24272         return 0;
24273  }
24274  
24275  static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
24276         int fin = 0;
24277 -       int toread;
24278 -       ssize_t r;
24279 -       
24280 +
24281         plugin_data *p    = hctx->plugin_data;
24282         connection *con   = hctx->remote_conn;
24283 -       int fcgi_fd       = hctx->fd;
24284         fcgi_extension_host *host= hctx->host;
24285         fcgi_proc *proc   = hctx->proc;
24286 -       
24287 -       /* 
24288 -        * check how much we have to read 
24289 -        */
24290 -       if (ioctl(hctx->fd, FIONREAD, &toread)) {
24291 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
24292 -                               "unexpected end-of-file (perhaps the fastcgi process died):",
24293 -                               fcgi_fd);
24294 -               return -1;
24295 -       }
24296 -       
24297 -       /* init read-buffer */
24298 -       
24299 -       if (toread > 0) {
24300 -               buffer *b;
24301 -
24302 -               b = chunkqueue_get_append_buffer(hctx->rb);
24303 -               buffer_prepare_copy(b, toread + 1);
24304 -
24305 -               /* append to read-buffer */
24306 -               if (-1 == (r = read(hctx->fd, b->ptr, toread))) {
24307 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
24308 -                                       "unexpected end-of-file (perhaps the fastcgi process died):",
24309 -                                       fcgi_fd, strerror(errno));
24310 -                       return -1;
24311 -               }
24312 -               
24313 -               /* this should be catched by the b > 0 above */
24314 -               assert(r);
24315 +       handler_t ret;
24316  
24317 -               b->used = r + 1; /* one extra for the fake \0 */
24318 -               b->ptr[b->used - 1] = '\0';
24319 -       } else {
24320 -               log_error_write(srv, __FILE__, __LINE__, "ssdsb", 
24321 -                               "unexpected end-of-file (perhaps the fastcgi process died):",
24322 -                               "pid:", proc->pid,
24323 -                               "socket:", proc->connection_name);
24324 -               
24325 +       /* in case we read nothing, check the return code
24326 +        * if we got something, be happy :)
24327 +        *
24328 +        * Ok, to be honest:
24329 +        * - it is fine to receive a EAGAIN on a second read() call
24330 +        * - it might be fine they we get a con-close on a second read() call */
24331 +       switch(srv->network_backend_read(srv, con, hctx->sock, hctx->rb)) {
24332 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
24333 +               /* a EAGAIN after we read exactly the chunk-size */
24334 +
24335 +               ERROR("%s", "oops, got a EAGAIN even if we just got call for the event, wired");
24336 +               return -1;
24337 +       case NETWORK_STATUS_SUCCESS:
24338 +               break;
24339 +       default:
24340 +               ERROR("reading from fastcgi socket failed (fd=%d)", hctx->sock->fd);
24341                 return -1;
24342         }
24343  
24344         /*
24345          * parse the fastcgi packets and forward the content to the write-queue
24346          *
24347 -        */     
24348 +        */
24349         while (fin == 0) {
24350                 fastcgi_response_packet packet;
24351  
24352 @@ -2454,92 +2329,136 @@
24353  
24354                         /* is the header already finished */
24355                         if (0 == con->file_started) {
24356 -                               char *c;
24357 -                               size_t blen;
24358 -                               data_string *ds;
24359 -                                       
24360 -                               /* search for header terminator 
24361 -                                * 
24362 -                                * if we start with \r\n check if last packet terminated with \r\n
24363 -                                * if we start with \n check if last packet terminated with \n
24364 -                                * search for \r\n\r\n
24365 -                                * search for \n\n
24366 -                                */
24367 -
24368 -                               if (hctx->response_header->used == 0) {
24369 -                                       buffer_copy_string_buffer(hctx->response_header, packet.b);
24370 -                               } else {
24371 -                                       buffer_append_string_buffer(hctx->response_header, packet.b);
24372 -                               }
24373 -
24374 -                               if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\r\n\r\n")))) {
24375 -                                       blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 4;
24376 -                                       hctx->response_header->used = (c - hctx->response_header->ptr) + 3;
24377 -                                       c += 4; /* point the the start of the response */
24378 -                               } else if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\n\n")))) {
24379 -                                       blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 2;
24380 -                                       hctx->response_header->used = c - hctx->response_header->ptr + 2;
24381 -                                       c += 2; /* point the the start of the response */
24382 -                               } else {
24383 -                                       /* no luck, no header found */
24384 +                               int have_content_length = 0;
24385 +                               int need_more = 0;
24386 +                               size_t i;
24387 +
24388 +                               /* append the current packet to the chunk queue */
24389 +                               chunkqueue_append_buffer(hctx->http_rb, packet.b);
24390 +                               http_response_reset(p->resp);
24391 +
24392 +                               switch(http_response_parse_cq(hctx->http_rb, p->resp)) {
24393 +                               case PARSE_ERROR:
24394 +                                       /* parsing the response header failed */
24395 +
24396 +                                       con->http_status = 502; /* Bad Gateway */
24397 +
24398 +                                       return 1;
24399 +                               case PARSE_NEED_MORE:
24400 +                                       need_more = 1;
24401 +                                       break; /* leave the loop */
24402 +                               case PARSE_SUCCESS:
24403                                         break;
24404 +                               default:
24405 +                                       /* should not happen */
24406 +                                       SEGFAULT();
24407                                 }
24408  
24409 -                               /* parse the response header */
24410 -                               fcgi_response_parse(srv, con, p, hctx->response_header);
24411 +                               if (need_more) break;
24412  
24413 -                               con->file_started = 1;
24414 +                               chunkqueue_remove_finished_chunks(hctx->http_rb);
24415 +
24416 +                               con->http_status = p->resp->status;
24417 +                               hctx->send_content_body = 1;
24418  
24419 -                               if (host->mode == FCGI_AUTHORIZER &&
24420 -                                   (con->http_status == 0 ||
24421 -                                    con->http_status == 200)) {
24422 -                                       /* a authorizer with approved the static request, ignore the content here */
24423 -                                       hctx->send_content_body = 0;
24424 -                               }
24425 -
24426 -                               if (host->allow_xsendfile &&
24427 -                                   NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-LIGHTTPD-send-file"))) {
24428 -                                       stat_cache_entry *sce;
24429 -
24430 -                                       if (HANDLER_ERROR != stat_cache_get_entry(srv, con, ds->value, &sce)) {
24431 -                                               /* found */
24432 -
24433 -                                               http_chunk_append_file(srv, con, ds->value, 0, sce->st.st_size);
24434 -                                               hctx->send_content_body = 0; /* ignore the content */
24435 -                                               joblist_append(srv, con);
24436 +                               /* handle the header fields */
24437 +                               if (host->mode == FCGI_AUTHORIZER) {
24438 +                                       /* auth mode is a bit different */
24439 +
24440 +                                       if (con->http_status == 0 ||
24441 +                                           con->http_status == 200) {
24442 +                                               /* a authorizer with approved the static request, ignore the content here */
24443 +                                               hctx->send_content_body = 0;
24444                                         }
24445                                 }
24446  
24447 +                               /* copy the http-headers */
24448 +                               for (i = 0; i < p->resp->headers->used; i++) {
24449 +                                       const char *ign[] = { "Status", NULL };
24450 +                                       size_t j;
24451 +                                       data_string *ds;
24452 +
24453 +                                       data_string *header = (data_string *)p->resp->headers->data[i];
24454 +
24455 +                                       /* ignore all headers in AUTHORIZER mode */
24456 +                                       if (host->mode == FCGI_AUTHORIZER) continue;
24457 +
24458 +                                       /* some headers are ignored by default */
24459 +                                       for (j = 0; ign[j]; j++) {
24460 +                                               if (0 == strcasecmp(ign[j], header->key->ptr)) break;
24461 +                                       }
24462 +                                       if (ign[j]) continue;
24463 +
24464 +                                       if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
24465 +                                               /* CGI/1.1 rev 03 - 7.2.1.2 */
24466 +                                               con->http_status = 302;
24467 +                                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
24468 +                                               have_content_length = 1;
24469 +                                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-Sendfile")) || 
24470 +                                                  0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-LIGHTTPD-send-file"))) {
24471 +                                               
24472 +                                               stat_cache_entry *sce;
24473                                                 
24474 -                               if (hctx->send_content_body && blen > 1) {                                              
24475 -                                       /* enable chunked-transfer-encoding */
24476 +                                               if (host->allow_xsendfile &&
24477 +                                                   HANDLER_ERROR != stat_cache_get_entry(srv, con, header->value, &sce)) {
24478 +                                                       http_chunk_append_file(srv, con, header->value, 0, sce->st.st_size);
24479 +                                                       hctx->send_content_body = 0; /* ignore the content */
24480 +                                       
24481 +                                                       joblist_append(srv, con);
24482 +                                               }
24483 +
24484 +                                               continue; /* ignore header */
24485 +                                       }
24486 +                                       
24487 +                                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
24488 +                                               ds = data_response_init();
24489 +                                       }
24490 +                                       buffer_copy_string_buffer(ds->key, header->key);
24491 +                                       buffer_copy_string_buffer(ds->value, header->value);
24492 +
24493 +                                       array_insert_unique(con->response.headers, (data_unset *)ds);
24494 +                               }
24495 +
24496 +                               /* header is complete ... go on with the body */
24497 +
24498 +                               con->file_started = 1;
24499 +
24500 +                               if (hctx->send_content_body) {
24501 +                                       chunk *c = hctx->http_rb->first;
24502 +
24503 +                                       /* if we don't have a content-length enable chunked encoding 
24504 +                                        * if possible
24505 +                                        * 
24506 +                                        * TODO: move this to a later stage in the filter-queue
24507 +                                        *  */
24508                                         if (con->request.http_version == HTTP_VERSION_1_1 &&
24509 -                                           !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
24510 +                                           !have_content_length) {
24511                                                 con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
24512                                         }
24513  
24514 -                                       http_chunk_append_mem(srv, con, c, blen);
24515 +                                       /* copy the rest of the data */
24516 +                                       for (c = hctx->http_rb->first; c; c = c->next) {
24517 +                                               if (c->mem->used > 1) {
24518 +                                                       http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
24519 +                                                       c->offset = c->mem->used - 1;
24520 +                                               }
24521 +                                       }
24522 +                                       chunkqueue_remove_finished_chunks(hctx->http_rb);
24523                                         joblist_append(srv, con);
24524                                 }
24525                         } else if (hctx->send_content_body && packet.b->used > 1) {
24526 -                               if (con->request.http_version == HTTP_VERSION_1_1 &&
24527 -                                   !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
24528 -                                       /* enable chunked-transfer-encoding */
24529 -                                       con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
24530 -                               }
24531 -
24532                                 http_chunk_append_mem(srv, con, packet.b->ptr, packet.b->used);
24533                                 joblist_append(srv, con);
24534                         }
24535                         break;
24536                 case FCGI_STDERR:
24537 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
24538 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
24539                                         "FastCGI-stderr:", packet.b);
24540 -                       
24541 +
24542                         break;
24543                 case FCGI_END_REQUEST:
24544                         con->file_finished = 1;
24545 -                       
24546 +
24547                         if (host->mode != FCGI_AUTHORIZER ||
24548                             !(con->http_status == 0 ||
24549                               con->http_status == 200)) {
24550 @@ -2547,39 +2466,39 @@
24551                                 http_chunk_append_mem(srv, con, NULL, 0);
24552                                 joblist_append(srv, con);
24553                         }
24554 -                       
24555 +
24556                         fin = 1;
24557                         break;
24558                 default:
24559 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
24560 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
24561                                         "FastCGI: header.type not handled: ", packet.type);
24562                         break;
24563                 }
24564                 buffer_free(packet.b);
24565         }
24566 -       
24567 +
24568         return fin;
24569  }
24570  
24571  static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_host *host) {
24572         fcgi_proc *proc;
24573 -       
24574 +
24575         for (proc = host->first; proc; proc = proc->next) {
24576                 int status;
24577  
24578                 if (p->conf.debug > 2) {
24579 -                       log_error_write(srv, __FILE__, __LINE__,  "sbdddd", 
24580 -                                       "proc:", 
24581 +                       log_error_write(srv, __FILE__, __LINE__,  "sbdddd",
24582 +                                       "proc:",
24583                                         proc->connection_name,
24584                                         proc->state,
24585                                         proc->is_local,
24586                                         proc->load,
24587                                         proc->pid);
24588                 }
24589 -               
24590 -               /* 
24591 +
24592 +               /*
24593                  * if the remote side is overloaded, we check back after <n> seconds
24594 -                * 
24595 +                *
24596                  */
24597                 switch (proc->state) {
24598                 case PROC_STATE_KILLED:
24599 @@ -2592,13 +2511,13 @@
24600                         break;
24601                 case PROC_STATE_OVERLOADED:
24602                         if (srv->cur_ts <= proc->disabled_until) break;
24603 -                       
24604 +
24605                         proc->state = PROC_STATE_RUNNING;
24606                         host->active_procs++;
24607 -                       
24608 -                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", 
24609 -                                       "fcgi-server re-enabled:", 
24610 -                                       host->host, host->port, 
24611 +
24612 +                       log_error_write(srv, __FILE__, __LINE__,  "sbdb",
24613 +                                       "fcgi-server re-enabled:",
24614 +                                       host->host, host->port,
24615                                         host->unixsocket);
24616                         break;
24617                 case PROC_STATE_DIED_WAIT_FOR_PID:
24618 @@ -2606,7 +2525,7 @@
24619                         if (!proc->is_local) break;
24620  
24621                         /* the child should not terminate at all */
24622 -                       
24623 +#ifndef _WIN32
24624                         switch(waitpid(proc->pid, &status, WNOHANG)) {
24625                         case 0:
24626                                 /* child is still alive */
24627 @@ -2616,45 +2535,45 @@
24628                         default:
24629                                 if (WIFEXITED(status)) {
24630  #if 0
24631 -                                       log_error_write(srv, __FILE__, __LINE__, "sdsd", 
24632 +                                       log_error_write(srv, __FILE__, __LINE__, "sdsd",
24633                                                         "child exited, pid:", proc->pid,
24634                                                         "status:", WEXITSTATUS(status));
24635  #endif
24636                                 } else if (WIFSIGNALED(status)) {
24637 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
24638 -                                                       "child signaled:", 
24639 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
24640 +                                                       "child signaled:",
24641                                                         WTERMSIG(status));
24642                                 } else {
24643 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
24644 -                                                       "child died somehow:", 
24645 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
24646 +                                                       "child died somehow:",
24647                                                         status);
24648                                 }
24649 -                               
24650 +
24651                                 proc->state = PROC_STATE_DIED;
24652                                 break;
24653                         }
24654 -
24655 +#endif
24656                         /* fall through if we have a dead proc now */
24657                         if (proc->state != PROC_STATE_DIED) break;
24658  
24659                 case PROC_STATE_DIED:
24660 -                       /* local proc get restarted by us, 
24661 +                       /* local proc get restarted by us,
24662                          * remote ones hopefully by the admin */
24663 -                       
24664 +
24665                         if (proc->is_local) {
24666                                 /* we still have connections bound to this proc,
24667                                  * let them terminate first */
24668                                 if (proc->load != 0) break;
24669 -                       
24670 +
24671                                 /* restart the child */
24672 -                               
24673 +
24674                                 if (p->conf.debug) {
24675                                         log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
24676                                                         "--- fastcgi spawning",
24677                                                         "\n\tsocket", proc->connection_name,
24678                                                         "\n\tcurrent:", 1, "/", host->min_procs);
24679                                 }
24680 -                               
24681 +
24682                                 if (fcgi_spawn_connection(srv, p, host, proc)) {
24683                                         log_error_write(srv, __FILE__, __LINE__, "s",
24684                                                         "ERROR: spawning fcgi failed.");
24685 @@ -2662,18 +2581,18 @@
24686                                 }
24687                         } else {
24688                                 if (srv->cur_ts <= proc->disabled_until) break;
24689 -                       
24690 +
24691                                 proc->state = PROC_STATE_RUNNING;
24692                                 host->active_procs++;
24693 -                       
24694 -                               log_error_write(srv, __FILE__, __LINE__,  "sb", 
24695 -                                               "fcgi-server re-enabled:", 
24696 +
24697 +                               log_error_write(srv, __FILE__, __LINE__,  "sb",
24698 +                                               "fcgi-server re-enabled:",
24699                                                 proc->connection_name);
24700                         }
24701                         break;
24702                 }
24703         }
24704 -       
24705 +
24706         return 0;
24707  }
24708  
24709 @@ -2682,19 +2601,19 @@
24710         fcgi_extension_host *host= hctx->host;
24711         connection *con   = hctx->remote_conn;
24712         fcgi_proc  *proc;
24713 -       
24714 +
24715         int ret;
24716  
24717 -       /* sanity check */      
24718 +       /* sanity check */
24719         if (!host ||
24720             ((!host->host->used || !host->port) && !host->unixsocket->used)) {
24721 -               log_error_write(srv, __FILE__, __LINE__, "sxddd", 
24722 +               log_error_write(srv, __FILE__, __LINE__, "sxddd",
24723                                 "write-req: error",
24724                                 host,
24725                                 host->host->used,
24726                                 host->port,
24727                                 host->unixsocket->used);
24728 -                       
24729 +
24730                 hctx->proc->disabled_until = srv->cur_ts + 10;
24731                 hctx->proc->state = PROC_STATE_DIED;
24732  
24733 @@ -2705,12 +2624,12 @@
24734         if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
24735                 int socket_error;
24736                 socklen_t socket_error_len = sizeof(socket_error);
24737 -                       
24738 +
24739                 /* try to finish the connect() */
24740 -               if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
24741 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
24742 +               if (0 != getsockopt(hctx->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
24743 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
24744                                         "getsockopt failed:", strerror(errno));
24745 -                       
24746 +
24747                         hctx->proc->disabled_until = srv->cur_ts + 10;
24748                         hctx->proc->state = PROC_STATE_DIED;
24749  
24750 @@ -2719,12 +2638,12 @@
24751                 if (socket_error != 0) {
24752                         if (!hctx->proc->is_local || p->conf.debug) {
24753                                 /* local procs get restarted */
24754 -                               
24755 +
24756                                 log_error_write(srv, __FILE__, __LINE__, "sssb",
24757 -                                               "establishing connection failed:", strerror(socket_error), 
24758 +                                               "establishing connection failed:", strerror(socket_error),
24759                                                 "socket:", hctx->proc->connection_name);
24760                         }
24761 -       
24762 +
24763                         hctx->proc->disabled_until = srv->cur_ts + 5;
24764  
24765                         if (hctx->proc->is_local) {
24766 @@ -2732,17 +2651,17 @@
24767                         } else {
24768                                 hctx->proc->state = PROC_STATE_DIED;
24769                         }
24770 -       
24771 +
24772                         hctx->proc->state = PROC_STATE_DIED;
24773 -               
24774 +
24775                         fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
24776                         buffer_append_string(p->statuskey, ".died");
24777  
24778                         status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
24779 -               
24780 +
24781                         return HANDLER_ERROR;
24782                 }
24783 -               /* go on with preparing the request */ 
24784 +               /* go on with preparing the request */
24785                 hctx->state = FCGI_STATE_PREPARE_WRITE;
24786         }
24787  
24788 @@ -2755,14 +2674,14 @@
24789                 /* do we have a running process for this host (max-procs) ? */
24790                 hctx->proc = NULL;
24791  
24792 -               for (proc = hctx->host->first; 
24793 -                    proc && proc->state != PROC_STATE_RUNNING; 
24794 +               for (proc = hctx->host->first;
24795 +                    proc && proc->state != PROC_STATE_RUNNING;
24796                      proc = proc->next);
24797 -                       
24798 +
24799                 /* all childs are dead */
24800                 if (proc == NULL) {
24801 -                       hctx->fde_ndx = -1;
24802 -               
24803 +                       hctx->sock->fde_ndx = -1;
24804 +
24805                         return HANDLER_ERROR;
24806                 }
24807  
24808 @@ -2775,50 +2694,50 @@
24809                 }
24810  
24811                 ret = host->unixsocket->used ? AF_UNIX : AF_INET;
24812 -               
24813 -               if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
24814 +
24815 +               if (-1 == (hctx->sock->fd = socket(ret, SOCK_STREAM, 0))) {
24816                         if (errno == EMFILE ||
24817                             errno == EINTR) {
24818 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
24819 -                                               "wait for fd at connection:", con->fd);
24820 -                               
24821 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
24822 +                                               "wait for fd at connection:", con->sock->fd);
24823 +
24824                                 return HANDLER_WAIT_FOR_FD;
24825                         }
24826 -                       
24827 -                       log_error_write(srv, __FILE__, __LINE__, "ssdd", 
24828 +
24829 +                       log_error_write(srv, __FILE__, __LINE__, "ssdd",
24830                                         "socket failed:", strerror(errno), srv->cur_fds, srv->max_fds);
24831                         return HANDLER_ERROR;
24832                 }
24833 -               hctx->fde_ndx = -1;
24834 -               
24835 +               hctx->sock->fde_ndx = -1;
24836 +
24837                 srv->cur_fds++;
24838 -               
24839 -               fdevent_register(srv->ev, hctx->fd, fcgi_handle_fdevent, hctx);
24840 -               
24841 -               if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
24842 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
24843 +
24844 +               fdevent_register(srv->ev, hctx->sock, fcgi_handle_fdevent, hctx);
24845 +
24846 +               if (-1 == fdevent_fcntl_set(srv->ev, hctx->sock)) {
24847 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
24848                                         "fcntl failed:", strerror(errno));
24849 -                       
24850 +
24851                         return HANDLER_ERROR;
24852                 }
24853 -                       
24854 +
24855                 if (hctx->proc->is_local) {
24856                         hctx->pid = hctx->proc->pid;
24857                 }
24858 -                       
24859 +
24860                 switch (fcgi_establish_connection(srv, hctx)) {
24861                 case CONNECTION_DELAYED:
24862                         /* connection is in progress, wait for an event and call getsockopt() below */
24863 -                       
24864 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
24865 -                       
24866 +
24867 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
24868 +
24869                         fcgi_set_state(srv, hctx, FCGI_STATE_CONNECT_DELAYED);
24870                         return HANDLER_WAIT_FOR_EVENT;
24871                 case CONNECTION_OVERLOADED:
24872                         /* cool down the backend, it is overloaded
24873                          * -> EAGAIN */
24874  
24875 -                       log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
24876 +                       log_error_write(srv, __FILE__, __LINE__, "ssdsd",
24877                                 "backend is overloaded, we disable it for a 2 seconds and send the request to another backend instead:",
24878                                 "reconnects:", hctx->reconnects,
24879                                 "load:", host->load);
24880 @@ -2831,7 +2750,7 @@
24881                         buffer_append_string(p->statuskey, ".overloaded");
24882  
24883                         status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
24884 -                       
24885 +
24886                         return HANDLER_ERROR;
24887                 case CONNECTION_DEAD:
24888                         /* we got a hard error from the backend like
24889 @@ -2840,19 +2759,19 @@
24890                          *
24891                          * for check if the host is back in 5 seconds
24892                          *  */
24893 -                       
24894 +
24895                         hctx->proc->disabled_until = srv->cur_ts + 5;
24896                         if (hctx->proc->is_local) {
24897                                 hctx->proc->state = PROC_STATE_DIED_WAIT_FOR_PID;
24898                         } else {
24899                                 hctx->proc->state = PROC_STATE_DIED;
24900                         }
24901 -       
24902 -                       log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
24903 +
24904 +                       log_error_write(srv, __FILE__, __LINE__, "ssdsd",
24905                                 "backend died, we disable it for a 5 seconds and send the request to another backend instead:",
24906                                 "reconnects:", hctx->reconnects,
24907                                 "load:", host->load);
24908 -       
24909 +
24910                         fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
24911                         buffer_append_string(p->statuskey, ".died");
24912  
24913 @@ -2863,19 +2782,19 @@
24914                         /* everything is ok, go on */
24915  
24916                         fcgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
24917 -                       
24918 +
24919                         break;
24920                 case CONNECTION_UNSET:
24921                         break;
24922                 }
24923 -               
24924 +
24925         case FCGI_STATE_PREPARE_WRITE:
24926                 /* ok, we have the connection */
24927 -               
24928 +
24929                 hctx->proc->load++;
24930                 hctx->proc->last_used = srv->cur_ts;
24931                 hctx->got_proc = 1;
24932 -       
24933 +
24934                 status_counter_inc(srv, CONST_STR_LEN("fastcgi.requests"));
24935                 status_counter_inc(srv, CONST_STR_LEN("fastcgi.active-requests"));
24936  
24937 @@ -2898,9 +2817,9 @@
24938  
24939                 if (p->conf.debug) {
24940                         log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
24941 -                                       "got proc:", 
24942 -                                       "pid:", hctx->proc->pid, 
24943 -                                       "socket:", hctx->proc->connection_name, 
24944 +                                       "got proc:",
24945 +                                       "pid:", hctx->proc->pid,
24946 +                                       "socket:", hctx->proc->connection_name,
24947                                         "load:", hctx->proc->load);
24948                 }
24949  
24950 @@ -2908,74 +2827,75 @@
24951                 if (hctx->request_id == 0) {
24952                         hctx->request_id = fcgi_requestid_new(srv, p);
24953                 } else {
24954 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
24955 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
24956                                         "fcgi-request is already in use:", hctx->request_id);
24957                 }
24958 -               
24959 +
24960                 /* fall through */
24961                 fcgi_create_env(srv, hctx, hctx->request_id);
24962 -               
24963 +
24964                 fcgi_set_state(srv, hctx, FCGI_STATE_WRITE);
24965 -               
24966 +
24967                 /* fall through */
24968         case FCGI_STATE_WRITE:
24969 -               ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); 
24970 +               ret = srv->network_backend_write(srv, con, hctx->sock, hctx->wb);
24971  
24972                 chunkqueue_remove_finished_chunks(hctx->wb);
24973 -               
24974 +
24975                 if (ret < 0) {
24976                         switch(errno) {
24977                         case ENOTCONN:
24978 -                               /* the connection got dropped after accept() 
24979 -                                * 
24980 -                                * this is most of the time a PHP which dies 
24981 +                               /* the connection got dropped after accept()
24982 +                                *
24983 +                                * this is most of the time a PHP which dies
24984                                  * after PHP_FCGI_MAX_REQUESTS
24985 -                                * 
24986 -                                */ 
24987 +                                *
24988 +                                */
24989                                 if (hctx->wb->bytes_out == 0 &&
24990                                     hctx->reconnects < 5) {
24991 -                                       usleep(10000); /* take away the load of the webserver 
24992 -                                                       * to let the php a chance to restart 
24993 +#ifndef _WIN32
24994 +                                       usleep(10000); /* take away the load of the webserver
24995 +                                                       * to let the php a chance to restart
24996                                                         */
24997 -                                       
24998 +#endif
24999                                         fcgi_reconnect(srv, hctx);
25000 -                               
25001 +
25002                                         return HANDLER_WAIT_FOR_FD;
25003                                 }
25004 -                               
25005 +
25006                                 /* not reconnected ... why
25007 -                                * 
25008 +                                *
25009                                  * far@#lighttpd report this for FreeBSD
25010 -                                * 
25011 +                                *
25012                                  */
25013 -                               
25014 -                               log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
25015 +
25016 +                               log_error_write(srv, __FILE__, __LINE__, "ssosd",
25017                                                 "[REPORT ME] connection was dropped after accept(). reconnect() denied:",
25018                                                 "write-offset:", hctx->wb->bytes_out,
25019                                                 "reconnect attempts:", hctx->reconnects);
25020 -                               
25021 +
25022                                 return HANDLER_ERROR;
25023                         case EAGAIN:
25024                         case EINTR:
25025 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
25026 -                               
25027 +                               fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
25028 +
25029                                 return HANDLER_WAIT_FOR_EVENT;
25030                         default:
25031 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", 
25032 +                               log_error_write(srv, __FILE__, __LINE__, "ssd",
25033                                                 "write failed:", strerror(errno), errno);
25034 -                               
25035 +
25036                                 return HANDLER_ERROR;
25037                         }
25038                 }
25039  
25040                 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
25041                         /* we don't need the out event anymore */
25042 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
25043 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
25044 +                       fdevent_event_del(srv->ev, hctx->sock);
25045 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
25046                         fcgi_set_state(srv, hctx, FCGI_STATE_READ);
25047                 } else {
25048 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
25049 -                               
25050 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
25051 +
25052                         return HANDLER_WAIT_FOR_EVENT;
25053                 }
25054  
25055 @@ -2987,7 +2907,7 @@
25056                 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
25057                 return HANDLER_ERROR;
25058         }
25059 -       
25060 +
25061         return HANDLER_WAIT_FOR_EVENT;
25062  }
25063  
25064 @@ -2996,18 +2916,18 @@
25065   * */
25066  SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
25067         plugin_data *p = p_d;
25068 -       
25069 +
25070         handler_ctx *hctx = con->plugin_ctx[p->id];
25071         fcgi_proc *proc;
25072         fcgi_extension_host *host;
25073 -       
25074 +
25075         if (NULL == hctx) return HANDLER_GO_ON;
25076 -       
25077 +
25078         /* not my job */
25079         if (con->mode != p->id) return HANDLER_GO_ON;
25080  
25081         /* we don't have a host yet, choose one
25082 -        * -> this happens in the first round 
25083 +        * -> this happens in the first round
25084          *    and when the host died and we have to select a new one */
25085         if (hctx->host == NULL) {
25086                 size_t k;
25087 @@ -3016,23 +2936,23 @@
25088                 /* get best server */
25089                 for (k = 0, ndx = -1; k < hctx->ext->used; k++) {
25090                         host = hctx->ext->hosts[k];
25091 -               
25092 +
25093                         /* we should have at least one proc that can do something */
25094                         if (host->active_procs == 0) continue;
25095  
25096                         if (used == -1 || host->load < used) {
25097                                 used = host->load;
25098 -                       
25099 +
25100                                 ndx = k;
25101                         }
25102                 }
25103 -       
25104 +
25105                 /* found a server */
25106                 if (ndx == -1) {
25107                         /* all hosts are down */
25108  
25109                         fcgi_connection_close(srv, hctx);
25110 -                       
25111 +
25112                         con->http_status = 500;
25113                         con->mode = DIRECT;
25114  
25115 @@ -3040,16 +2960,16 @@
25116                 }
25117  
25118                 host = hctx->ext->hosts[ndx];
25119 -               
25120 -               /* 
25121 -                * if check-local is disabled, use the uri.path handler 
25122 -                * 
25123 +
25124 +               /*
25125 +                * if check-local is disabled, use the uri.path handler
25126 +                *
25127                  */
25128 -               
25129 +
25130                 /* init handler-context */
25131                 hctx->host = host;
25132  
25133 -               /* we put a connection on this host, move the other new connections to other hosts 
25134 +               /* we put a connection on this host, move the other new connections to other hosts
25135                  *
25136                  * as soon as hctx->host is unassigned, decrease the load again */
25137                 hctx->host->load++;
25138 @@ -3063,7 +2983,7 @@
25139         case HANDLER_ERROR:
25140                 proc = hctx->proc;
25141                 host = hctx->host;
25142 -               
25143 +
25144                 if (hctx->state == FCGI_STATE_INIT ||
25145                     hctx->state == FCGI_STATE_CONNECT_DELAYED) {
25146                         if (proc) host->active_procs--;
25147 @@ -3078,7 +2998,7 @@
25148                                 return HANDLER_WAIT_FOR_FD;
25149                         } else {
25150                                 fcgi_connection_close(srv, hctx);
25151 -                       
25152 +
25153                                 buffer_reset(con->physical.path);
25154                                 con->mode = DIRECT;
25155                                 con->http_status = 500;
25156 @@ -3088,12 +3008,12 @@
25157                         }
25158                 } else {
25159                         fcgi_connection_close(srv, hctx);
25160 -                       
25161 +
25162                         buffer_reset(con->physical.path);
25163                         con->mode = DIRECT;
25164                         con->http_status = 503;
25165                         joblist_append(srv, con); /* really ? */
25166 -                       
25167 +
25168                         return HANDLER_FINISHED;
25169                 }
25170         case HANDLER_WAIT_FOR_EVENT:
25171 @@ -3115,7 +3035,7 @@
25172         handler_ctx *hctx = ctx;
25173         connection  *con  = hctx->remote_conn;
25174         plugin_data *p    = hctx->plugin_data;
25175 -       
25176 +
25177         fcgi_proc *proc   = hctx->proc;
25178         fcgi_extension_host *host= hctx->host;
25179  
25180 @@ -3125,8 +3045,8 @@
25181                 case 0:
25182                         break;
25183                 case 1:
25184 -                       
25185 -                       if (host->mode == FCGI_AUTHORIZER && 
25186 +
25187 +                       if (host->mode == FCGI_AUTHORIZER &&
25188                             (con->http_status == 200 ||
25189                              con->http_status == 0)) {
25190                                 /*
25191 @@ -3136,26 +3056,26 @@
25192                                  */
25193  
25194                                 buffer_copy_string_buffer(con->physical.doc_root, host->docroot);
25195 -                               
25196 +
25197                                 buffer_copy_string_buffer(con->physical.path, host->docroot);
25198                                 buffer_append_string_buffer(con->physical.path, con->uri.path);
25199                                 fcgi_connection_close(srv, hctx);
25200 -                               
25201 +
25202                                 con->mode = DIRECT;
25203                                 con->file_started = 1; /* fcgi_extension won't touch the request afterwards */
25204                         } else {
25205                                 /* we are done */
25206                                 fcgi_connection_close(srv, hctx);
25207                         }
25208 -                       
25209 +
25210                         joblist_append(srv, con);
25211                         return HANDLER_FINISHED;
25212                 case -1:
25213                         if (proc->pid && proc->state != PROC_STATE_DIED) {
25214                                 int status;
25215 -                               
25216 +
25217                                 /* only fetch the zombie if it is not already done */
25218 -                               
25219 +#ifndef _WIN32
25220                                 switch(waitpid(proc->pid, &status, WNOHANG)) {
25221                                 case 0:
25222                                         /* child is still alive */
25223 @@ -3165,60 +3085,61 @@
25224                                 default:
25225                                         /* the child should not terminate at all */
25226                                         if (WIFEXITED(status)) {
25227 -                                               log_error_write(srv, __FILE__, __LINE__, "sdsd", 
25228 +                                               log_error_write(srv, __FILE__, __LINE__, "sdsd",
25229                                                                 "child exited, pid:", proc->pid,
25230                                                                 "status:", WEXITSTATUS(status));
25231                                         } else if (WIFSIGNALED(status)) {
25232 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
25233 -                                                               "child signaled:", 
25234 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
25235 +                                                               "child signaled:",
25236                                                                 WTERMSIG(status));
25237                                         } else {
25238 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
25239 -                                                               "child died somehow:", 
25240 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
25241 +                                                               "child died somehow:",
25242                                                                 status);
25243                                         }
25244 -                                       
25245 +
25246                                         if (p->conf.debug) {
25247                                                 log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
25248                                                                 "--- fastcgi spawning",
25249                                                                 "\n\tsocket", proc->connection_name,
25250                                                                 "\n\tcurrent:", 1, "/", host->min_procs);
25251                                         }
25252 -                                       
25253 +
25254                                         if (fcgi_spawn_connection(srv, p, host, proc)) {
25255                                                 /* respawning failed, retry later */
25256                                                 proc->state = PROC_STATE_DIED;
25257  
25258 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
25259 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
25260                                                                 "respawning failed, will retry later");
25261                                         }
25262 -                                       
25263 +
25264                                         break;
25265                                 }
25266 +#endif
25267                         }
25268  
25269                         if (con->file_started == 0) {
25270                                 /* nothing has been send out yet, try to use another child */
25271 -                               
25272 +
25273                                 if (hctx->wb->bytes_out == 0 &&
25274                                     hctx->reconnects < 5) {
25275                                         fcgi_reconnect(srv, hctx);
25276 -                                       
25277 -                                       log_error_write(srv, __FILE__, __LINE__, "ssbsbs", 
25278 +
25279 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
25280                                                 "response not received, request not sent",
25281 -                                               "on socket:", proc->connection_name, 
25282 +                                               "on socket:", proc->connection_name,
25283                                                 "for", con->uri.path, ", reconnecting");
25284 -                                       
25285 +
25286                                         return HANDLER_WAIT_FOR_FD;
25287                                 }
25288 -                       
25289 -                               log_error_write(srv, __FILE__, __LINE__, "sosbsbs", 
25290 +
25291 +                               log_error_write(srv, __FILE__, __LINE__, "sosbsbs",
25292                                                 "response not received, request sent:", hctx->wb->bytes_out,
25293 -                                               "on socket:", proc->connection_name, 
25294 +                                               "on socket:", proc->connection_name,
25295                                                 "for", con->uri.path, ", closing connection");
25296 -                               
25297 +
25298                                 fcgi_connection_close(srv, hctx);
25299 -                               
25300 +
25301                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
25302                                 buffer_reset(con->physical.path);
25303                                 con->http_status = 500;
25304 @@ -3226,76 +3147,76 @@
25305                         } else {
25306                                 /* response might have been already started, kill the connection */
25307                                 fcgi_connection_close(srv, hctx);
25308 -                               
25309 -                               log_error_write(srv, __FILE__, __LINE__, "ssbsbs", 
25310 +
25311 +                               log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
25312                                                 "response already sent out, but backend returned error",
25313 -                                               "on socket:", proc->connection_name, 
25314 +                                               "on socket:", proc->connection_name,
25315                                                 "for", con->uri.path, ", terminating connection");
25316 -                               
25317 +
25318                                 connection_set_state(srv, con, CON_STATE_ERROR);
25319                         }
25320  
25321                         /* */
25322 -                       
25323 -                       
25324 +
25325 +
25326                         joblist_append(srv, con);
25327                         return HANDLER_FINISHED;
25328                 }
25329         }
25330 -       
25331 +
25332         if (revents & FDEVENT_OUT) {
25333                 if (hctx->state == FCGI_STATE_CONNECT_DELAYED ||
25334                     hctx->state == FCGI_STATE_WRITE) {
25335                         /* we are allowed to send something out
25336 -                        * 
25337 +                        *
25338                          * 1. in a unfinished connect() call
25339                          * 2. in a unfinished write() call (long POST request)
25340                          */
25341                         return mod_fastcgi_handle_subrequest(srv, con, p);
25342                 } else {
25343 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
25344 -                                       "got a FDEVENT_OUT and didn't know why:", 
25345 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
25346 +                                       "got a FDEVENT_OUT and didn't know why:",
25347                                         hctx->state);
25348                 }
25349         }
25350 -       
25351 +
25352         /* perhaps this issue is already handled */
25353         if (revents & FDEVENT_HUP) {
25354                 if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
25355                         /* getoptsock will catch this one (right ?)
25356 -                        * 
25357 -                        * if we are in connect we might get a EINPROGRESS 
25358 -                        * in the first call and a FDEVENT_HUP in the 
25359 +                        *
25360 +                        * if we are in connect we might get a EINPROGRESS
25361 +                        * in the first call and a FDEVENT_HUP in the
25362                          * second round
25363 -                        * 
25364 +                        *
25365                          * FIXME: as it is a bit ugly.
25366 -                        * 
25367 +                        *
25368                          */
25369                         return mod_fastcgi_handle_subrequest(srv, con, p);
25370                 } else if (hctx->state == FCGI_STATE_READ &&
25371                            hctx->proc->port == 0) {
25372                         /* FIXME:
25373 -                        * 
25374 +                        *
25375                          * ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket
25376                          * even if the FCGI_FIN packet is not received yet
25377                          */
25378                 } else {
25379 -                       log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd", 
25380 -                                       "error: unexpected close of fastcgi connection for", 
25381 +                       log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
25382 +                                       "error: unexpected close of fastcgi connection for",
25383                                         con->uri.path,
25384 -                                       "(no fastcgi process on host:", 
25385 +                                       "(no fastcgi process on host:",
25386                                         host->host,
25387 -                                       ", port: ", 
25388 +                                       ", port: ",
25389                                         host->port,
25390                                         " ?)",
25391                                         hctx->state);
25392 -                       
25393 +
25394                         connection_set_state(srv, con, CON_STATE_ERROR);
25395                         fcgi_connection_close(srv, hctx);
25396                         joblist_append(srv, con);
25397                 }
25398         } else if (revents & FDEVENT_ERR) {
25399 -               log_error_write(srv, __FILE__, __LINE__, "s", 
25400 +               log_error_write(srv, __FILE__, __LINE__, "s",
25401                                 "fcgi: got a FDEVENT_ERR. Don't know why.");
25402                 /* kill all connections to the fastcgi process */
25403  
25404 @@ -3304,45 +3225,42 @@
25405                 fcgi_connection_close(srv, hctx);
25406                 joblist_append(srv, con);
25407         }
25408 -       
25409 +
25410         return HANDLER_FINISHED;
25411  }
25412 -#define PATCH(x) \
25413 -       p->conf.x = s->x;
25414 +
25415  static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) {
25416         size_t i, j;
25417         plugin_config *s = p->config_storage[0];
25418 -       
25419 -       PATCH(exts);
25420 -       PATCH(debug);
25421 -       PATCH(ext_mapping);
25422 -       
25423 +
25424 +       PATCH_OPTION(exts);
25425 +       PATCH_OPTION(debug);
25426 +       PATCH_OPTION(ext_mapping);
25427 +
25428         /* skip the first, the global context */
25429         for (i = 1; i < srv->config_context->used; i++) {
25430                 data_config *dc = (data_config *)srv->config_context->data[i];
25431                 s = p->config_storage[i];
25432 -               
25433 +
25434                 /* condition didn't match */
25435                 if (!config_check_cond(srv, con, dc)) continue;
25436 -               
25437 +
25438                 /* merge config */
25439                 for (j = 0; j < dc->value->used; j++) {
25440                         data_unset *du = dc->value->data[j];
25441 -                       
25442 +
25443                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.server"))) {
25444 -                               PATCH(exts);
25445 +                               PATCH_OPTION(exts);
25446                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.debug"))) {
25447 -                               PATCH(debug);
25448 +                               PATCH_OPTION(debug);
25449                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.map-extensions"))) {
25450 -                               PATCH(ext_mapping);
25451 +                               PATCH_OPTION(ext_mapping);
25452                         }
25453                 }
25454         }
25455 -       
25456 +
25457         return 0;
25458  }
25459 -#undef PATCH
25460 -
25461  
25462  static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
25463         plugin_data *p = p_d;
25464 @@ -3351,16 +3269,16 @@
25465         buffer *fn;
25466         fcgi_extension *extension = NULL;
25467         fcgi_extension_host *host = NULL;
25468 -       
25469 +
25470         /* Possibly, we processed already this request */
25471         if (con->file_started == 1) return HANDLER_GO_ON;
25472  
25473         fn = uri_path_handler ? con->uri.path : con->physical.path;
25474  
25475         if (buffer_is_empty(fn)) return HANDLER_GO_ON;
25476 -       
25477 +
25478         s_len = fn->used - 1;
25479 -       
25480 +
25481         fcgi_patch_connection(srv, con, p);
25482  
25483         /* fastcgi.map-extensions maps extensions to existing fastcgi.server entries
25484 @@ -3368,24 +3286,24 @@
25485          * fastcgi.map-extensions = ( ".php3" => ".php" )
25486          *
25487          * fastcgi.server = ( ".php" => ... )
25488 -        * 
25489 +        *
25490          * */
25491  
25492         /* check if extension-mapping matches */
25493         for (k = 0; k < p->conf.ext_mapping->used; k++) {
25494                 data_string *ds = (data_string *)p->conf.ext_mapping->data[k];
25495                 size_t ct_len; /* length of the config entry */
25496 -               
25497 +
25498                 if (ds->key->used == 0) continue;
25499 -               
25500 +
25501                 ct_len = ds->key->used - 1;
25502 -               
25503 +
25504                 if (s_len < ct_len) continue;
25505 -               
25506 +
25507                 /* found a mapping */
25508                 if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
25509                         /* check if we know the extension */
25510 -                       
25511 +
25512                         /* we can reuse k here */
25513                         for (k = 0; k < p->conf.exts->used; k++) {
25514                                 extension = p->conf.exts->exts[k];
25515 @@ -3407,15 +3325,15 @@
25516                 /* check if extension matches */
25517                 for (k = 0; k < p->conf.exts->used; k++) {
25518                         size_t ct_len; /* length of the config entry */
25519 -               
25520 +
25521                         extension = p->conf.exts->exts[k];
25522 -               
25523 +
25524                         if (extension->key->used == 0) continue;
25525 -               
25526 +
25527                         ct_len = extension->key->used - 1;
25528 -               
25529 +
25530                         if (s_len < ct_len) continue;
25531 -               
25532 +
25533                         /* check extension in the form "/fcgi_pattern" */
25534                         if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
25535                                 break;
25536 @@ -3441,10 +3359,10 @@
25537                         continue;
25538                 }
25539  
25540 -               /* we found one host that is alive */ 
25541 +               /* we found one host that is alive */
25542                 break;
25543         }
25544 -       
25545 +
25546         if (!host) {
25547                 /* sorry, we don't have a server alive for this ext */
25548                 buffer_reset(con->physical.path);
25549 @@ -3459,72 +3377,72 @@
25550                                         "on", extension->key,
25551                                         "are down.");
25552                 }
25553 -               
25554 +
25555                 return HANDLER_FINISHED;
25556         }
25557  
25558         /* a note about no handler is not sent yey */
25559         extension->note_is_sent = 0;
25560  
25561 -       /* 
25562 -        * if check-local is disabled, use the uri.path handler 
25563 -        * 
25564 +       /*
25565 +        * if check-local is disabled, use the uri.path handler
25566 +        *
25567          */
25568 -       
25569 +
25570         /* init handler-context */
25571         if (uri_path_handler) {
25572                 if (host->check_local == 0) {
25573                         handler_ctx *hctx;
25574                         char *pathinfo;
25575 -                       
25576 +
25577                         hctx = handler_ctx_init();
25578 -                       
25579 +
25580                         hctx->remote_conn      = con;
25581                         hctx->plugin_data      = p;
25582                         hctx->proc             = NULL;
25583                         hctx->ext              = extension;
25584 -       
25585 +
25586  
25587                         hctx->conf.exts        = p->conf.exts;
25588                         hctx->conf.debug       = p->conf.debug;
25589 -                               
25590 +
25591                         con->plugin_ctx[p->id] = hctx;
25592 -                               
25593 +
25594                         con->mode = p->id;
25595 -                               
25596 +
25597                         if (con->conf.log_request_handling) {
25598 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
25599 +                               log_error_write(srv, __FILE__, __LINE__, "s",
25600                                 "handling it in mod_fastcgi");
25601                         }
25602 -                               
25603 -                       /* the prefix is the SCRIPT_NAME, 
25604 +
25605 +                       /* the prefix is the SCRIPT_NAME,
25606                          * everthing from start to the next slash
25607                          * this is important for check-local = "disable"
25608 -                        * 
25609 +                        *
25610                          * if prefix = /admin.fcgi
25611 -                        * 
25612 +                        *
25613                          * /admin.fcgi/foo/bar
25614 -                        * 
25615 +                        *
25616                          * SCRIPT_NAME = /admin.fcgi
25617                          * PATH_INFO   = /foo/bar
25618 -                        * 
25619 +                        *
25620                          * if prefix = /fcgi-bin/
25621 -                        * 
25622 +                        *
25623                          * /fcgi-bin/foo/bar
25624 -                        * 
25625 +                        *
25626                          * SCRIPT_NAME = /fcgi-bin/foo
25627                          * PATH_INFO   = /bar
25628 -                        * 
25629 +                        *
25630                          */
25631 -                       
25632 +
25633                         /* the rewrite is only done for /prefix/? matches */
25634                         if (extension->key->ptr[0] == '/' &&
25635                             con->uri.path->used > extension->key->used &&
25636                             NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
25637 -                               /* rewrite uri.path and pathinfo */ 
25638 -                               
25639 +                               /* rewrite uri.path and pathinfo */
25640 +
25641                                 buffer_copy_string(con->request.pathinfo, pathinfo);
25642 -                               
25643 +
25644                                 con->uri.path->used -= con->request.pathinfo->used - 1;
25645                                 con->uri.path->ptr[con->uri.path->used - 1] = '\0';
25646                         }
25647 @@ -3532,19 +3450,19 @@
25648         } else {
25649                 handler_ctx *hctx;
25650                 hctx = handler_ctx_init();
25651 -               
25652 +
25653                 hctx->remote_conn      = con;
25654                 hctx->plugin_data      = p;
25655                 hctx->proc             = NULL;
25656                 hctx->ext              = extension;
25657 -               
25658 +
25659                 hctx->conf.exts        = p->conf.exts;
25660                 hctx->conf.debug       = p->conf.debug;
25661 -               
25662 +
25663                 con->plugin_ctx[p->id] = hctx;
25664 -               
25665 +
25666                 con->mode = p->id;
25667 -               
25668 +
25669                 if (con->conf.log_request_handling) {
25670                         log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
25671                 }
25672 @@ -3566,19 +3484,19 @@
25673  JOBLIST_FUNC(mod_fastcgi_handle_joblist) {
25674         plugin_data *p = p_d;
25675         handler_ctx *hctx = con->plugin_ctx[p->id];
25676 -       
25677 +
25678         if (hctx == NULL) return HANDLER_GO_ON;
25679  
25680 -       if (hctx->fd != -1) {
25681 +       if (hctx->sock->fd != -1) {
25682                 switch (hctx->state) {
25683                 case FCGI_STATE_READ:
25684 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
25685 -                       
25686 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
25687 +
25688                         break;
25689                 case FCGI_STATE_CONNECT_DELAYED:
25690                 case FCGI_STATE_WRITE:
25691 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
25692 -                       
25693 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
25694 +
25695                         break;
25696                 case FCGI_STATE_INIT:
25697                         /* at reconnect */
25698 @@ -3595,7 +3513,7 @@
25699  
25700  static handler_t fcgi_connection_close_callback(server *srv, connection *con, void *p_d) {
25701         plugin_data *p = p_d;
25702 -       
25703 +
25704         fcgi_connection_close(srv, con->plugin_ctx[p->id]);
25705  
25706         return HANDLER_GO_ON;
25707 @@ -3604,16 +3522,39 @@
25708  TRIGGER_FUNC(mod_fastcgi_handle_trigger) {
25709         plugin_data *p = p_d;
25710         size_t i, j, n;
25711 -       
25712 -       
25713 +
25714 +
25715         /* perhaps we should kill a connect attempt after 10-15 seconds
25716 -        * 
25717 +        *
25718          * currently we wait for the TCP timeout which is on Linux 180 seconds
25719 -        * 
25720 -        * 
25721 -        * 
25722 +        *
25723          */
25724  
25725 +       for (i = 0; i < srv->conns->used; i++) {
25726 +               connection *con = srv->conns->ptr[i];
25727 +               handler_ctx *hctx = con->plugin_ctx[p->id];
25728 +
25729 +               /* if a connection is ours and is in handle-req for more than max-request-time
25730 +                * kill the connection */
25731 +
25732 +               if (con->mode != p->id) continue;
25733 +               if (con->state != CON_STATE_HANDLE_REQUEST) continue;
25734 +               if (srv->cur_ts < con->request_start + 60) continue;
25735 +
25736 +               /* the request is waiting for a FCGI_STDOUT since 60 seconds */
25737 +
25738 +               /* kill the connection */
25739 +
25740 +               log_error_write(srv, __FILE__, __LINE__, "s", "fastcgi backend didn't responded after 60 seconds");
25741 +
25742 +               fcgi_connection_close(srv, hctx);
25743 +
25744 +               con->mode = DIRECT;
25745 +               con->http_status = 500;
25746 +
25747 +               joblist_append(srv, con);
25748 +       }
25749 +
25750         /* check all childs if they are still up */
25751  
25752         for (i = 0; i < srv->config_context->used; i++) {
25753 @@ -3628,45 +3569,45 @@
25754                         fcgi_extension *ex;
25755  
25756                         ex = exts->exts[j];
25757 -                       
25758 +
25759                         for (n = 0; n < ex->used; n++) {
25760 -                               
25761 +
25762                                 fcgi_proc *proc;
25763                                 unsigned long sum_load = 0;
25764                                 fcgi_extension_host *host;
25765 -                               
25766 +
25767                                 host = ex->hosts[n];
25768 -                               
25769 +
25770                                 fcgi_restart_dead_procs(srv, p, host);
25771 -                               
25772 +
25773                                 for (proc = host->first; proc; proc = proc->next) {
25774                                         sum_load += proc->load;
25775                                 }
25776 -                               
25777 +
25778                                 if (host->num_procs &&
25779                                     host->num_procs < host->max_procs &&
25780                                     (sum_load / host->num_procs) > host->max_load_per_proc) {
25781                                         /* overload, spawn new child */
25782                                         if (p->conf.debug) {
25783 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
25784 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
25785                                                                 "overload detected, spawning a new child");
25786                                         }
25787 -                                       
25788 +
25789                                         for (proc = host->unused_procs; proc && proc->pid != 0; proc = proc->next);
25790 -                                       
25791 +
25792                                         if (proc) {
25793                                                 if (proc == host->unused_procs) host->unused_procs = proc->next;
25794 -                                               
25795 +
25796                                                 if (proc->next) proc->next->prev = NULL;
25797 -                                               
25798 +
25799                                                 host->max_id++;
25800                                         } else {
25801                                                 proc = fastcgi_process_init();
25802                                                 proc->id = host->max_id++;
25803                                         }
25804 -                                       
25805 +
25806                                         host->num_procs++;
25807 -                                       
25808 +
25809                                         if (buffer_is_empty(host->unixsocket)) {
25810                                                 proc->port = host->port + proc->id;
25811                                         } else {
25812 @@ -3674,13 +3615,13 @@
25813                                                 buffer_append_string(proc->unixsocket, "-");
25814                                                 buffer_append_long(proc->unixsocket, proc->id);
25815                                         }
25816 -                                       
25817 +
25818                                         if (fcgi_spawn_connection(srv, p, host, proc)) {
25819                                                 log_error_write(srv, __FILE__, __LINE__, "s",
25820                                                                 "ERROR: spawning fcgi failed.");
25821                                                 return HANDLER_ERROR;
25822                                         }
25823 -                                       
25824 +
25825                                         proc->prev = NULL;
25826                                         proc->next = host->first;
25827                                         if (host->first) {
25828 @@ -3688,56 +3629,56 @@
25829                                         }
25830                                         host->first = proc;
25831                                 }
25832 -                               
25833 +
25834                                 for (proc = host->first; proc; proc = proc->next) {
25835                                         if (proc->load != 0) break;
25836                                         if (host->num_procs <= host->min_procs) break;
25837                                         if (proc->pid == 0) continue;
25838 -                                       
25839 +
25840                                         if (srv->cur_ts - proc->last_used > host->idle_timeout) {
25841                                                 /* a proc is idling for a long time now,
25842                                                  * terminated it */
25843 -                                               
25844 +
25845                                                 if (p->conf.debug) {
25846 -                                                       log_error_write(srv, __FILE__, __LINE__, "ssbsd", 
25847 -                                                                       "idle-timeout reached, terminating child:", 
25848 -                                                                       "socket:", proc->connection_name, 
25849 +                                                       log_error_write(srv, __FILE__, __LINE__, "ssbsd",
25850 +                                                                       "idle-timeout reached, terminating child:",
25851 +                                                                       "socket:", proc->connection_name,
25852                                                                         "pid", proc->pid);
25853                                                 }
25854 -                                               
25855 -                                               
25856 +
25857 +
25858                                                 if (proc->next) proc->next->prev = proc->prev;
25859                                                 if (proc->prev) proc->prev->next = proc->next;
25860 -                                               
25861 +
25862                                                 if (proc->prev == NULL) host->first = proc->next;
25863 -                                               
25864 +
25865                                                 proc->prev = NULL;
25866                                                 proc->next = host->unused_procs;
25867 -                                               
25868 +
25869                                                 if (host->unused_procs) host->unused_procs->prev = proc;
25870                                                 host->unused_procs = proc;
25871 -                                               
25872 +
25873                                                 kill(proc->pid, SIGTERM);
25874 -                                               
25875 +
25876                                                 proc->state = PROC_STATE_KILLED;
25877 -                                               
25878 -                                               log_error_write(srv, __FILE__, __LINE__, "ssbsd", 
25879 -                                                                       "killed:", 
25880 -                                                                       "socket:", proc->connection_name, 
25881 +
25882 +                                               log_error_write(srv, __FILE__, __LINE__, "ssbsd",
25883 +                                                                       "killed:",
25884 +                                                                       "socket:", proc->connection_name,
25885                                                                         "pid", proc->pid);
25886 -                                               
25887 +
25888                                                 host->num_procs--;
25889 -                                               
25890 +
25891                                                 /* proc is now in unused, let the next second handle the next process */
25892                                                 break;
25893 -                                       }       
25894 +                                       }
25895                                 }
25896 -                               
25897 +
25898                                 for (proc = host->unused_procs; proc; proc = proc->next) {
25899                                         int status;
25900 -                                       
25901 +
25902                                         if (proc->pid == 0) continue;
25903 -                                       
25904 +#ifndef _WIN32
25905                                         switch (waitpid(proc->pid, &status, WNOHANG)) {
25906                                         case 0:
25907                                                 /* child still running after timeout, good */
25908 @@ -3745,10 +3686,10 @@
25909                                         case -1:
25910                                                 if (errno != EINTR) {
25911                                                         /* no PID found ? should never happen */
25912 -                                                       log_error_write(srv, __FILE__, __LINE__, "sddss", 
25913 +                                                       log_error_write(srv, __FILE__, __LINE__, "sddss",
25914                                                                         "pid ", proc->pid, proc->state,
25915                                                                         "not found:", strerror(errno));
25916 -                                                       
25917 +
25918  #if 0
25919                                                         if (errno == ECHILD) {
25920                                                                 /* someone else has cleaned up for us */
25921 @@ -3762,25 +3703,26 @@
25922                                                 /* the child should not terminate at all */
25923                                                 if (WIFEXITED(status)) {
25924                                                         if (proc->state != PROC_STATE_KILLED) {
25925 -                                                               log_error_write(srv, __FILE__, __LINE__, "sdb", 
25926 -                                                                               "child exited:", 
25927 +                                                               log_error_write(srv, __FILE__, __LINE__, "sdb",
25928 +                                                                               "child exited:",
25929                                                                                 WEXITSTATUS(status), proc->connection_name);
25930                                                         }
25931                                                 } else if (WIFSIGNALED(status)) {
25932                                                         if (WTERMSIG(status) != SIGTERM) {
25933 -                                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
25934 -                                                                               "child signaled:", 
25935 +                                                               log_error_write(srv, __FILE__, __LINE__, "sd",
25936 +                                                                               "child signaled:",
25937                                                                                 WTERMSIG(status));
25938                                                         }
25939                                                 } else {
25940 -                                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
25941 -                                                                       "child died somehow:", 
25942 +                                                       log_error_write(srv, __FILE__, __LINE__, "sd",
25943 +                                                                       "child died somehow:",
25944                                                                         status);
25945                                                 }
25946                                                 proc->pid = 0;
25947                                                 proc->state = PROC_STATE_UNSET;
25948                                                 host->max_id--;
25949                                         }
25950 +#endif
25951                                 }
25952                         }
25953                 }
25954 @@ -3804,8 +3746,8 @@
25955         p->handle_subrequest       = mod_fastcgi_handle_subrequest;
25956         p->handle_joblist          = mod_fastcgi_handle_joblist;
25957         p->handle_trigger          = mod_fastcgi_handle_trigger;
25958 -       
25959 +
25960         p->data         = NULL;
25961 -       
25962 +
25963         return 0;
25964  }
25965 --- ../lighttpd-1.4.11/src/mod_flv_streaming.c  2006-03-07 14:06:26.000000000 +0200
25966 +++ lighttpd-1.4.12/src/mod_flv_streaming.c     2006-07-16 00:26:04.000000000 +0300
25967 @@ -23,35 +23,35 @@
25968  
25969  typedef struct {
25970         PLUGIN_DATA;
25971 -       
25972 +
25973         buffer *query_str;
25974         array *get_params;
25975 -       
25976 +
25977         plugin_config **config_storage;
25978 -       
25979 -       plugin_config conf; 
25980 +
25981 +       plugin_config conf;
25982  } plugin_data;
25983  
25984  /* init the plugin data */
25985  INIT_FUNC(mod_flv_streaming_init) {
25986         plugin_data *p;
25987 -       
25988 +
25989         p = calloc(1, sizeof(*p));
25990 -       
25991 +
25992         p->query_str = buffer_init();
25993         p->get_params = array_init();
25994 -       
25995 +
25996         return p;
25997  }
25998  
25999  /* detroy the plugin data */
26000  FREE_FUNC(mod_flv_streaming_free) {
26001         plugin_data *p = p_d;
26002 -       
26003 +
26004         UNUSED(srv);
26005  
26006         if (!p) return HANDLER_GO_ON;
26007 -       
26008 +
26009         if (p->config_storage) {
26010                 size_t i;
26011  
26012 @@ -59,19 +59,19 @@
26013                         plugin_config *s = p->config_storage[i];
26014  
26015                         if (!s) continue;
26016 -                       
26017 +
26018                         array_free(s->extensions);
26019 -                       
26020 +
26021                         free(s);
26022                 }
26023                 free(p->config_storage);
26024         }
26025 -       
26026 +
26027         buffer_free(p->query_str);
26028         array_free(p->get_params);
26029 -       
26030 +
26031         free(p);
26032 -       
26033 +
26034         return HANDLER_GO_ON;
26035  }
26036  
26037 @@ -80,83 +80,80 @@
26038  SETDEFAULTS_FUNC(mod_flv_streaming_set_defaults) {
26039         plugin_data *p = p_d;
26040         size_t i = 0;
26041 -       
26042 -       config_values_t cv[] = { 
26043 +
26044 +       config_values_t cv[] = {
26045                 { "flv-streaming.extensions",   NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
26046                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
26047         };
26048 -       
26049 +
26050         if (!p) return HANDLER_ERROR;
26051 -       
26052 +
26053         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
26054 -       
26055 +
26056         for (i = 0; i < srv->config_context->used; i++) {
26057                 plugin_config *s;
26058 -               
26059 +
26060                 s = calloc(1, sizeof(plugin_config));
26061                 s->extensions     = array_init();
26062 -               
26063 +
26064                 cv[0].destination = s->extensions;
26065 -               
26066 +
26067                 p->config_storage[i] = s;
26068 -       
26069 +
26070                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
26071                         return HANDLER_ERROR;
26072                 }
26073         }
26074 -       
26075 +
26076         return HANDLER_GO_ON;
26077  }
26078  
26079 -#define PATCH(x) \
26080 -       p->conf.x = s->x;
26081  static int mod_flv_streaming_patch_connection(server *srv, connection *con, plugin_data *p) {
26082         size_t i, j;
26083         plugin_config *s = p->config_storage[0];
26084 -       
26085 -       PATCH(extensions);
26086 -       
26087 +
26088 +       PATCH_OPTION(extensions);
26089 +
26090         /* skip the first, the global context */
26091         for (i = 1; i < srv->config_context->used; i++) {
26092                 data_config *dc = (data_config *)srv->config_context->data[i];
26093                 s = p->config_storage[i];
26094 -               
26095 +
26096                 /* condition didn't match */
26097                 if (!config_check_cond(srv, con, dc)) continue;
26098 -               
26099 +
26100                 /* merge config */
26101                 for (j = 0; j < dc->value->used; j++) {
26102                         data_unset *du = dc->value->data[j];
26103 -                       
26104 +
26105                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("flv-streaming.extensions"))) {
26106 -                               PATCH(extensions);
26107 +                               PATCH_OPTION(extensions);
26108                         }
26109                 }
26110         }
26111 -       
26112 +
26113         return 0;
26114  }
26115 -#undef PATCH
26116  
26117 -static int split_get_params(server *srv, connection *con, array *get_params, buffer *qrystr) {
26118 +static int split_get_params(array *get_params, buffer *qrystr) {
26119         size_t is_key = 1;
26120         size_t i;
26121         char *key = NULL, *val = NULL;
26122 -       
26123 +
26124         key = qrystr->ptr;
26125 -       
26126 +
26127         /* we need the \0 */
26128         for (i = 0; i < qrystr->used; i++) {
26129                 switch(qrystr->ptr[i]) {
26130                 case '=':
26131                         if (is_key) {
26132                                 val = qrystr->ptr + i + 1;
26133 -                               
26134 +
26135                                 qrystr->ptr[i] = '\0';
26136 -                               
26137 +
26138                                 is_key = 0;
26139                         }
26140 -                       
26141 +
26142                         break;
26143                 case '&':
26144                 case '\0': /* fin symbol */
26145 @@ -167,7 +164,7 @@
26146                                 /* terminate the value */
26147                                 qrystr->ptr[i] = '\0';
26148  
26149 -                               if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
26150 +                               if (NULL == (ds = (data_string *)array_get_unused_element(get_params, TYPE_STRING))) {
26151                                         ds = data_string_init();
26152                                 }
26153                                 buffer_copy_string_len(ds->key, key, strlen(key));
26154 @@ -175,14 +172,14 @@
26155  
26156                                 array_insert_unique(get_params, (data_unset *)ds);
26157                         }
26158 -                       
26159 +
26160                         key = qrystr->ptr + i + 1;
26161                         val = NULL;
26162                         is_key = 1;
26163                         break;
26164                 }
26165         }
26166 -       
26167 +
26168         return 0;
26169  }
26170  
26171 @@ -190,34 +187,34 @@
26172         plugin_data *p = p_d;
26173         int s_len;
26174         size_t k;
26175 -       
26176 +
26177         UNUSED(srv);
26178  
26179         if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
26180 -       
26181 +
26182         mod_flv_streaming_patch_connection(srv, con, p);
26183  
26184         s_len = con->physical.path->used - 1;
26185 -       
26186 +
26187         for (k = 0; k < p->conf.extensions->used; k++) {
26188                 data_string *ds = (data_string *)p->conf.extensions->data[k];
26189                 int ct_len = ds->value->used - 1;
26190 -               
26191 +
26192                 if (ct_len > s_len) continue;
26193                 if (ds->value->used == 0) continue;
26194 -               
26195 +
26196                 if (0 == strncmp(con->physical.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
26197                         data_string *get_param;
26198                         stat_cache_entry *sce = NULL;
26199                         buffer *b;
26200                         int start;
26201                         char *err = NULL;
26202 -                       /* if there is a start=[0-9]+ in the header use it as start, 
26203 +                       /* if there is a start=[0-9]+ in the header use it as start,
26204                          * otherwise send the full file */
26205  
26206                         array_reset(p->get_params);
26207                         buffer_copy_string_buffer(p->query_str, con->uri.query);
26208 -                       split_get_params(srv, con, p->get_params, p->query_str);
26209 +                       split_get_params(p->get_params, p->query_str);
26210  
26211                         if (NULL == (get_param = (data_string *)array_get_element(p->get_params, "start"))) {
26212                                 return HANDLER_GO_ON;
26213 @@ -256,7 +253,7 @@
26214                         return HANDLER_FINISHED;
26215                 }
26216         }
26217 -       
26218 +
26219         /* not found */
26220         return HANDLER_GO_ON;
26221  }
26222 @@ -266,13 +263,13 @@
26223  int mod_flv_streaming_plugin_init(plugin *p) {
26224         p->version     = LIGHTTPD_VERSION_ID;
26225         p->name        = buffer_init_string("flv_streaming");
26226 -       
26227 +
26228         p->init        = mod_flv_streaming_init;
26229         p->handle_physical = mod_flv_streaming_path_handler;
26230         p->set_defaults  = mod_flv_streaming_set_defaults;
26231         p->cleanup     = mod_flv_streaming_free;
26232 -       
26233 +
26234         p->data        = NULL;
26235 -       
26236 +
26237         return 0;
26238  }
26239 --- ../lighttpd-1.4.11/src/mod_indexfile.c      2005-09-30 01:08:53.000000000 +0300
26240 +++ lighttpd-1.4.12/src/mod_indexfile.c 2006-07-16 00:26:04.000000000 +0300
26241 @@ -12,6 +12,8 @@
26242  
26243  #include "stat_cache.h"
26244  
26245 +#include "sys-strings.h"
26246 +#include "sys-files.h"
26247  /* plugin config for all request/connections */
26248  
26249  typedef struct {
26250 @@ -20,51 +22,51 @@
26251  
26252  typedef struct {
26253         PLUGIN_DATA;
26254 -       
26255 +
26256         buffer *tmp_buf;
26257 -       
26258 +
26259         plugin_config **config_storage;
26260 -       
26261 -       plugin_config conf; 
26262 +
26263 +       plugin_config conf;
26264  } plugin_data;
26265  
26266  /* init the plugin data */
26267  INIT_FUNC(mod_indexfile_init) {
26268         plugin_data *p;
26269 -       
26270 +
26271         p = calloc(1, sizeof(*p));
26272 -       
26273 +
26274         p->tmp_buf = buffer_init();
26275 -       
26276 +
26277         return p;
26278  }
26279  
26280  /* detroy the plugin data */
26281  FREE_FUNC(mod_indexfile_free) {
26282         plugin_data *p = p_d;
26283 -       
26284 +
26285         UNUSED(srv);
26286  
26287         if (!p) return HANDLER_GO_ON;
26288 -       
26289 +
26290         if (p->config_storage) {
26291                 size_t i;
26292                 for (i = 0; i < srv->config_context->used; i++) {
26293                         plugin_config *s = p->config_storage[i];
26294  
26295                         if (!s) continue;
26296 -                       
26297 +
26298                         array_free(s->indexfiles);
26299 -                       
26300 +
26301                         free(s);
26302                 }
26303                 free(p->config_storage);
26304         }
26305 -       
26306 +
26307         buffer_free(p->tmp_buf);
26308 -       
26309 +
26310         free(p);
26311 -       
26312 +
26313         return HANDLER_GO_ON;
26314  }
26315  
26316 @@ -73,131 +75,139 @@
26317  SETDEFAULTS_FUNC(mod_indexfile_set_defaults) {
26318         plugin_data *p = p_d;
26319         size_t i = 0;
26320 -       
26321 -       config_values_t cv[] = { 
26322 +
26323 +       config_values_t cv[] = {
26324                 { "index-file.names",           NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
26325                 { "server.indexfiles",          NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
26326                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
26327         };
26328 -       
26329 +
26330         if (!p) return HANDLER_ERROR;
26331 -       
26332 +
26333         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
26334 -       
26335 +
26336         for (i = 0; i < srv->config_context->used; i++) {
26337                 plugin_config *s;
26338 -               
26339 +
26340                 s = calloc(1, sizeof(plugin_config));
26341                 s->indexfiles    = array_init();
26342 -               
26343 +
26344                 cv[0].destination = s->indexfiles;
26345                 cv[1].destination = s->indexfiles; /* old name for [0] */
26346 -               
26347 +
26348                 p->config_storage[i] = s;
26349 -       
26350 +
26351                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
26352                         return HANDLER_ERROR;
26353                 }
26354         }
26355 -       
26356 +
26357         return HANDLER_GO_ON;
26358  }
26359  
26360 -#define PATCH(x) \
26361 -       p->conf.x = s->x;
26362  static int mod_indexfile_patch_connection(server *srv, connection *con, plugin_data *p) {
26363         size_t i, j;
26364         plugin_config *s = p->config_storage[0];
26365 -       
26366 -       PATCH(indexfiles);
26367 -       
26368 +
26369 +       PATCH_OPTION(indexfiles);
26370 +
26371         /* skip the first, the global context */
26372         for (i = 1; i < srv->config_context->used; i++) {
26373                 data_config *dc = (data_config *)srv->config_context->data[i];
26374                 s = p->config_storage[i];
26375 -               
26376 +
26377                 /* condition didn't match */
26378                 if (!config_check_cond(srv, con, dc)) continue;
26379 -               
26380 +
26381                 /* merge config */
26382                 for (j = 0; j < dc->value->used; j++) {
26383                         data_unset *du = dc->value->data[j];
26384 -                       
26385 +
26386                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.indexfiles"))) {
26387 -                               PATCH(indexfiles);
26388 +                               PATCH_OPTION(indexfiles);
26389                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("index-file.names"))) {
26390 -                               PATCH(indexfiles);
26391 +                               PATCH_OPTION(indexfiles);
26392                         }
26393                 }
26394         }
26395 -       
26396 +
26397         return 0;
26398  }
26399 -#undef PATCH
26400  
26401  URIHANDLER_FUNC(mod_indexfile_subrequest) {
26402         plugin_data *p = p_d;
26403         size_t k;
26404         stat_cache_entry *sce = NULL;
26405 -       
26406 +
26407         if (con->uri.path->used == 0) return HANDLER_GO_ON;
26408         if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
26409 -       
26410 +
26411         mod_indexfile_patch_connection(srv, con, p);
26412 -       
26413 +
26414 +       /* is the physical-path really a dir ? */
26415 +       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
26416 +               return HANDLER_GO_ON;
26417 +       }
26418 +
26419 +       if (!S_ISDIR(sce->st.st_mode)) {
26420 +               return HANDLER_GO_ON;
26421 +       }
26422 +
26423         if (con->conf.log_request_handling) {
26424                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling the request as Indexfile");
26425                 log_error_write(srv, __FILE__, __LINE__,  "sb", "URI          :", con->uri.path);
26426         }
26427 -       
26428 +
26429 +
26430         /* indexfile */
26431         for (k = 0; k < p->conf.indexfiles->used; k++) {
26432                 data_string *ds = (data_string *)p->conf.indexfiles->data[k];
26433 -               
26434 +
26435                 if (ds->value && ds->value->ptr[0] == '/') {
26436 -                       /* if the index-file starts with a prefix as use this file as 
26437 +                       /* if the index-file starts with a prefix as use this file as
26438                          * index-generator */
26439                         buffer_copy_string_buffer(p->tmp_buf, con->physical.doc_root);
26440                 } else {
26441                         buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
26442 +                       PATHNAME_APPEND_SLASH(p->tmp_buf);
26443                 }
26444                 buffer_append_string_buffer(p->tmp_buf, ds->value);
26445 -               
26446 +
26447                 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
26448                         if (errno == EACCES) {
26449                                 con->http_status = 403;
26450                                 buffer_reset(con->physical.path);
26451 -                               
26452 +
26453                                 return HANDLER_FINISHED;
26454                         }
26455 -                       
26456 +
26457                         if (errno != ENOENT &&
26458                             errno != ENOTDIR) {
26459                                 /* we have no idea what happend. let's tell the user so. */
26460 -                               
26461 +
26462                                 con->http_status = 500;
26463 -                               
26464 +
26465                                 log_error_write(srv, __FILE__, __LINE__, "ssbsb",
26466                                                 "file not found ... or so: ", strerror(errno),
26467                                                 con->uri.path,
26468                                                 "->", con->physical.path);
26469 -                               
26470 +
26471                                 buffer_reset(con->physical.path);
26472 -                               
26473 +
26474                                 return HANDLER_FINISHED;
26475                         }
26476                         continue;
26477                 }
26478 -                       
26479 +
26480                 /* rewrite uri.path to the real path (/ -> /index.php) */
26481                 buffer_append_string_buffer(con->uri.path, ds->value);
26482                 buffer_copy_string_buffer(con->physical.path, p->tmp_buf);
26483 -               
26484 +
26485                 /* fce is already set up a few lines above */
26486 -               
26487 +
26488                 return HANDLER_GO_ON;
26489         }
26490 -       
26491 +
26492         /* not found */
26493         return HANDLER_GO_ON;
26494  }
26495 @@ -207,13 +217,13 @@
26496  int mod_indexfile_plugin_init(plugin *p) {
26497         p->version     = LIGHTTPD_VERSION_ID;
26498         p->name        = buffer_init_string("indexfile");
26499 -       
26500 +
26501         p->init        = mod_indexfile_init;
26502         p->handle_subrequest_start = mod_indexfile_subrequest;
26503         p->set_defaults  = mod_indexfile_set_defaults;
26504         p->cleanup     = mod_indexfile_free;
26505 -       
26506 +
26507         p->data        = NULL;
26508 -       
26509 +
26510         return 0;
26511  }
26512 --- ../lighttpd-1.4.11/src/mod_mysql_vhost.c    2006-01-14 20:35:10.000000000 +0200
26513 +++ lighttpd-1.4.12/src/mod_mysql_vhost.c       2006-07-16 00:26:04.000000000 +0300
26514 @@ -1,13 +1,18 @@
26515 -#include <unistd.h>
26516  #include <stdio.h>
26517  #include <errno.h>
26518  #include <fcntl.h>
26519 -#include <strings.h>
26520 +#include <string.h>
26521  
26522  #ifdef HAVE_CONFIG_H
26523  #include "config.h"
26524  #endif
26525  
26526 +#ifdef HAVE_MYSQL_H 
26527 +# ifdef HAVE_LIBMYSQL
26528 +#  define HAVE_MYSQL
26529 +# endif
26530 +#endif
26531 +
26532  #ifdef HAVE_MYSQL
26533  #include <mysql.h>
26534  #endif
26535 @@ -16,61 +21,40 @@
26536  #include "log.h"
26537  
26538  #include "stat_cache.h"
26539 -#ifdef DEBUG_MOD_MYSQL_VHOST
26540 -#define DEBUG
26541 -#endif
26542 +#include "sys-files.h"
26543  
26544 -/*
26545 - * Plugin for lighttpd to use MySQL 
26546 - *   for domain to directory lookups,
26547 - *   i.e virtual hosts (vhosts).
26548 - *   
26549 - * Optionally sets fcgi_offset and fcgi_arg 
26550 - *   in preparation for fcgi.c to handle 
26551 - *   per-user fcgi chroot jails.
26552 - *
26553 - * /ada@riksnet.se 2004-12-06
26554 - */
26555 +#include "mod_sql_vhost_core.h"
26556  
26557  #ifdef HAVE_MYSQL
26558 +
26559 +#define CORE_PLUGIN "mod_sql_vhost_core"
26560 +
26561  typedef struct {
26562         MYSQL   *mysql;
26563 -       
26564 -       buffer  *mydb;
26565 -       buffer  *myuser;
26566 -       buffer  *mypass;
26567 -       buffer  *mysock;
26568 -       
26569 -       buffer  *hostname;
26570 -       unsigned short port;
26571 -       
26572 +
26573         buffer  *mysql_pre;
26574         buffer  *mysql_post;
26575 +
26576 +       mod_sql_vhost_core_plugin_config *core;
26577  } plugin_config;
26578  
26579  /* global plugin data */
26580  typedef struct {
26581         PLUGIN_DATA;
26582 -       
26583 +
26584         buffer  *tmp_buf;
26585 -       
26586 +
26587         plugin_config **config_storage;
26588 -       
26589 -       plugin_config conf; 
26590 +
26591 +       plugin_config conf;
26592  } plugin_data;
26593  
26594 -/* per connection plugin data */
26595 -typedef struct {
26596 -       buffer  *server_name;
26597 -       buffer  *document_root;
26598 -       buffer  *fcgi_arg;
26599 -       unsigned fcgi_offset;
26600 -} plugin_connection_data;
26601 +SQLVHOST_BACKEND_GETVHOST(mod_mysql_vhost_get_vhost); 
26602  
26603  /* init the plugin data */
26604  INIT_FUNC(mod_mysql_vhost_init) {
26605         plugin_data *p;
26606 -       
26607 +
26608         p = calloc(1, sizeof(*p));
26609  
26610         p->tmp_buf = buffer_init();
26611 @@ -83,144 +67,77 @@
26612         plugin_data *p = p_d;
26613  
26614         UNUSED(srv);
26615 -       
26616 -#ifdef DEBUG
26617 -       log_error_write(srv, __FILE__, __LINE__, "ss", 
26618 -               "mod_mysql_vhost_cleanup", p ? "yes" : "NO");
26619 -#endif
26620 +
26621         if (!p) return HANDLER_GO_ON;
26622 -       
26623 +
26624         if (p->config_storage) {
26625                 size_t i;
26626                 for (i = 0; i < srv->config_context->used; i++) {
26627                         plugin_config *s = p->config_storage[i];
26628  
26629                         if (!s) continue;
26630 -                       
26631 +
26632                         mysql_close(s->mysql);
26633 -                       
26634 -                       buffer_free(s->mydb);
26635 -                       buffer_free(s->myuser);
26636 -                       buffer_free(s->mypass);
26637 -                       buffer_free(s->mysock);
26638 +
26639                         buffer_free(s->mysql_pre);
26640                         buffer_free(s->mysql_post);
26641 -                       
26642 +
26643                         free(s);
26644                 }
26645                 free(p->config_storage);
26646         }
26647         buffer_free(p->tmp_buf);
26648 -       
26649 -       free(p);
26650  
26651 -       return HANDLER_GO_ON;
26652 -}
26653 -
26654 -/* handle the plugin per connection data */
26655 -static void* mod_mysql_vhost_connection_data(server *srv, connection *con, void *p_d)
26656 -{
26657 -       plugin_data *p = p_d;
26658 -       plugin_connection_data *c = con->plugin_ctx[p->id];
26659 -
26660 -       UNUSED(srv);
26661 -
26662 -#ifdef DEBUG
26663 -        log_error_write(srv, __FILE__, __LINE__, "ss", 
26664 -               "mod_mysql_connection_data", c ? "old" : "NEW");
26665 -#endif
26666 -
26667 -       if (c) return c;
26668 -       c = calloc(1, sizeof(*c));
26669 -
26670 -       c->server_name = buffer_init();
26671 -       c->document_root = buffer_init();
26672 -       c->fcgi_arg = buffer_init();
26673 -       c->fcgi_offset = 0;
26674 -
26675 -       return con->plugin_ctx[p->id] = c;
26676 -}
26677 -
26678 -/* destroy the plugin per connection data */
26679 -CONNECTION_FUNC(mod_mysql_vhost_handle_connection_close) {
26680 -       plugin_data *p = p_d;
26681 -       plugin_connection_data *c = con->plugin_ctx[p->id];
26682 -
26683 -       UNUSED(srv);
26684 -
26685 -#ifdef DEBUG
26686 -       log_error_write(srv, __FILE__, __LINE__, "ss", 
26687 -               "mod_mysql_vhost_handle_connection_close", c ? "yes" : "NO");
26688 -#endif
26689 -       
26690 -       if (!c) return HANDLER_GO_ON;
26691 -
26692 -       buffer_free(c->server_name);
26693 -       buffer_free(c->document_root);
26694 -       buffer_free(c->fcgi_arg);
26695 -       c->fcgi_offset = 0;
26696 -
26697 -       free(c);
26698 +       free(p);
26699  
26700 -       con->plugin_ctx[p->id] = NULL;
26701         return HANDLER_GO_ON;
26702  }
26703  
26704  /* set configuration values */
26705  SERVER_FUNC(mod_mysql_vhost_set_defaults) {
26706         plugin_data *p = p_d;
26707 +       mod_sql_vhost_core_plugin_data *core_config;
26708  
26709 -       char *qmark;
26710         size_t i = 0;
26711  
26712 -       config_values_t cv[] = {
26713 -               { "mysql-vhost.db",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
26714 -               { "mysql-vhost.user",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
26715 -               { "mysql-vhost.pass",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
26716 -               { "mysql-vhost.sock",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
26717 -               { "mysql-vhost.sql",    NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
26718 -               { "mysql-vhost.hostname", NULL, T_CONFIG_STRING,T_CONFIG_SCOPE_SERVER },
26719 -               { "mysql-vhost.port",   NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_SERVER },
26720 -                { NULL,                        NULL, T_CONFIG_UNSET,   T_CONFIG_SCOPE_UNSET }
26721 -        };
26722 -       
26723 +       /* our very own plugin storage, one entry for each conditional
26724 +        * 
26725 +        * srv->config_context->used is the number of conditionals
26726 +        * */
26727         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
26728 -       
26729 +
26730 +       /* get the config of the core-plugin */
26731 +       core_config = plugin_get_config(srv, CORE_PLUGIN);
26732 +
26733 +
26734 +       /* walk through all conditionals and check for assignments */
26735         for (i = 0; i < srv->config_context->used; i++) {
26736                 plugin_config *s;
26737                 buffer *sel;
26738 -               
26739 -               
26740 +               char *qmark;
26741 +
26742 +               /* get the config from the core plugin for this conditional-context */
26743                 s = calloc(1, sizeof(plugin_config));
26744 -               s->mydb = buffer_init();
26745 -               s->myuser = buffer_init();
26746 -               s->mypass = buffer_init();
26747 -               s->mysock = buffer_init();
26748 -               s->hostname = buffer_init();
26749 -               s->port   = 0;               /* default port for mysql */
26750 -               sel = buffer_init();
26751 -               s->mysql = NULL;
26752 +
26753 +               s->core = core_config->config_storage[i];
26754                 
26755 +               s->mysql = NULL;
26756 +
26757                 s->mysql_pre = buffer_init();
26758                 s->mysql_post = buffer_init();
26759 -               
26760 -               cv[0].destination = s->mydb;
26761 -               cv[1].destination = s->myuser;
26762 -               cv[2].destination = s->mypass;
26763 -               cv[3].destination = s->mysock;
26764 -               cv[4].destination = sel;
26765 -               cv[5].destination = s->hostname;
26766 -               cv[6].destination = &(s->port);
26767 -               
26768 +
26769                 p->config_storage[i] = s;
26770 -               
26771 -               if (config_insert_values_global(srv, 
26772 -                       ((data_config *)srv->config_context->data[i])->value,
26773 -                       cv)) return HANDLER_ERROR;
26774 -               
26775 -               s->mysql_pre = buffer_init();
26776 -               s->mysql_post = buffer_init();
26777 -               
26778 +
26779 +               /* check if we are the plugin for this backend */
26780 +               if (!buffer_is_equal_string(s->core->backend, CONST_STR_LEN("mysql"))) continue;
26781 +
26782 +               /* attach us to the core-plugin */
26783 +               s->core->backend_data = p;
26784 +               s->core->get_vhost = mod_mysql_vhost_get_vhost;
26785 +
26786 +               sel = buffer_init();
26787 +               buffer_copy_string_buffer(sel, s->core->select_vhost);
26788 +
26789                 if (sel->used && (qmark = index(sel->ptr, '?'))) {
26790                         *qmark = '\0';
26791                         buffer_copy_string(s->mysql_pre, sel->ptr);
26792 @@ -228,35 +145,35 @@
26793                 } else {
26794                         buffer_copy_string_buffer(s->mysql_pre, sel);
26795                 }
26796 -               
26797 +
26798                 /* required:
26799                  * - username
26800 -                * - database 
26801 -                * 
26802 +                * - database
26803 +                *
26804                  * optional:
26805                  * - password, default: empty
26806                  * - socket, default: mysql default
26807                  * - hostname, if set overrides socket
26808                  * - port, default: 3306
26809                  */
26810 -               
26811 +
26812                 /* all have to be set */
26813 -               if (!(buffer_is_empty(s->myuser) ||
26814 -                     buffer_is_empty(s->mydb))) {
26815 +               if (!(buffer_is_empty(s->core->user) ||
26816 +                     buffer_is_empty(s->core->db))) {
26817  
26818                         int fd;
26819 -               
26820 +
26821                         if (NULL == (s->mysql = mysql_init(NULL))) {
26822                                 log_error_write(srv, __FILE__, __LINE__, "s", "mysql_init() failed, exiting...");
26823 -                               
26824 +
26825                                 return HANDLER_ERROR;
26826                         }
26827 -#define FOO(x) (s->x->used ? s->x->ptr : NULL)
26828 -                       
26829 -                       if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(myuser), FOO(mypass), 
26830 -                                               FOO(mydb), s->port, FOO(mysock), 0)) {
26831 +#define FOO(x) (s->core->x->used ? s->core->x->ptr : NULL)
26832 +
26833 +                       if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(user), FOO(pass),
26834 +                                               FOO(db), s->core->port, FOO(sock), 0)) {
26835                                 log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(s->mysql));
26836 -                               
26837 +
26838                                 return HANDLER_ERROR;
26839                         }
26840  #undef FOO
26841 @@ -265,61 +182,47 @@
26842                         /* otherwise we cannot be sure that mysql is fd i-1 */
26843                         if (-1 == (fd = open("/dev/null", 0))) {
26844                                 close(fd);
26845 -                               fcntl(fd-1, F_SETFD, FD_CLOEXEC); 
26846 +                               fcntl(fd-1, F_SETFD, FD_CLOEXEC);
26847                         }
26848                 }
26849         }
26850 -       
26851 -       
26852 +
26853 +
26854  
26855          return HANDLER_GO_ON;
26856  }
26857  
26858 -#define PATCH(x) \
26859 -       p->conf.x = s->x;
26860  static int mod_mysql_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
26861 -       size_t i, j;
26862 +       size_t i;
26863         plugin_config *s = p->config_storage[0];
26864 -       
26865 -       PATCH(mysql_pre);
26866 -       PATCH(mysql_post);
26867 -#ifdef HAVE_MYSQL
26868 -       PATCH(mysql);
26869 -#endif
26870 -       
26871 +
26872 +       PATCH_OPTION(mysql_pre);
26873 +       PATCH_OPTION(mysql_post);
26874 +       PATCH_OPTION(mysql);
26875 +
26876         /* skip the first, the global context */
26877         for (i = 1; i < srv->config_context->used; i++) {
26878                 data_config *dc = (data_config *)srv->config_context->data[i];
26879                 s = p->config_storage[i];
26880 -               
26881 +
26882                 /* condition didn't match */
26883                 if (!config_check_cond(srv, con, dc)) continue;
26884 -               
26885 -               /* merge config */
26886 -               for (j = 0; j < dc->value->used; j++) {
26887 -                       data_unset *du = dc->value->data[j];
26888 -                       
26889 -                       if (buffer_is_equal_string(du->key, CONST_STR_LEN("mysql-vhost.sql"))) {
26890 -                               PATCH(mysql_pre);
26891 -                               PATCH(mysql_post);
26892 -                       }
26893 -               }
26894 -               
26895 +
26896                 if (s->mysql) {
26897 -                       PATCH(mysql);
26898 +                       PATCH_OPTION(mysql);
26899 +                       PATCH_OPTION(mysql_pre);
26900 +                       PATCH_OPTION(mysql_post);
26901                 }
26902         }
26903 -       
26904 +
26905         return 0;
26906  }
26907 -#undef PATCH
26908  
26909 -
26910 -/* handle document root request */
26911 -CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
26912 +/**
26913 + * get the vhost info from the database 
26914 + */
26915 +SQLVHOST_BACKEND_GETVHOST(mod_mysql_vhost_get_vhost) {
26916         plugin_data *p = p_d;
26917 -       plugin_connection_data *c;
26918 -       stat_cache_entry *sce;
26919  
26920         unsigned  cols;
26921         MYSQL_ROW row;
26922 @@ -332,13 +235,6 @@
26923  
26924         if (!p->conf.mysql) return HANDLER_GO_ON;
26925  
26926 -       /* sets up connection data if not done yet */
26927 -       c = mod_mysql_vhost_connection_data(srv, con, p_d);
26928 -
26929 -       /* check if cached this connection */
26930 -       if (c->server_name->used && /* con->uri.authority->used && */
26931 -            buffer_is_equal(c->server_name, con->uri.authority)) goto GO_ON;
26932 -
26933         /* build and run SQL query */
26934         buffer_copy_string_buffer(p->tmp_buf, p->conf.mysql_pre);
26935         if (p->conf.mysql_post->used) {
26936 @@ -347,77 +243,43 @@
26937         }
26938         if (mysql_query(p->conf.mysql, p->tmp_buf->ptr)) {
26939                 log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(p->conf.mysql));
26940 -               goto ERR500;
26941 +
26942 +               mysql_free_result(result);
26943 +               return HANDLER_GO_ON;
26944         }
26945         result = mysql_store_result(p->conf.mysql);
26946         cols = mysql_num_fields(result);
26947         row = mysql_fetch_row(result);
26948 +
26949         if (!row || cols < 1) {
26950                 /* no such virtual host */
26951                 mysql_free_result(result);
26952                 return HANDLER_GO_ON;
26953         }
26954  
26955 -       /* sanity check that really is a directory */
26956 -       buffer_copy_string(p->tmp_buf, row[0]);
26957 -       BUFFER_APPEND_SLASH(p->tmp_buf);
26958 -
26959 -       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
26960 -               log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
26961 -               goto ERR500;
26962 -       }
26963 -        if (!S_ISDIR(sce->st.st_mode)) {
26964 -               log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", p->tmp_buf);
26965 -               goto ERR500;
26966 -       }
26967 +       buffer_copy_string(docroot, row[0]);
26968  
26969 -       /* cache the data */
26970 -       buffer_copy_string_buffer(c->server_name, con->uri.authority);
26971 -       buffer_copy_string_buffer(c->document_root, p->tmp_buf);
26972 -
26973 -       /* fcgi_offset and fcgi_arg are optional */
26974 -       if (cols > 1 && row[1]) {
26975 -               c->fcgi_offset = atoi(row[1]);
26976 -               
26977 -               if (cols > 2 && row[2]) {
26978 -                       buffer_copy_string(c->fcgi_arg, row[2]);
26979 -               } else {
26980 -                       c->fcgi_arg->used = 0;
26981 -               }
26982 -       } else {
26983 -               c->fcgi_offset = c->fcgi_arg->used = 0;
26984 -       }
26985         mysql_free_result(result);
26986  
26987 -       /* fix virtual server and docroot */
26988 -GO_ON: buffer_copy_string_buffer(con->server_name, c->server_name);
26989 -       buffer_copy_string_buffer(con->physical.doc_root, c->document_root);
26990 -
26991 -#ifdef DEBUG
26992 -       log_error_write(srv, __FILE__, __LINE__, "sbbdb", 
26993 -               result ? "NOT CACHED" : "cached", 
26994 -               con->server_name, con->physical.doc_root,
26995 -               c->fcgi_offset, c->fcgi_arg);
26996 -#endif
26997 -       return HANDLER_GO_ON;   
26998 -
26999 -ERR500:        if (result) mysql_free_result(result);
27000 -       con->http_status = 500; /* Internal Error */
27001 -       return HANDLER_FINISHED;
27002 +       return HANDLER_GO_ON;
27003  }
27004  
27005  /* this function is called at dlopen() time and inits the callbacks */
27006  int mod_mysql_vhost_plugin_init(plugin *p) {
27007 +       data_string *ds;
27008 +       
27009         p->version     = LIGHTTPD_VERSION_ID;
27010         p->name                         = buffer_init_string("mysql_vhost");
27011  
27012         p->init                         = mod_mysql_vhost_init;
27013         p->cleanup                      = mod_mysql_vhost_cleanup;
27014 -       p->handle_request_done          = mod_mysql_vhost_handle_connection_close;
27015  
27016         p->set_defaults                 = mod_mysql_vhost_set_defaults;
27017 -       p->handle_docroot               = mod_mysql_vhost_handle_docroot;
27018         
27019 +       ds = data_string_init();
27020 +       buffer_copy_string(ds->value, CORE_PLUGIN);
27021 +       array_insert_unique(p->required_plugins, (data_unset *)ds);
27022 +
27023         return 0;
27024  }
27025  #else
27026 --- ../lighttpd-1.4.11/src/mod_proxy.c  2006-01-31 13:01:22.000000000 +0200
27027 +++ lighttpd-1.4.12/src/mod_proxy.c     2006-07-18 13:03:40.000000000 +0300
27028 @@ -1,6 +1,5 @@
27029  #include <sys/types.h>
27030  
27031 -#include <unistd.h>
27032  #include <errno.h>
27033  #include <fcntl.h>
27034  #include <string.h>
27035 @@ -23,6 +22,9 @@
27036  
27037  #include "inet_ntop_cache.h"
27038  #include "crc32.h"
27039 +#include "network.h"
27040 +
27041 +#include "http_resp.h"
27042  
27043  #include <stdio.h>
27044  
27045 @@ -31,6 +33,8 @@
27046  #endif
27047  
27048  #include "sys-socket.h"
27049 +#include "sys-files.h"
27050 +#include "sys-strings.h"
27051  
27052  #define data_proxy data_fastcgi
27053  #define data_proxy_init data_fastcgi_init
27054 @@ -38,22 +42,25 @@
27055  #define PROXY_RETRY_TIMEOUT 60
27056  
27057  /**
27058 - * 
27059 - * the proxy module is based on the fastcgi module 
27060 - * 
27061 + *
27062 + * the proxy module is based on the fastcgi module
27063 + *
27064   * 28.06.2004 Jan Kneschke     The first release
27065   * 01.07.2004 Evgeny Rodichev  Several bugfixes and cleanups
27066   *            - co-ordinate up- and downstream flows correctly (proxy_demux_response
27067   *              and proxy_handle_fdevent)
27068   *            - correctly transfer upstream http_response_status;
27069   *            - some unused structures removed.
27070 - * 
27071 + *
27072   * TODO:      - delay upstream read if write_queue is too large
27073   *              (to prevent memory eating, like in apache). Shoud be
27074   *              configurable).
27075   *            - persistent connection with upstream servers
27076   *            - HTTP/1.1
27077   */
27078 +
27079 +
27080 +
27081  typedef enum {
27082         PROXY_BALANCE_UNSET,
27083         PROXY_BALANCE_FAIR,
27084 @@ -66,26 +73,33 @@
27085         int debug;
27086  
27087         proxy_balance_t balance;
27088 +
27089 +       array *last_used_backends; /* "extension" : last_used_backend */
27090  } plugin_config;
27091  
27092  typedef struct {
27093         PLUGIN_DATA;
27094 -       
27095 +
27096         buffer *parse_response;
27097         buffer *balance_buf;
27098 -       
27099 +
27100 +       http_resp *resp;
27101 +
27102 +       array *ignore_headers;
27103 +
27104         plugin_config **config_storage;
27105 -       
27106 +
27107         plugin_config conf;
27108  } plugin_data;
27109  
27110 -typedef enum { 
27111 -       PROXY_STATE_INIT, 
27112 -       PROXY_STATE_CONNECT, 
27113 -       PROXY_STATE_PREPARE_WRITE, 
27114 -       PROXY_STATE_WRITE, 
27115 -       PROXY_STATE_READ, 
27116 -       PROXY_STATE_ERROR 
27117 +typedef enum {
27118 +       PROXY_STATE_INIT,
27119 +       PROXY_STATE_CONNECT,
27120 +       PROXY_STATE_PREPARE_WRITE,
27121 +       PROXY_STATE_WRITE,
27122 +       PROXY_STATE_RESPONSE_HEADER,
27123 +       PROXY_STATE_RESPONSE_CONTENT,
27124 +       PROXY_STATE_ERROR
27125  } proxy_connection_state_t;
27126  
27127  enum { PROXY_STDOUT, PROXY_END_REQUEST };
27128 @@ -93,19 +107,16 @@
27129  typedef struct {
27130         proxy_connection_state_t state;
27131         time_t state_timestamp;
27132 -       
27133 +
27134         data_proxy *host;
27135 -       
27136 -       buffer *response;
27137 -       buffer *response_header;
27138  
27139         chunkqueue *wb;
27140 -       
27141 -       int fd; /* fd to the proxy process */
27142 -       int fde_ndx; /* index into the fd-event buffer */
27143 +       chunkqueue *rb;
27144 +
27145 +       iosocket *fd; /* fd to the proxy process */
27146  
27147         size_t path_info_offset; /* start of path_info in uri.path */
27148 -       
27149 +
27150         connection *remote_conn;  /* dump pointer */
27151         plugin_data *plugin_data; /* dump pointer */
27152  } handler_ctx;
27153 @@ -116,69 +127,89 @@
27154  
27155  static handler_ctx * handler_ctx_init() {
27156         handler_ctx * hctx;
27157 -       
27158 +
27159  
27160         hctx = calloc(1, sizeof(*hctx));
27161 -       
27162 +
27163         hctx->state = PROXY_STATE_INIT;
27164         hctx->host = NULL;
27165 -       
27166 -       hctx->response = buffer_init();
27167 -       hctx->response_header = buffer_init();
27168  
27169         hctx->wb = chunkqueue_init();
27170 +       hctx->rb = chunkqueue_init();
27171 +
27172 +       hctx->fd = iosocket_init();
27173  
27174 -       hctx->fd = -1;
27175 -       hctx->fde_ndx = -1;
27176 -       
27177         return hctx;
27178  }
27179  
27180  static void handler_ctx_free(handler_ctx *hctx) {
27181 -       buffer_free(hctx->response);
27182 -       buffer_free(hctx->response_header);
27183         chunkqueue_free(hctx->wb);
27184 -       
27185 +       chunkqueue_free(hctx->rb);
27186 +
27187 +       iosocket_free(hctx->fd);
27188 +
27189         free(hctx);
27190  }
27191  
27192  INIT_FUNC(mod_proxy_init) {
27193         plugin_data *p;
27194 -       
27195 +       size_t i;
27196 +
27197 +       char *hop2hop_headers[] = {
27198 +               "Connection",
27199 +               "Keep-Alive",
27200 +               "Host",
27201 +               NULL
27202 +       };
27203 +
27204         p = calloc(1, sizeof(*p));
27205 -       
27206 -       p->parse_response = buffer_init();
27207 +
27208         p->balance_buf = buffer_init();
27209 -       
27210 +       p->ignore_headers = array_init();
27211 +       p->resp = http_response_init();
27212 +
27213 +       for (i = 0; hop2hop_headers[i]; i++) {
27214 +               data_string *ds;
27215 +
27216 +               if (NULL == (ds = (data_string *)array_get_unused_element(p->ignore_headers, TYPE_STRING))) {
27217 +                       ds = data_string_init();
27218 +               }
27219 +
27220 +               buffer_copy_string(ds->key, hop2hop_headers[i]);
27221 +               buffer_copy_string(ds->value, hop2hop_headers[i]);
27222 +               array_insert_unique(p->ignore_headers, (data_unset *)ds);
27223 +       }
27224 +
27225         return p;
27226  }
27227  
27228  
27229  FREE_FUNC(mod_proxy_free) {
27230         plugin_data *p = p_d;
27231 -       
27232 +
27233         UNUSED(srv);
27234  
27235 -       buffer_free(p->parse_response);
27236 -       buffer_free(p->balance_buf);
27237 -       
27238         if (p->config_storage) {
27239                 size_t i;
27240                 for (i = 0; i < srv->config_context->used; i++) {
27241                         plugin_config *s = p->config_storage[i];
27242 -                       
27243 +
27244                         if (s) {
27245 -                       
27246                                 array_free(s->extensions);
27247 -                       
27248 +                               array_free(s->last_used_backends);
27249 +
27250                                 free(s);
27251                         }
27252                 }
27253                 free(p->config_storage);
27254         }
27255 -       
27256 +
27257 +       array_free(p->ignore_headers);
27258 +       buffer_free(p->balance_buf);
27259 +       http_response_free(p->resp);
27260 +
27261         free(p);
27262 -       
27263 +
27264         return HANDLER_GO_ON;
27265  }
27266  
27267 @@ -186,37 +217,38 @@
27268         plugin_data *p = p_d;
27269         data_unset *du;
27270         size_t i = 0;
27271 -       
27272 -       config_values_t cv[] = { 
27273 +
27274 +       config_values_t cv[] = {
27275                 { "proxy.server",              NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
27276                 { "proxy.debug",               NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
27277                 { "proxy.balance",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 2 */
27278                 { NULL,                        NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
27279         };
27280 -       
27281 +
27282         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
27283 -       
27284 +
27285         for (i = 0; i < srv->config_context->used; i++) {
27286                 plugin_config *s;
27287                 array *ca;
27288 -               
27289 +
27290                 s = malloc(sizeof(plugin_config));
27291 -               s->extensions    = array_init();
27292 +               s->extensions         = array_init();
27293 +               s->last_used_backends = array_init();
27294                 s->debug         = 0;
27295 -               
27296 +
27297                 cv[0].destination = s->extensions;
27298                 cv[1].destination = &(s->debug);
27299                 cv[2].destination = p->balance_buf;
27300  
27301                 buffer_reset(p->balance_buf);
27302 -               
27303 +
27304                 p->config_storage[i] = s;
27305                 ca = ((data_config *)srv->config_context->data[i])->value;
27306 -       
27307 +
27308                 if (0 != config_insert_values_global(srv, ca, cv)) {
27309                         return HANDLER_ERROR;
27310                 }
27311 -       
27312 +
27313                 if (buffer_is_empty(p->balance_buf)) {
27314                         s->balance = PROXY_BALANCE_FAIR;
27315                 } else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("fair"))) {
27316 @@ -226,99 +258,99 @@
27317                 } else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("hash"))) {
27318                         s->balance = PROXY_BALANCE_HASH;
27319                 } else {
27320 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
27321 -                                       "proxy.balance has to be one of: fair, round-robin, hash, but not:", p->balance_buf);
27322 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
27323 +                               "proxy.balance has to be one of: fair, round-robin, hash, but not:", p->balance_buf);
27324                         return HANDLER_ERROR;
27325                 }
27326  
27327                 if (NULL != (du = array_get_element(ca, "proxy.server"))) {
27328                         size_t j;
27329                         data_array *da = (data_array *)du;
27330 -                       
27331 +
27332                         if (du->type != TYPE_ARRAY) {
27333 -                               log_error_write(srv, __FILE__, __LINE__, "sss", 
27334 +                               log_error_write(srv, __FILE__, __LINE__, "sss",
27335                                                 "unexpected type for key: ", "proxy.server", "array of strings");
27336 -                               
27337 +
27338                                 return HANDLER_ERROR;
27339                         }
27340 -                       
27341 -                       /* 
27342 +
27343 +                       /*
27344                          * proxy.server = ( "<ext>" => ...,
27345                          *                  "<ext>" => ... )
27346                          */
27347 -                       
27348 +
27349                         for (j = 0; j < da->value->used; j++) {
27350                                 data_array *da_ext = (data_array *)da->value->data[j];
27351                                 size_t n;
27352 -                               
27353 +
27354                                 if (da_ext->type != TYPE_ARRAY) {
27355 -                                       log_error_write(srv, __FILE__, __LINE__, "sssbs", 
27356 -                                                       "unexpected type for key: ", "proxy.server", 
27357 +                                       log_error_write(srv, __FILE__, __LINE__, "sssbs",
27358 +                                                       "unexpected type for key: ", "proxy.server",
27359                                                         "[", da->value->data[j]->key, "](string)");
27360 -                                       
27361 +
27362                                         return HANDLER_ERROR;
27363                                 }
27364 -                               
27365 -                               /* 
27366 -                                * proxy.server = ( "<ext>" => 
27367 -                                *                     ( "<host>" => ( ... ), 
27368 +
27369 +                               /*
27370 +                                * proxy.server = ( "<ext>" =>
27371 +                                *                     ( "<host>" => ( ... ),
27372                                  *                       "<host>" => ( ... )
27373 -                                *                     ), 
27374 +                                *                     ),
27375                                  *                    "<ext>" => ... )
27376                                  */
27377 -                               
27378 +
27379                                 for (n = 0; n < da_ext->value->used; n++) {
27380                                         data_array *da_host = (data_array *)da_ext->value->data[n];
27381 -                                       
27382 +
27383                                         data_proxy *df;
27384                                         data_array *dfa;
27385 -                                       
27386 -                                       config_values_t pcv[] = { 
27387 +
27388 +                                       config_values_t pcv[] = {
27389                                                 { "host",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 0 */
27390                                                 { "port",              NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
27391                                                 { NULL,                NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
27392                                         };
27393 -                                       
27394 +
27395                                         if (da_host->type != TYPE_ARRAY) {
27396 -                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS", 
27397 -                                                               "unexpected type for key:", 
27398 -                                                               "proxy.server", 
27399 +                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS",
27400 +                                                               "unexpected type for key:",
27401 +                                                               "proxy.server",
27402                                                                 "[", da_ext->value->data[n]->key, "](string)");
27403 -                                               
27404 +
27405                                                 return HANDLER_ERROR;
27406                                         }
27407 -                                       
27408 +
27409                                         df = data_proxy_init();
27410 -                                       
27411 +
27412                                         df->port = 80;
27413 -                                       
27414 +
27415                                         buffer_copy_string_buffer(df->key, da_host->key);
27416 -                                       
27417 +
27418                                         pcv[0].destination = df->host;
27419                                         pcv[1].destination = &(df->port);
27420 -                                       
27421 +
27422                                         if (0 != config_insert_values_internal(srv, da_host->value, pcv)) {
27423                                                 return HANDLER_ERROR;
27424                                         }
27425 -                                       
27426 +
27427                                         if (buffer_is_empty(df->host)) {
27428 -                                               log_error_write(srv, __FILE__, __LINE__, "sbbbs", 
27429 -                                                               "missing key (string):", 
27430 +                                               log_error_write(srv, __FILE__, __LINE__, "sbbbs",
27431 +                                                               "missing key (string):",
27432                                                                 da->key,
27433                                                                 da_ext->key,
27434                                                                 da_host->key,
27435                                                                 "host");
27436 -                                               
27437 +
27438                                                 return HANDLER_ERROR;
27439                                         }
27440 -                                       
27441 +
27442                                         /* if extension already exists, take it */
27443 -                                       
27444 +
27445                                         if (NULL == (dfa = (data_array *)array_get_element(s->extensions, da_ext->key->ptr))) {
27446                                                 dfa = data_array_init();
27447 -                                               
27448 +
27449                                                 buffer_copy_string_buffer(dfa->key, da_ext->key);
27450 -                                               
27451 +
27452                                                 array_insert_unique(dfa->value, (data_unset *)df);
27453                                                 array_insert_unique(s->extensions, (data_unset *)dfa);
27454                                         } else {
27455 @@ -328,67 +360,76 @@
27456                         }
27457                 }
27458         }
27459 -       
27460 +
27461         return HANDLER_GO_ON;
27462  }
27463  
27464  void proxy_connection_close(server *srv, handler_ctx *hctx) {
27465         plugin_data *p;
27466         connection *con;
27467 -       
27468 +
27469         if (NULL == hctx) return;
27470 -       
27471 +
27472         p    = hctx->plugin_data;
27473         con  = hctx->remote_conn;
27474 -       
27475 +
27476         if (hctx->fd != -1) {
27477 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
27478 +               fdevent_event_del(srv->ev, hctx->fd);
27479                 fdevent_unregister(srv->ev, hctx->fd);
27480  
27481 -               close(hctx->fd);
27482 +               close(hctx->fd->fd);
27483                 srv->cur_fds--;
27484         }
27485 -       
27486 +
27487         handler_ctx_free(hctx);
27488 -       con->plugin_ctx[p->id] = NULL;  
27489 +       con->plugin_ctx[p->id] = NULL;
27490  }
27491  
27492  static int proxy_establish_connection(server *srv, handler_ctx *hctx) {
27493         struct sockaddr *proxy_addr;
27494         struct sockaddr_in proxy_addr_in;
27495         socklen_t servlen;
27496 -       
27497 +
27498         plugin_data *p    = hctx->plugin_data;
27499         data_proxy *host= hctx->host;
27500 -       int proxy_fd       = hctx->fd;
27501 -       
27502 +       int proxy_fd       = hctx->fd->fd;
27503 +
27504         memset(&proxy_addr, 0, sizeof(proxy_addr));
27505 -       
27506 +
27507         proxy_addr_in.sin_family = AF_INET;
27508         proxy_addr_in.sin_addr.s_addr = inet_addr(host->host->ptr);
27509         proxy_addr_in.sin_port = htons(host->port);
27510         servlen = sizeof(proxy_addr_in);
27511 -               
27512 +
27513         proxy_addr = (struct sockaddr *) &proxy_addr_in;
27514 -       
27515 +
27516         if (-1 == connect(proxy_fd, proxy_addr, servlen)) {
27517 -               if (errno == EINPROGRESS || errno == EALREADY) {
27518 +#ifdef _WIN32
27519 +       errno = WSAGetLastError();
27520 +#endif
27521 +       switch(errno) {
27522 +#ifdef _WIN32
27523 +       case WSAEWOULDBLOCK:
27524 +#endif
27525 +       case EINPROGRESS:
27526 +       case EALREADY:
27527                         if (p->conf.debug) {
27528 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
27529 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
27530                                                 "connect delayed:", proxy_fd);
27531                         }
27532 -                       
27533 +
27534                         return 1;
27535 -               } else {
27536 -                       
27537 -                       log_error_write(srv, __FILE__, __LINE__, "sdsd", 
27538 +               default:
27539 +
27540 +                       log_error_write(srv, __FILE__, __LINE__, "sdsd",
27541                                         "connect failed:", proxy_fd, strerror(errno), errno);
27542 -                       
27543 +
27544                         return -1;
27545                 }
27546         }
27547 +       fprintf(stderr, "%s.%d: connected fd = %d\r\n", __FILE__, __LINE__, proxy_fd);
27548         if (p->conf.debug) {
27549 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
27550 +               log_error_write(srv, __FILE__, __LINE__, "sd",
27551                                 "connect succeeded: ", proxy_fd);
27552         }
27553  
27554 @@ -396,51 +437,52 @@
27555  }
27556  
27557  void proxy_set_header(connection *con, const char *key, const char *value) {
27558 -    data_string *ds_dst;
27559 +       data_string *ds_dst;
27560  
27561 -    if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27562 -          ds_dst = data_string_init();
27563 -    }
27564 -
27565 -    buffer_copy_string(ds_dst->key, key);
27566 -    buffer_copy_string(ds_dst->value, value);
27567 -    array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27568 +       if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27569 +               ds_dst = data_string_init();
27570 +       }
27571 +
27572 +       buffer_copy_string(ds_dst->key, key);
27573 +       buffer_copy_string(ds_dst->value, value);
27574 +       array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27575  }
27576  
27577  void proxy_append_header(connection *con, const char *key, const char *value) {
27578 -    data_string *ds_dst;
27579 +       data_string *ds_dst;
27580  
27581 -    if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27582 -          ds_dst = data_string_init();
27583 -    }
27584 -
27585 -    buffer_copy_string(ds_dst->key, key);
27586 -    buffer_append_string(ds_dst->value, value);
27587 -    array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27588 +       if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27589 +               ds_dst = data_string_init();
27590 +       }
27591 +
27592 +       buffer_copy_string(ds_dst->key, key);
27593 +       buffer_append_string(ds_dst->value, value);
27594 +       array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27595  }
27596  
27597  
27598  static int proxy_create_env(server *srv, handler_ctx *hctx) {
27599         size_t i;
27600 -       
27601 +
27602         connection *con   = hctx->remote_conn;
27603 +       plugin_data *p    = hctx->plugin_data;
27604         buffer *b;
27605 -       
27606 +
27607         /* build header */
27608  
27609         b = chunkqueue_get_append_buffer(hctx->wb);
27610 -       
27611 +
27612         /* request line */
27613         buffer_copy_string(b, get_http_method_name(con->request.http_method));
27614         BUFFER_APPEND_STRING_CONST(b, " ");
27615 -       
27616 +
27617         buffer_append_string_buffer(b, con->request.uri);
27618         BUFFER_APPEND_STRING_CONST(b, " HTTP/1.0\r\n");
27619  
27620         proxy_append_header(con, "X-Forwarded-For", (char *)inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
27621 -       /* http_host is NOT is just a pointer to a buffer 
27622 +       /* http_host is NOT is just a pointer to a buffer
27623          * which is NULL if it is not set */
27624 -       if (con->request.http_host && 
27625 +       if (con->request.http_host &&
27626             !buffer_is_empty(con->request.http_host)) {
27627                 proxy_set_header(con, "X-Host", con->request.http_host->ptr);
27628         }
27629 @@ -449,24 +491,25 @@
27630         /* request header */
27631         for (i = 0; i < con->request.headers->used; i++) {
27632                 data_string *ds;
27633 -               
27634 +
27635                 ds = (data_string *)con->request.headers->data[i];
27636 -               
27637 -               if (ds->value->used && ds->key->used) {
27638 -                       if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
27639 -                       
27640 -                       buffer_append_string_buffer(b, ds->key);
27641 -                       BUFFER_APPEND_STRING_CONST(b, ": ");
27642 -                       buffer_append_string_buffer(b, ds->value);
27643 -                       BUFFER_APPEND_STRING_CONST(b, "\r\n");
27644 -               }
27645 +
27646 +               if (buffer_is_empty(ds->value) || buffer_is_empty(ds->key)) continue;
27647 +
27648 +               if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
27649 +               if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Keep-Alive"))) continue;
27650 +
27651 +               buffer_append_string_buffer(b, ds->key);
27652 +               BUFFER_APPEND_STRING_CONST(b, ": ");
27653 +               buffer_append_string_buffer(b, ds->value);
27654 +               BUFFER_APPEND_STRING_CONST(b, "\r\n");
27655         }
27656 -       
27657 +
27658         BUFFER_APPEND_STRING_CONST(b, "\r\n");
27659 -       
27660 +
27661         hctx->wb->bytes_in += b->used - 1;
27662         /* body */
27663 -       
27664 +
27665         if (con->request.content_length) {
27666                 chunkqueue *req_cq = con->request_content_queue;
27667                 chunk *req_c;
27668 @@ -479,7 +522,7 @@
27669  
27670                         /* we announce toWrite octects
27671                          * now take all the request_content chunk that we need to fill this request
27672 -                        * */   
27673 +                        * */
27674  
27675                         switch (req_c->type) {
27676                         case FILE_CHUNK:
27677 @@ -507,223 +550,150 @@
27678  
27679                                 req_c->offset += weHave;
27680                                 req_cq->bytes_out += weHave;
27681 -                               
27682 +
27683                                 hctx->wb->bytes_in += weHave;
27684  
27685                                 break;
27686                         default:
27687                                 break;
27688                         }
27689 -                       
27690 +
27691                         offset += weHave;
27692                 }
27693  
27694         }
27695 -       
27696 +
27697         return 0;
27698  }
27699  
27700  static int proxy_set_state(server *srv, handler_ctx *hctx, proxy_connection_state_t state) {
27701         hctx->state = state;
27702         hctx->state_timestamp = srv->cur_ts;
27703 -       
27704 -       return 0;
27705 -}
27706  
27707 -
27708 -static int proxy_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
27709 -       char *s, *ns;
27710 -       int http_response_status = -1;
27711 -       
27712 -       UNUSED(srv);
27713 -
27714 -       /* \r\n -> \0\0 */
27715 -       
27716 -       buffer_copy_string_buffer(p->parse_response, in);
27717 -       
27718 -       for (s = p->parse_response->ptr; NULL != (ns = strstr(s, "\r\n")); s = ns + 2) {
27719 -               char *key, *value;
27720 -               int key_len;
27721 -               data_string *ds;
27722 -               int copy_header;
27723 -               
27724 -               ns[0] = '\0';
27725 -               ns[1] = '\0';
27726 -
27727 -               if (-1 == http_response_status) {
27728 -                       /* The first line of a Response message is the Status-Line */
27729 -
27730 -                       for (key=s; *key && *key != ' '; key++);
27731 -
27732 -                       if (*key) {
27733 -                               http_response_status = (int) strtol(key, NULL, 10);
27734 -                               if (http_response_status <= 0) http_response_status = 502;
27735 -                       } else {
27736 -                               http_response_status = 502;
27737 -                       }
27738 -
27739 -                       con->http_status = http_response_status;
27740 -                       con->parsed_response |= HTTP_STATUS;
27741 -                       continue;
27742 -               }
27743 -               
27744 -               if (NULL == (value = strchr(s, ':'))) {
27745 -                       /* now we expect: "<key>: <value>\n" */
27746 -
27747 -                       continue;
27748 -               }
27749 -
27750 -               key = s;
27751 -               key_len = value - key;
27752 -               
27753 -               value++;
27754 -               /* strip WS */
27755 -               while (*value == ' ' || *value == '\t') value++;
27756 -               
27757 -               copy_header = 1;
27758 -               
27759 -               switch(key_len) {
27760 -               case 4:
27761 -                       if (0 == strncasecmp(key, "Date", key_len)) {
27762 -                               con->parsed_response |= HTTP_DATE;
27763 -                       }
27764 -                       break;
27765 -               case 8:
27766 -                       if (0 == strncasecmp(key, "Location", key_len)) {
27767 -                               con->parsed_response |= HTTP_LOCATION;
27768 -                       }
27769 -                       break;
27770 -               case 10:
27771 -                       if (0 == strncasecmp(key, "Connection", key_len)) {
27772 -                               copy_header = 0;
27773 -                       }
27774 -                       break;
27775 -               case 14:
27776 -                       if (0 == strncasecmp(key, "Content-Length", key_len)) {
27777 -                               con->response.content_length = strtol(value, NULL, 10);
27778 -                               con->parsed_response |= HTTP_CONTENT_LENGTH;
27779 -                       }
27780 -                       break;
27781 -               default:
27782 -                       break;
27783 -               }
27784 -
27785 -               if (copy_header) {
27786 -                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
27787 -                               ds = data_response_init();
27788 -                       }
27789 -                       buffer_copy_string_len(ds->key, key, key_len);
27790 -                       buffer_copy_string(ds->value, value);
27791 -                       
27792 -                       array_insert_unique(con->response.headers, (data_unset *)ds);
27793 -               }
27794 -       }
27795 -       
27796         return 0;
27797  }
27798  
27799  
27800  static int proxy_demux_response(server *srv, handler_ctx *hctx) {
27801 -       int fin = 0;
27802 -       int b;
27803 -       ssize_t r;
27804 -       
27805         plugin_data *p    = hctx->plugin_data;
27806         connection *con   = hctx->remote_conn;
27807 -       int proxy_fd       = hctx->fd;
27808 -       
27809 -       /* check how much we have to read */
27810 -       if (ioctl(hctx->fd, FIONREAD, &b)) {
27811 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
27812 -                               "ioctl failed: ",
27813 -                               proxy_fd);
27814 +       chunkqueue *next_queue = NULL;
27815 +       chunk *c = NULL;
27816 +
27817 +       switch(srv->network_backend_read(srv, con, hctx->fd, hctx->rb)) {
27818 +       case NETWORK_STATUS_SUCCESS:
27819 +               /* we got content */
27820 +               break;
27821 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
27822 +               return 0;
27823 +       case NETWORK_STATUS_CONNECTION_CLOSE:
27824 +               /* we are done, get out of here */
27825 +               con->file_finished = 1;
27826 +
27827 +               /* close the chunk-queue with a empty chunk */
27828 +
27829 +               return 1;
27830 +       default:
27831 +               /* oops */
27832                 return -1;
27833         }
27834  
27835 +       /* looks like we got some content
27836 +       *
27837 +       * split off the header from the incoming stream
27838 +       */
27839  
27840 -       if (p->conf.debug) {
27841 -               log_error_write(srv, __FILE__, __LINE__, "sd",
27842 -                              "proxy - have to read:", b);
27843 -       }
27844 +       if (hctx->state == PROXY_STATE_RESPONSE_HEADER) {
27845 +               size_t i;
27846 +               int have_content_length = 0;
27847  
27848 -       if (b > 0) {
27849 -               if (hctx->response->used == 0) {
27850 -                       /* avoid too small buffer */
27851 -                       buffer_prepare_append(hctx->response, b + 1);
27852 -                       hctx->response->used = 1;
27853 -               } else {
27854 -                       buffer_prepare_append(hctx->response, hctx->response->used + b);
27855 -               }
27856 -               
27857 -               if (-1 == (r = read(hctx->fd, hctx->response->ptr + hctx->response->used - 1, b))) {
27858 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
27859 -                                       "unexpected end-of-file (perhaps the proxy process died):",
27860 -                                       proxy_fd, strerror(errno));
27861 -                       return -1;
27862 -               }
27863 -               
27864 -               /* this should be catched by the b > 0 above */
27865 -               assert(r);
27866 -               
27867 -               hctx->response->used += r;
27868 -               hctx->response->ptr[hctx->response->used - 1] = '\0';
27869 -
27870 -#if 0
27871 -               log_error_write(srv, __FILE__, __LINE__, "sdsbs", 
27872 -                               "demux: Response buffer len", hctx->response->used, ":", hctx->response, ":");
27873 -#endif
27874 +               http_response_reset(p->resp);
27875  
27876 -               if (0 == con->got_response) {
27877 -                       con->got_response = 1;
27878 -                       buffer_prepare_copy(hctx->response_header, 128);
27879 -               }
27880 -                               
27881 -               if (0 == con->file_started) {
27882 -                       char *c;
27883 -                               
27884 -                       /* search for the \r\n\r\n in the string */
27885 -                       if (NULL != (c = buffer_search_string_len(hctx->response, "\r\n\r\n", 4))) {
27886 -                               size_t hlen = c - hctx->response->ptr + 4;
27887 -                               size_t blen = hctx->response->used - hlen - 1;
27888 -                               /* found */
27889 -                               
27890 -                               buffer_append_string_len(hctx->response_header, hctx->response->ptr, c - hctx->response->ptr + 4);
27891 -#if 0
27892 -                               log_error_write(srv, __FILE__, __LINE__, "sb", "Header:", hctx->response_header);
27893 -#endif
27894 -                               /* parse the response header */
27895 -                               proxy_response_parse(srv, con, p, hctx->response_header);
27896 -                                       
27897 -                               /* enable chunked-transfer-encoding */
27898 -                               if (con->request.http_version == HTTP_VERSION_1_1 &&
27899 -                                   !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
27900 -                                       con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
27901 +               /* the response header is not fully received yet,
27902 +               *
27903 +               * extract the http-response header from the rb-cq
27904 +               */
27905 +               switch (http_response_parse_cq(hctx->rb, p->resp)) {
27906 +               case PARSE_ERROR:
27907 +                       /* parsing failed */
27908 +
27909 +                       con->http_status = 502; /* Bad Gateway */
27910 +                       return 1;
27911 +               case PARSE_NEED_MORE:
27912 +                       return 0;
27913 +               case PARSE_SUCCESS:
27914 +                       con->http_status = p->resp->status;
27915 +
27916 +                       chunkqueue_remove_finished_chunks(hctx->rb);
27917 +
27918 +                       /* copy the http-headers */
27919 +                       for (i = 0; i < p->resp->headers->used; i++) {
27920 +                               const char *ign[] = { "Status", "Connection", NULL };
27921 +                               size_t j;
27922 +                               data_string *ds;
27923 +
27924 +                               data_string *header = (data_string *)p->resp->headers->data[i];
27925 +
27926 +                               /* some headers are ignored by default */
27927 +                               for (j = 0; ign[j]; j++) {
27928 +                                       if (0 == strcasecmp(ign[j], header->key->ptr)) break;
27929 +                               }
27930 +                               if (ign[j]) continue;
27931 +
27932 +                               if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
27933 +                                       /* CGI/1.1 rev 03 - 7.2.1.2 */
27934 +                                       if (con->http_status == 0) con->http_status = 302;
27935 +                               } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
27936 +                                       have_content_length = 1;
27937                                 }
27938 -                                       
27939 -                               con->file_started = 1;
27940 -                               if (blen) {
27941 -                                       http_chunk_append_mem(srv, con, c + 4, blen + 1);
27942 -                                       joblist_append(srv, con);
27943 +                               
27944 +                               if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
27945 +                                       ds = data_response_init();
27946                                 }
27947 -                               hctx->response->used = 0;
27948 +                               buffer_copy_string_buffer(ds->key, header->key);
27949 +                               buffer_copy_string_buffer(ds->value, header->value);
27950 +
27951 +                               array_insert_unique(con->response.headers, (data_unset *)ds);
27952                         }
27953 -               } else {
27954 -                       http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
27955 -                       joblist_append(srv, con);
27956 -                       hctx->response->used = 0;
27957 +
27958 +                       con->file_started = 1;
27959 +
27960 +                       if (con->request.http_version == HTTP_VERSION_1_1 &&
27961 +                           !have_content_length) {
27962 +                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
27963 +                       }
27964 +
27965 +                       hctx->state = PROXY_STATE_RESPONSE_CONTENT;
27966 +                       break;
27967                 }
27968 -               
27969 -       } else {
27970 -               /* reading from upstream done */
27971 -               con->file_finished = 1;
27972 -               
27973 -               http_chunk_append_mem(srv, con, NULL, 0);
27974 -               joblist_append(srv, con);
27975 -               
27976 -               fin = 1;
27977         }
27978 -       
27979 -       return fin;
27980 +
27981 +       /* FIXME: pass the response-header to the other plugins to
27982 +       * setup the filter-queue
27983 +       *
27984 +       * - use next-queue instead of con->write_queue
27985 +       */
27986 +
27987 +       next_queue = con->write_queue;
27988 +
27989 +       assert(hctx->state == PROXY_STATE_RESPONSE_CONTENT);
27990 +
27991 +       /* FIXME: if we have a content-length or chunked-encoding
27992 +       * handle it.
27993 +       *
27994 +       * for now we wait for EOF on the socket */
27995 +
27996 +       /* copy the content to the next cq */
27997 +       for (c = hctx->rb->first; c; c = c->next) {
27998 +               http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
27999 +
28000 +               c->offset = c->mem->used - 1;
28001 +       }
28002 +
28003 +       chunkqueue_remove_finished_chunks(hctx->rb);
28004 +       joblist_append(srv, con);
28005 +
28006 +       return 0;
28007  }
28008  
28009  
28010 @@ -731,32 +701,32 @@
28011         data_proxy *host= hctx->host;
28012         plugin_data *p    = hctx->plugin_data;
28013         connection *con   = hctx->remote_conn;
28014 -       
28015 +
28016         int ret;
28017 -       
28018 -       if (!host || 
28019 -           (!host->host->used || !host->port)) return -1;
28020 -       
28021 +
28022 +       if (!host ||
28023 +               (!host->host->used || !host->port)) return -1;
28024 +
28025         switch(hctx->state) {
28026         case PROXY_STATE_INIT:
28027 -               if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) {
28028 +               if (-1 == (hctx->fd->fd = socket(AF_INET, SOCK_STREAM, 0))) {
28029                         log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
28030                         return HANDLER_ERROR;
28031                 }
28032 -               hctx->fde_ndx = -1;
28033 -               
28034 +               hctx->fd->fde_ndx = -1;
28035 +
28036                 srv->cur_fds++;
28037 -               
28038 +
28039                 fdevent_register(srv->ev, hctx->fd, proxy_handle_fdevent, hctx);
28040 -               
28041 +
28042                 if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
28043                         log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
28044 -                       
28045 +
28046                         return HANDLER_ERROR;
28047                 }
28048 -               
28049 +
28050                 /* fall through */
28051 -               
28052 +
28053         case PROXY_STATE_CONNECT:
28054                 /* try to finish the connect() */
28055                 if (hctx->state == PROXY_STATE_INIT) {
28056 @@ -764,16 +734,16 @@
28057                         switch (proxy_establish_connection(srv, hctx)) {
28058                         case 1:
28059                                 proxy_set_state(srv, hctx, PROXY_STATE_CONNECT);
28060 -                               
28061 +
28062                                 /* connection is in progress, wait for an event and call getsockopt() below */
28063 -                               
28064 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28065 -                               
28066 +
28067 +                               fdevent_event_add(srv->ev, hctx->fd, FDEVENT_OUT);
28068 +
28069                                 return HANDLER_WAIT_FOR_EVENT;
28070                         case -1:
28071                                 /* if ECONNREFUSED choose another connection -> FIXME */
28072 -                               hctx->fde_ndx = -1;
28073 -                               
28074 +                               hctx->fd->fde_ndx = -1;
28075 +
28076                                 return HANDLER_ERROR;
28077                         default:
28078                                 /* everything is ok, go on */
28079 @@ -782,152 +752,152 @@
28080                 } else {
28081                         int socket_error;
28082                         socklen_t socket_error_len = sizeof(socket_error);
28083 -               
28084 -                       /* we don't need it anymore */  
28085 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
28086 +
28087 +                       /* we don't need it anymore */
28088 +                       fdevent_event_del(srv->ev, hctx->fd);
28089  
28090                         /* try to finish the connect() */
28091 -                       if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
28092 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
28093 +                       if (0 != getsockopt(hctx->fd->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
28094 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
28095                                                 "getsockopt failed:", strerror(errno));
28096 -                               
28097 +
28098                                 return HANDLER_ERROR;
28099                         }
28100                         if (socket_error != 0) {
28101                                 log_error_write(srv, __FILE__, __LINE__, "ss",
28102 -                                               "establishing connection failed:", strerror(socket_error), 
28103 +                                               "establishing connection failed:", strerror(socket_error),
28104                                                 "port:", hctx->host->port);
28105 -                               
28106 +
28107                                 return HANDLER_ERROR;
28108                         }
28109                         if (p->conf.debug) {
28110 -                               log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - connect - delayed success"); 
28111 +                               log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - connect - delayed success");
28112                         }
28113                 }
28114 -               
28115 +
28116                 proxy_set_state(srv, hctx, PROXY_STATE_PREPARE_WRITE);
28117                 /* fall through */
28118         case PROXY_STATE_PREPARE_WRITE:
28119                 proxy_create_env(srv, hctx);
28120 -               
28121 +
28122                 proxy_set_state(srv, hctx, PROXY_STATE_WRITE);
28123 -               
28124 +
28125                 /* fall through */
28126         case PROXY_STATE_WRITE:;
28127 -               ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); 
28128 +               ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb);
28129  
28130                 chunkqueue_remove_finished_chunks(hctx->wb);
28131  
28132 -               if (-1 == ret) {
28133 -                       if (errno != EAGAIN &&
28134 -                           errno != EINTR) {
28135 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
28136 -                               
28137 -                               return HANDLER_ERROR;
28138 -                       } else {
28139 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28140 +               switch(ret) {
28141 +               case NETWORK_STATUS_FATAL_ERROR:
28142 +                       log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
28143  
28144 -                               return HANDLER_WAIT_FOR_EVENT;
28145 -                       }
28146 +                       return HANDLER_ERROR;
28147 +               case NETWORK_STATUS_WAIT_FOR_EVENT:
28148 +
28149 +                       fdevent_event_add(srv->ev, hctx->fd, FDEVENT_OUT);
28150 +
28151 +                       return HANDLER_WAIT_FOR_EVENT;
28152                 }
28153  
28154                 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
28155 -                       proxy_set_state(srv, hctx, PROXY_STATE_READ);
28156 +                       proxy_set_state(srv, hctx, PROXY_STATE_RESPONSE_HEADER);
28157  
28158 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
28159 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
28160 +                       fdevent_event_del(srv->ev, hctx->fd);
28161 +                       fdevent_event_add(srv->ev, hctx->fd, FDEVENT_IN);
28162                 } else {
28163 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28164 -                               
28165 +                       fdevent_event_add(srv->ev, hctx->fd, FDEVENT_OUT);
28166 +
28167                         return HANDLER_WAIT_FOR_EVENT;
28168                 }
28169 -               
28170 +
28171                 return HANDLER_WAIT_FOR_EVENT;
28172 -       case PROXY_STATE_READ:
28173 +       case PROXY_STATE_RESPONSE_CONTENT:
28174 +       case PROXY_STATE_RESPONSE_HEADER:
28175                 /* waiting for a response */
28176 +
28177                 return HANDLER_WAIT_FOR_EVENT;
28178         default:
28179                 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
28180                 return HANDLER_ERROR;
28181         }
28182 -       
28183 +
28184         return HANDLER_GO_ON;
28185  }
28186  
28187 -#define PATCH(x) \
28188 -       p->conf.x = s->x;
28189  static int mod_proxy_patch_connection(server *srv, connection *con, plugin_data *p) {
28190         size_t i, j;
28191         plugin_config *s = p->config_storage[0];
28192 -       
28193 -       PATCH(extensions);
28194 -       PATCH(debug);
28195 -       PATCH(balance);
28196 -       
28197 +
28198 +       PATCH_OPTION(extensions);
28199 +       PATCH_OPTION(debug);
28200 +       PATCH_OPTION(balance);
28201 +       PATCH_OPTION(last_used_backends);
28202 +
28203         /* skip the first, the global context */
28204         for (i = 1; i < srv->config_context->used; i++) {
28205                 data_config *dc = (data_config *)srv->config_context->data[i];
28206                 s = p->config_storage[i];
28207 -               
28208 +
28209                 /* condition didn't match */
28210                 if (!config_check_cond(srv, con, dc)) continue;
28211 -               
28212 +
28213                 /* merge config */
28214                 for (j = 0; j < dc->value->used; j++) {
28215                         data_unset *du = dc->value->data[j];
28216 -                       
28217 +
28218                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.server"))) {
28219 -                               PATCH(extensions);
28220 +                               PATCH_OPTION(extensions);
28221                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.debug"))) {
28222 -                               PATCH(debug);
28223 +                               PATCH_OPTION(debug);
28224                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.balance"))) {
28225 -                               PATCH(balance);
28226 +                               PATCH_OPTION(balance);
28227 +                               PATCH_OPTION(last_used_backends);
28228                         }
28229                 }
28230         }
28231 -       
28232 +
28233         return 0;
28234  }
28235 -#undef PATCH
28236  
28237  SUBREQUEST_FUNC(mod_proxy_handle_subrequest) {
28238         plugin_data *p = p_d;
28239 -       
28240 +
28241         handler_ctx *hctx = con->plugin_ctx[p->id];
28242         data_proxy *host;
28243 -       
28244 +
28245         if (NULL == hctx) return HANDLER_GO_ON;
28246  
28247         mod_proxy_patch_connection(srv, con, p);
28248 -       
28249 +
28250         host = hctx->host;
28251 -       
28252 +
28253         /* not my job */
28254         if (con->mode != p->id) return HANDLER_GO_ON;
28255 -       
28256 +
28257         /* ok, create the request */
28258         switch(proxy_write_request(srv, hctx)) {
28259         case HANDLER_ERROR:
28260 -               log_error_write(srv, __FILE__, __LINE__,  "sbdd", "proxy-server disabled:", 
28261 +               log_error_write(srv, __FILE__, __LINE__,  "sbdd", "proxy-server disabled:",
28262                                 host->host,
28263                                 host->port,
28264 -                               hctx->fd);
28265 -               
28266 +                               hctx->fd->fd);
28267 +
28268                 /* disable this server */
28269                 host->is_disabled = 1;
28270                 host->disable_ts = srv->cur_ts;
28271 -               
28272 +
28273                 proxy_connection_close(srv, hctx);
28274 -       
28275 -               /* reset the enviroment and restart the sub-request */  
28276 +
28277 +               /* reset the enviroment and restart the sub-request */
28278                 buffer_reset(con->physical.path);
28279                 con->mode = DIRECT;
28280  
28281                 joblist_append(srv, con);
28282  
28283 -               /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop 
28284 -                * and hope that the childs will be restarted 
28285 -                * 
28286 +               /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
28287 +                * and hope that the childs will be restarted
28288 +                *
28289                  */
28290  
28291                 return HANDLER_WAIT_FOR_FD;
28292 @@ -938,7 +908,7 @@
28293         default:
28294                 break;
28295         }
28296 -       
28297 +
28298         if (con->file_started == 1) {
28299                 return HANDLER_FINISHED;
28300         } else {
28301 @@ -951,13 +921,14 @@
28302         handler_ctx *hctx = ctx;
28303         connection  *con  = hctx->remote_conn;
28304         plugin_data *p    = hctx->plugin_data;
28305 -       
28306 -       
28307 +
28308 +
28309         if ((revents & FDEVENT_IN) &&
28310 -           hctx->state == PROXY_STATE_READ) {
28311 +           (hctx->state == PROXY_STATE_RESPONSE_HEADER ||
28312 +            hctx->state == PROXY_STATE_RESPONSE_CONTENT)) {
28313  
28314                 if (p->conf.debug) {
28315 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
28316 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
28317                                         "proxy: fdevent-in", hctx->state);
28318                 }
28319  
28320 @@ -965,11 +936,15 @@
28321                 case 0:
28322                         break;
28323                 case 1:
28324 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
28325 +                                       "proxy: request done", hctx->fd->fd);
28326                         hctx->host->usage--;
28327 -                       
28328 +
28329 +                       http_chunk_append_mem(srv, con, NULL, 0);
28330 +
28331                         /* we are done */
28332                         proxy_connection_close(srv, hctx);
28333 -                       
28334 +
28335                         joblist_append(srv, con);
28336                         return HANDLER_FINISHED;
28337                 case -1:
28338 @@ -982,53 +957,53 @@
28339                                 /* response might have been already started, kill the connection */
28340                                 connection_set_state(srv, con, CON_STATE_ERROR);
28341                         }
28342 -                       
28343 +
28344                         joblist_append(srv, con);
28345                         return HANDLER_FINISHED;
28346                 }
28347         }
28348 -       
28349 +
28350         if (revents & FDEVENT_OUT) {
28351                 if (p->conf.debug) {
28352 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
28353 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
28354                                         "proxy: fdevent-out", hctx->state);
28355                 }
28356  
28357                 if (hctx->state == PROXY_STATE_CONNECT ||
28358                     hctx->state == PROXY_STATE_WRITE) {
28359                         /* we are allowed to send something out
28360 -                        * 
28361 +                        *
28362                          * 1. in a unfinished connect() call
28363                          * 2. in a unfinished write() call (long POST request)
28364                          */
28365                         return mod_proxy_handle_subrequest(srv, con, p);
28366                 } else {
28367 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
28368 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
28369                                         "proxy: out", hctx->state);
28370                 }
28371         }
28372 -       
28373 +
28374         /* perhaps this issue is already handled */
28375         if (revents & FDEVENT_HUP) {
28376                 if (p->conf.debug) {
28377 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
28378 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
28379                                         "proxy: fdevent-hup", hctx->state);
28380                 }
28381 -               
28382 +
28383                 if (hctx->state == PROXY_STATE_CONNECT) {
28384                         /* connect() -> EINPROGRESS -> HUP */
28385 -                       
28386 +
28387                         /**
28388 -                        * what is proxy is doing if it can't reach the next hop ? 
28389 -                        * 
28390 +                        * what is proxy is doing if it can't reach the next hop ?
28391 +                        *
28392                          */
28393 -                       
28394 +
28395                         proxy_connection_close(srv, hctx);
28396                         joblist_append(srv, con);
28397 -                       
28398 +
28399                         con->http_status = 503;
28400                         con->mode = DIRECT;
28401 -                       
28402 +
28403                         return HANDLER_FINISHED;
28404                 }
28405  
28406 @@ -1038,13 +1013,13 @@
28407                 joblist_append(srv, con);
28408         } else if (revents & FDEVENT_ERR) {
28409                 /* kill all connections to the proxy process */
28410 -               
28411 +
28412                 log_error_write(srv, __FILE__, __LINE__, "sd", "proxy-FDEVENT_ERR, but no HUP", revents);
28413  
28414                 joblist_append(srv, con);
28415                 proxy_connection_close(srv, hctx);
28416         }
28417 -       
28418 +
28419         return HANDLER_FINISHED;
28420  }
28421  
28422 @@ -1058,44 +1033,48 @@
28423         buffer *fn;
28424         data_array *extension = NULL;
28425         size_t path_info_offset;
28426 -       
28427 +       data_integer *last_used_backend;
28428 +       data_proxy *host = NULL;
28429 +       handler_ctx *hctx = NULL;
28430 +
28431 +       array *backends = NULL;
28432 +
28433         /* Possibly, we processed already this request */
28434         if (con->file_started == 1) return HANDLER_GO_ON;
28435 -       
28436 +
28437         mod_proxy_patch_connection(srv, con, p);
28438 -       
28439 +
28440         fn = con->uri.path;
28441  
28442         if (fn->used == 0) {
28443                 return HANDLER_ERROR;
28444         }
28445 -       
28446 +
28447         s_len = fn->used - 1;
28448 -       
28449 -       
28450 +
28451         path_info_offset = 0;
28452  
28453 -       if (p->conf.debug) {    
28454 +       if (p->conf.debug) {
28455                 log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - start");
28456         }
28457  
28458         /* check if extension matches */
28459         for (k = 0; k < p->conf.extensions->used; k++) {
28460                 size_t ct_len;
28461 -               
28462 +
28463                 extension = (data_array *)p->conf.extensions->data[k];
28464 -               
28465 +
28466                 if (extension->key->used == 0) continue;
28467 -               
28468 +
28469                 ct_len = extension->key->used - 1;
28470 -               
28471 +
28472                 if (s_len < ct_len) continue;
28473 -               
28474 +
28475                 /* check extension in the form "/proxy_pattern" */
28476                 if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
28477                         if (s_len > ct_len + 1) {
28478                                 char *pi_offset;
28479 -                               
28480 +
28481                                 if (0 != (pi_offset = strchr(fn->ptr + ct_len + 1, '/'))) {
28482                                         path_info_offset = pi_offset - fn->ptr;
28483                                 }
28484 @@ -1106,12 +1085,14 @@
28485                         break;
28486                 }
28487         }
28488 -       
28489 +
28490         if (k == p->conf.extensions->used) {
28491                 return HANDLER_GO_ON;
28492         }
28493  
28494 -       if (p->conf.debug) {    
28495 +       backends = extension->value;
28496 +
28497 +       if (p->conf.debug) {
28498                 log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - ext found");
28499         }
28500  
28501 @@ -1120,34 +1101,34 @@
28502                 /* hash balancing */
28503  
28504                 if (p->conf.debug) {
28505 -                       log_error_write(srv, __FILE__, __LINE__,  "sd", 
28506 -                                       "proxy - used hash balancing, hosts:", extension->value->used);
28507 +                       log_error_write(srv, __FILE__, __LINE__,  "sd",
28508 +                                       "proxy - used hash balancing, hosts:", backends->used);
28509                 }
28510  
28511 -               for (k = 0, ndx = -1, last_max = ULONG_MAX; k < extension->value->used; k++) {
28512 -                       data_proxy *host = (data_proxy *)extension->value->data[k];
28513 +               for (k = 0, ndx = -1, last_max = ULONG_MAX; k < backends->used; k++) {
28514                         unsigned long cur_max;
28515  
28516 -                       if (host->is_disabled) continue;
28517 -                       
28518 +                       data_proxy *cur = (data_proxy *)backends->data[k];
28519 +
28520 +                       if (cur->is_disabled) continue;
28521 +
28522                         cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) +
28523 -                               generate_crc32c(CONST_BUF_LEN(host->host)) + /* we can cache this */
28524 +                               generate_crc32c(CONST_BUF_LEN(cur->host)) + /* we can cache this */
28525                                 generate_crc32c(CONST_BUF_LEN(con->uri.authority));
28526 -                       
28527 +
28528                         if (p->conf.debug) {
28529 -                               log_error_write(srv, __FILE__, __LINE__,  "sbbbd", 
28530 +                               log_error_write(srv, __FILE__, __LINE__,  "sbbbd",
28531                                                 "proxy - election:",
28532                                                 con->uri.path,
28533 -                                               host->host,
28534 +                                               cur->host,
28535                                                 con->uri.authority,
28536                                                 cur_max);
28537                         }
28538  
28539 -                       if ((last_max == ULONG_MAX) || /* first round */
28540 -                           (cur_max > last_max)) {
28541 +                       if (host == NULL || (cur_max > last_max)) {
28542                                 last_max = cur_max;
28543  
28544 -                               ndx = k;
28545 +                               host = cur;
28546                         }
28547                 }
28548  
28549 @@ -1155,19 +1136,20 @@
28550         case PROXY_BALANCE_FAIR:
28551                 /* fair balancing */
28552                 if (p->conf.debug) {
28553 -                       log_error_write(srv, __FILE__, __LINE__,  "s", 
28554 +                       log_error_write(srv, __FILE__, __LINE__,  "s",
28555                                         "proxy - used fair balancing");
28556                 }
28557  
28558 -               for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) {
28559 -                       data_proxy *host = (data_proxy *)extension->value->data[k];
28560 -               
28561 -                       if (host->is_disabled) continue;
28562 -
28563 -                       if (host->usage < max_usage) {
28564 -                               max_usage = host->usage;
28565 -                       
28566 -                               ndx = k;
28567 +               /* try to find the host with the lowest load */
28568 +               for (k = 0, max_usage = 0; k < backends->used; k++) {
28569 +                       data_proxy *cur = (data_proxy *)backends->data[k];
28570 +
28571 +                       if (cur->is_disabled) continue;
28572 +
28573 +                       if (NULL == host || cur->usage < max_usage) {
28574 +                               max_usage = cur->usage;
28575 +
28576 +                               host = cur;
28577                         }
28578                 }
28579  
28580 @@ -1175,89 +1157,100 @@
28581         case PROXY_BALANCE_RR:
28582                 /* round robin */
28583                 if (p->conf.debug) {
28584 -                       log_error_write(srv, __FILE__, __LINE__,  "s", 
28585 +                       log_error_write(srv, __FILE__, __LINE__,  "s",
28586                                         "proxy - used round-robin balancing");
28587                 }
28588  
28589                 /* just to be sure */
28590 -               assert(extension->value->used < INT_MAX);
28591 -               
28592 -               for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) {
28593 -                       data_proxy *host = (data_proxy *)extension->value->data[k];
28594 -               
28595 -                       if (host->is_disabled) continue;
28596 -
28597 -                       /* first usable ndx */
28598 -                       if (max_usage == INT_MAX) {
28599 -                               max_usage = k;
28600 -                       }
28601 +               assert(backends->used < INT_MAX);
28602  
28603 -                       /* get next ndx */
28604 -                       if ((int)k > host->last_used_ndx) {
28605 -                               ndx = k;
28606 -                               host->last_used_ndx = k;
28607 +               /* send each request to another host:
28608 +                *
28609 +                * e.g.:
28610 +                *
28611 +                * if we have three hosts it is
28612 +                *
28613 +                * 1 .. 2 .. 3 .. 1 .. 2 .. 3
28614 +                *
28615 +                **/
28616  
28617 -                               break;
28618 -                       }
28619 +               /* walk through the list */
28620 +               last_used_backend = (data_integer *)array_get_element(p->conf.last_used_backends, extension->key->ptr);
28621 +
28622 +               if (NULL == last_used_backend) {
28623 +                       last_used_backend = data_integer_init();
28624 +
28625 +                       buffer_copy_string_buffer(last_used_backend->key, extension->key);
28626 +                       last_used_backend->value = 0;
28627 +
28628 +                       array_insert_unique(p->conf.last_used_backends, (data_unset *)last_used_backend);
28629 +               }
28630 +
28631 +               /* scan all but the last host to see if they are up
28632 +                * take the first running host */
28633 +               for (k = last_used_backend->value + 1; (int)(k % backends->used) != last_used_backend->value; k++) {
28634 +                       data_proxy *cur = (data_proxy *)backends->data[k % backends->used];
28635 +
28636 +                       if (cur->is_disabled) continue;
28637 +
28638 +                       host = cur;
28639 +
28640 +                       last_used_backend->value = k;
28641 +
28642 +                       break;
28643                 }
28644 -               
28645 -               /* didn't found a higher id, wrap to the start */
28646 -               if (ndx != -1 && max_usage != INT_MAX) {
28647 -                       ndx = max_usage;
28648 +
28649 +               if (NULL == host) {
28650 +                       /* we found nothing better, fallback to the last used backend
28651 +                        * and check if it is still up */
28652 +                       host = (data_proxy *)backends->data[last_used_backend->value];
28653 +
28654 +                       if (host->is_disabled) host = NULL;
28655                 }
28656  
28657                 break;
28658         default:
28659                 break;
28660         }
28661 -       
28662 -       /* found a server */
28663 -       if (ndx != -1) {
28664 -               data_proxy *host = (data_proxy *)extension->value->data[ndx];
28665 -               
28666 -               /* 
28667 -                * if check-local is disabled, use the uri.path handler 
28668 -                * 
28669 -                */
28670 -               
28671 -               /* init handler-context */
28672 -               handler_ctx *hctx;
28673 -               hctx = handler_ctx_init();
28674 -                               
28675 -               hctx->path_info_offset = path_info_offset;
28676 -               hctx->remote_conn      = con;
28677 -               hctx->plugin_data      = p;
28678 -               hctx->host             = host;
28679 -                               
28680 -               con->plugin_ctx[p->id] = hctx;
28681 -               
28682 -               host->usage++;
28683 -               
28684 -               con->mode = p->id;
28685 -               
28686 -               if (p->conf.debug) {
28687 -                       log_error_write(srv, __FILE__, __LINE__,  "sbd", 
28688 -                                       "proxy - found a host",
28689 -                                       host->host, host->port);
28690 -               }
28691  
28692 -               return HANDLER_GO_ON;
28693 -       } else {
28694 -               /* no handler found */
28695 +       /* we havn't found a host */
28696 +       if (NULL == host) {
28697                 con->http_status = 500;
28698 -               
28699 -               log_error_write(srv, __FILE__, __LINE__,  "sb", 
28700 -                               "no proxy-handler found for:", 
28701 +
28702 +               log_error_write(srv, __FILE__, __LINE__,  "sb",
28703 +                               "no proxy-handler found for:",
28704                                 fn);
28705 -               
28706 +
28707                 return HANDLER_FINISHED;
28708         }
28709 +
28710 +       /* init handler-context */
28711 +       hctx = handler_ctx_init();
28712 +
28713 +       hctx->path_info_offset = path_info_offset;
28714 +       hctx->remote_conn      = con;
28715 +       hctx->plugin_data      = p;
28716 +       hctx->host             = host;
28717 +
28718 +       con->plugin_ctx[p->id] = hctx;
28719 +
28720 +       host->usage++;
28721 +
28722 +       /* we handle this request */
28723 +       con->mode = p->id;
28724 +
28725 +       if (p->conf.debug) {
28726 +               log_error_write(srv, __FILE__, __LINE__,  "sbd",
28727 +                               "proxy - found a host",
28728 +                               host->host, host->port);
28729 +       }
28730 +
28731         return HANDLER_GO_ON;
28732  }
28733  
28734  static handler_t mod_proxy_connection_close_callback(server *srv, connection *con, void *p_d) {
28735         plugin_data *p = p_d;
28736 -       
28737 +
28738         proxy_connection_close(srv, con->plugin_ctx[p->id]);
28739  
28740         return HANDLER_GO_ON;
28741 @@ -1276,11 +1269,11 @@
28742                 size_t i, n, k;
28743                 for (i = 0; i < srv->config_context->used; i++) {
28744                         plugin_config *s = p->config_storage[i];
28745 -                       
28746 -                       if (!s) continue; 
28747 +
28748 +                       if (!s) continue;
28749  
28750                         /* get the extensions for all configs */
28751 -                       
28752 +
28753                         for (k = 0; k < s->extensions->used; k++) {
28754                                 data_array *extension = (data_array *)s->extensions->data[k];
28755  
28756 @@ -1290,8 +1283,8 @@
28757  
28758                                         if (!host->is_disabled ||
28759                                             srv->cur_ts - host->disable_ts < 5) continue;
28760 -                       
28761 -                                       log_error_write(srv, __FILE__, __LINE__,  "sbd", 
28762 +
28763 +                                       log_error_write(srv, __FILE__, __LINE__,  "sbd",
28764                                                         "proxy - re-enabled:",
28765                                                         host->host, host->port);
28766  
28767 @@ -1317,8 +1310,8 @@
28768         p->handle_uri_clean        = mod_proxy_check_extension;
28769         p->handle_subrequest       = mod_proxy_handle_subrequest;
28770         p->handle_trigger          = mod_proxy_trigger;
28771 -       
28772 +
28773         p->data         = NULL;
28774 -       
28775 +
28776         return 0;
28777  }
28778 --- ../lighttpd-1.4.11/src/mod_proxy_core.c     1970-01-01 03:00:00.000000000 +0300
28779 +++ lighttpd-1.4.12/src/mod_proxy_core.c        2006-07-18 13:03:40.000000000 +0300
28780 @@ -0,0 +1,1451 @@
28781 +#include <string.h>
28782 +#include <stdlib.h>
28783 +#include <fcntl.h>
28784 +#include <errno.h>
28785 +
28786 +#include "buffer.h"
28787 +#include "array.h"
28788 +#include "log.h"
28789 +
28790 +#include "base.h"
28791 +#include "plugin.h"
28792 +#include "joblist.h"
28793 +#include "sys-files.h"
28794 +#include "inet_ntop_cache.h"
28795 +#include "http_resp.h"
28796 +#include "http_chunk.h"
28797 +#include "crc32.h"
28798 +
28799 +#include "mod_proxy_core_pool.h"       
28800 +#include "mod_proxy_core_backend.h"
28801 +#include "mod_proxy_core_backlog.h"
28802 +
28803 +typedef enum {
28804 +       PROXY_PROTOCOL_UNSET,
28805 +       PROXY_PROTOCOL_HTTP,
28806 +       PROXY_PROTOCOL_HTTPS,
28807 +       PROXY_PROTOCOL_FASTCGI,
28808 +       PROXY_PROTOCOL_SCGI
28809 +} proxy_protocol_t;
28810 +
28811 +typedef struct {
28812 +       proxy_backends *backends;
28813 +
28814 +       proxy_backlog *backlog;
28815 +
28816 +       int debug;
28817 +
28818 +       proxy_balance_t balancer;
28819 +       proxy_protocol_t protocol;
28820 +} plugin_config;
28821 +
28822 +typedef struct {
28823 +       PLUGIN_DATA;
28824 +
28825 +       http_resp *resp;
28826 +
28827 +       array *possible_balancers;
28828 +       array *possible_protocols;
28829 +
28830 +       /* for parsing only */
28831 +       array *backends_arr;
28832 +       buffer *protocol_buf;
28833 +       buffer *balance_buf;
28834 +
28835 +       plugin_config **config_storage;
28836 +
28837 +       plugin_config conf;
28838 +} plugin_data;
28839 +
28840 +int array_insert_int(array *a, const char *key, int val) {
28841 +       data_integer *di;
28842 +
28843 +       if (NULL == (di = (data_integer *)array_get_unused_element(a, TYPE_INTEGER))) {
28844 +               di = data_integer_init();
28845 +       }
28846 +
28847 +       buffer_copy_string(di->key, key);
28848 +       di->value = val;
28849 +       array_insert_unique(a, (data_unset *)di);
28850 +
28851 +       return 0;
28852 +}
28853 +
28854 +INIT_FUNC(mod_proxy_core_init) {
28855 +       plugin_data *p;
28856 +
28857 +       p = calloc(1, sizeof(*p));
28858 +
28859 +       /* create some backends as long as we don't have the config-parser */
28860 +
28861 +       p->possible_balancers = array_init();
28862 +       array_insert_int(p->possible_balancers, "fair", PROXY_BALANCE_FAIR);
28863 +       array_insert_int(p->possible_balancers, "hash", PROXY_BALANCE_RR);
28864 +       array_insert_int(p->possible_balancers, "round-robin", PROXY_BALANCE_HASH);
28865 +
28866 +       p->possible_protocols = array_init();
28867 +       array_insert_int(p->possible_protocols, "http", PROXY_PROTOCOL_HTTP);
28868 +       array_insert_int(p->possible_protocols, "fastcgi", PROXY_PROTOCOL_FASTCGI);
28869 +       array_insert_int(p->possible_protocols, "scgi", PROXY_PROTOCOL_SCGI);
28870 +       array_insert_int(p->possible_protocols, "https", PROXY_PROTOCOL_HTTPS);
28871 +
28872 +       p->balance_buf = buffer_init();
28873 +       p->protocol_buf = buffer_init();
28874 +       p->backends_arr = array_init();
28875 +
28876 +       p->resp = http_response_init();
28877 +
28878 +       return p;
28879 +}
28880 +
28881 +FREE_FUNC(mod_proxy_core_free) {
28882 +       plugin_data *p = p_d;
28883 +
28884 +       if (!p) return HANDLER_GO_ON;
28885 +
28886 +       if (p->config_storage) {
28887 +               size_t i;
28888 +               for (i = 0; i < srv->config_context->used; i++) {
28889 +                       plugin_config *s = p->config_storage[i];
28890 +
28891 +                       if (!s) continue;
28892 +
28893 +                       proxy_backends_free(s->backends);
28894 +                       proxy_backlog_free(s->backlog);
28895 +
28896 +
28897 +                       free(s);
28898 +               }
28899 +               free(p->config_storage);
28900 +       }
28901 +
28902 +       array_free(p->possible_protocols);
28903 +       array_free(p->possible_balancers);
28904 +       array_free(p->backends_arr);
28905 +
28906 +       buffer_free(p->balance_buf);
28907 +       buffer_free(p->protocol_buf);
28908 +       
28909 +       http_response_free(p->resp);
28910 +
28911 +       free(p);
28912 +
28913 +       return HANDLER_GO_ON;
28914 +}
28915 +
28916 +SETDEFAULTS_FUNC(mod_proxy_core_set_defaults) {
28917 +       plugin_data *p = p_d;
28918 +       size_t i, j;
28919 +
28920 +       config_values_t cv[] = {
28921 +               { "proxy-core.backends",       NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
28922 +               { "proxy-core.debug",          NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
28923 +               { "proxy-core.balancer",       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 2 */
28924 +               { "proxy-core.protocol",       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 3 */
28925 +               { NULL,                        NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
28926 +       };
28927 +
28928 +       p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
28929 +
28930 +       for (i = 0; i < srv->config_context->used; i++) {
28931 +               plugin_config *s;
28932 +               array *ca;
28933 +               proxy_backend *backend;
28934 +
28935 +               array_reset(p->backends_arr);
28936 +               buffer_reset(p->balance_buf);
28937 +               buffer_reset(p->protocol_buf);
28938 +
28939 +               s = malloc(sizeof(plugin_config));
28940 +               s->debug     = 0;
28941 +               s->balancer  = PROXY_BALANCE_UNSET;
28942 +               s->protocol  = PROXY_PROTOCOL_UNSET;
28943 +               s->backends  = proxy_backends_init();
28944 +               s->backlog   = proxy_backlog_init();
28945 +
28946 +               cv[0].destination = p->backends_arr;
28947 +               cv[1].destination = &(s->debug);
28948 +               cv[2].destination = p->balance_buf; /* parse into a constant */
28949 +               cv[3].destination = p->protocol_buf; /* parse into a constant */
28950 +
28951 +               buffer_reset(p->balance_buf);
28952 +
28953 +               p->config_storage[i] = s;
28954 +               ca = ((data_config *)srv->config_context->data[i])->value;
28955 +
28956 +               if (0 != config_insert_values_global(srv, ca, cv)) {
28957 +                       return HANDLER_ERROR;
28958 +               }
28959 +
28960 +               if (!buffer_is_empty(p->balance_buf)) {
28961 +                       data_integer *di;
28962 +                       
28963 +                       if (NULL == (di = (data_integer *)array_get_element(p->possible_balancers, BUF_STR(p->balance_buf)))) {
28964 +                               ERROR("proxy.balance has to be on of 'fair', 'round-robin', 'hash', got %s", BUF_STR(p->balance_buf));
28965 +
28966 +                               return HANDLER_ERROR;
28967 +                       }
28968 +
28969 +                       s->balancer = di->value;
28970 +               }
28971 +
28972 +               if (!buffer_is_empty(p->protocol_buf)) {
28973 +                       data_integer *di;
28974 +                       
28975 +                       if (NULL == (di = (data_integer *)array_get_element(p->possible_protocols, BUF_STR(p->protocol_buf)))) {
28976 +                               ERROR("proxy.balance has to be on of 'fair', 'round-robin', 'hash', got %s", BUF_STR(p->protocol_buf));
28977 +
28978 +                               return HANDLER_ERROR;
28979 +                       }
28980 +
28981 +                       s->protocol = di->value;
28982 +               }
28983 +
28984 +               backend = proxy_backend_init();
28985 +
28986 +               /* check if the backends have a valid host-name */
28987 +               for (j = 0; j < p->backends_arr->used; j++) {
28988 +                       data_string *ds = (data_string *)p->backends_arr->data[j];
28989 +
28990 +                       /* the values should be ips or hostnames */
28991 +                       if (0 != proxy_address_pool_add_string(backend->address_pool, ds->value)) {
28992 +                               return HANDLER_ERROR;
28993 +                       }
28994 +               }
28995 +
28996 +               proxy_backends_add(s->backends, backend);
28997 +       }
28998 +
28999 +       return HANDLER_GO_ON;
29000 +}
29001 +
29002 +
29003 +typedef enum {
29004 +       PROXY_STATE_UNSET,
29005 +       PROXY_STATE_CONNECTING,
29006 +       PROXY_STATE_CONNECTED,
29007 +       PROXY_STATE_WRITE_REQUEST_HEADER,
29008 +       PROXY_STATE_WRITE_REQUEST_BODY,
29009 +       PROXY_STATE_READ_RESPONSE_HEADER,
29010 +       PROXY_STATE_READ_RESPONSE_BODY
29011 +} proxy_state_t;
29012 +
29013 +typedef struct {
29014 +       proxy_connection *proxy_con;
29015 +       proxy_backend *proxy_backend;
29016 +
29017 +       connection *remote_con;
29018 +
29019 +       array *request_headers;
29020 +
29021 +       int is_chunked;
29022 +       
29023 +       /**
29024 +        * chunkqueues
29025 +        * - the encoded_rb is the raw network stuff
29026 +        * - the rb is filtered through the stream decoder
29027 +        *
29028 +        * - wb is the normal bytes stream
29029 +        * - encoded_wb is encoded for the network by the stream encoder
29030 +        */
29031 +       chunkqueue *recv;
29032 +       chunkqueue *recv_raw;
29033 +       chunkqueue *send_raw;
29034 +       chunkqueue *send;
29035 +       
29036 +       off_t bytes_read;
29037 +       off_t content_length;
29038 +
29039 +       proxy_state_t state;
29040 +} proxy_session;
29041 +
29042 +proxy_session *proxy_session_init(void) {
29043 +       proxy_session *sess;
29044 +
29045 +       sess = calloc(1, sizeof(*sess));
29046 +
29047 +       sess->state = PROXY_STATE_UNSET;
29048 +       sess->request_headers = array_init();
29049 +
29050 +       sess->recv = chunkqueue_init();
29051 +       sess->recv_raw = chunkqueue_init();
29052 +       sess->send_raw = chunkqueue_init();
29053 +       sess->send = chunkqueue_init();
29054 +
29055 +       sess->is_chunked = 0;
29056 +
29057 +       return sess;
29058 +}
29059 +
29060 +void proxy_session_free(proxy_session *sess) {
29061 +       if (!sess) return;
29062 +
29063 +       array_free(sess->request_headers);
29064 +
29065 +       chunkqueue_free(sess->recv);
29066 +       chunkqueue_free(sess->recv_raw);
29067 +       chunkqueue_free(sess->send_raw);
29068 +       chunkqueue_free(sess->send);
29069 +
29070 +       free(sess);
29071 +}
29072 +
29073 +handler_t proxy_connection_connect(proxy_connection *con) {
29074 +       int fd;
29075 +       
29076 +       if (-1 == (fd = socket(con->address->addr.plain.sa_family, SOCK_STREAM, 0))) {
29077 +       }
29078 +
29079 +       fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
29080 +
29081 +       con->sock->fd = fd;
29082 +       con->sock->fde_ndx = -1;
29083 +       con->sock->type = IOSOCKET_TYPE_SOCKET;
29084 +
29085 +       if (-1 == connect(fd, &(con->address->addr.plain), sizeof(con->address->addr))) {
29086 +               switch(errno) {
29087 +               case EINPROGRESS:
29088 +               case EALREADY:
29089 +               case EINTR:
29090 +                       return HANDLER_WAIT_FOR_EVENT;
29091 +               default:
29092 +                       close(fd);
29093 +                       con->sock->fd = -1;
29094 +
29095 +                       return HANDLER_ERROR;
29096 +               }
29097 +       }
29098 +
29099 +       return HANDLER_GO_ON;
29100 +}
29101 +
29102 +/**
29103 + * event-handler for idling connections
29104 + *
29105 + * unused (idling) keep-alive connections are not bound to a session
29106 + * and need their own event-handler 
29107 + *
29108 + * if the connection closes (we get a FDEVENT_IN), close our side too and 
29109 + * let the trigger-func handle the cleanup
29110 + *
29111 + * @see proxy_trigger
29112 + */
29113 +
29114 +
29115 +static handler_t proxy_handle_fdevent_idle(void *s, void *ctx, int revents) {
29116 +       server      *srv  = (server *)s;
29117 +       proxy_connection *proxy_con = ctx;
29118 +
29119 +       if (revents & FDEVENT_IN) {
29120 +               switch (proxy_con->state) {
29121 +               case PROXY_CONNECTION_STATE_IDLE:
29122 +                       proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29123 +
29124 +                       /* close + unregister have to be in the same call,
29125 +                        * otherwise we get a events for a re-opened fd */
29126 +
29127 +                       fdevent_event_del(srv->ev, proxy_con->sock);
29128 +
29129 +                       break;
29130 +               case PROXY_CONNECTION_STATE_CLOSED:
29131 +                       /* poll() is state-driven, we will get events as long as it isn't disabled
29132 +                        * the close() above should disable the events too */
29133 +                       ERROR("%s", "hurry up buddy, I got another event for a closed idle-connection");
29134 +                       break;
29135 +               default:
29136 +                       ERROR("invalid connection state: %d, should be idle", proxy_con->state);
29137 +                       break;
29138 +               }
29139 +       }
29140 +
29141 +       return HANDLER_GO_ON;
29142 +}
29143 +
29144 +void chunkqueue_skip(chunkqueue *cq, off_t skip) {
29145 +       chunk *c;
29146 +
29147 +       for (c = cq->first; c && skip; c = c->next) {
29148 +               if (skip > c->mem->used - c->offset - 1) {
29149 +                       skip -= c->mem->used - c->offset - 1;
29150 +               } else {
29151 +                       c->offset += skip;
29152 +                       skip = 0;
29153 +               }
29154 +       }
29155 +
29156 +       return;
29157 +}
29158 +
29159 +int proxy_http_stream_decoder(server *srv, proxy_session *sess, chunkqueue *raw, chunkqueue *decoded) {
29160 +       chunk *c;
29161 +
29162 +       if (sess->is_chunked) {
29163 +               do {
29164 +                       /* the start should always be a chunk-length */
29165 +                       off_t chunk_len = 0;
29166 +                       char *err = NULL;
29167 +                       int chunklen_strlen = 0;
29168 +                       char ch;
29169 +                       off_t we_have = 0, we_need = 0;
29170 +
29171 +                       c = raw->first;
29172 +
29173 +                       chunk_len = strtol(BUF_STR(c->mem) + c->offset, &err, 16);
29174 +                       if (!(*err == ' ' || *err == '\r' || *err == ';')) {
29175 +                               if (*err == '\0') {
29176 +                                       /* we just need more data */
29177 +                                       return 0;
29178 +                               }
29179 +                               return -1;
29180 +                       }
29181 +
29182 +                       if (chunk_len < 0) {
29183 +                               ERROR("chunk_len is negative: %Ld", chunk_len);
29184 +                               return -1;
29185 +                       }
29186 +
29187 +                       chunklen_strlen = err - (BUF_STR(c->mem) + c->offset);
29188 +                       chunklen_strlen++; /* skip the err-char */ 
29189 +                       
29190 +                       do {
29191 +                               ch = BUF_STR(c->mem)[c->offset + chunklen_strlen];
29192 +       
29193 +                               switch (ch) {
29194 +                               case '\n':
29195 +                               case '\0':
29196 +                                       /* bingo, chunk-header is finished */
29197 +                                       break;
29198 +                               default:
29199 +                                       break;
29200 +                               }
29201 +                               chunklen_strlen++;
29202 +                       } while (ch != '\n' && c != '\0');
29203 +
29204 +                       if (ch != '\n') {
29205 +                               ERROR("%s", "missing the CRLF");
29206 +                               return 0;
29207 +                       }
29208 +
29209 +                       we_need = chunk_len + chunklen_strlen + 2;
29210 +                       /* do we have the full chunk ? */
29211 +                       for (c = raw->first; c; c = c->next) {
29212 +                               we_have += c->mem->used - 1 - c->offset;
29213 +
29214 +                               /* we have enough, jump out */
29215 +                               if (we_have > we_need) break;
29216 +                       }
29217 +
29218 +                       /* get more data */
29219 +                       if (we_have < we_need) {
29220 +                               return 0;
29221 +                       }
29222 +
29223 +                       /* skip the chunk-header */
29224 +                       chunkqueue_skip(raw, chunklen_strlen);
29225 +
29226 +                       /* final chunk */
29227 +                       if (chunk_len == 0) {
29228 +                               chunkqueue_skip(raw, 2);
29229 +
29230 +                               return 1;
29231 +                       }
29232 +
29233 +                       /* we have enough, copy the data */     
29234 +                       for (c = raw->first; c && chunk_len; c = c->next) {
29235 +                               off_t we_want = 0;
29236 +                               buffer *b = chunkqueue_get_append_buffer(decoded);
29237 +
29238 +                               we_want = chunk_len > (c->mem->used - c->offset - 1) ? c->mem->used - c->offset - 1: chunk_len;
29239 +
29240 +                               buffer_copy_string_len(b, c->mem->ptr + c->offset, we_want);
29241 +
29242 +                               c->offset += we_want;
29243 +                               chunk_len -= we_want;
29244 +                       }
29245 +
29246 +                       /* skip the \r\n */
29247 +                       chunkqueue_skip(raw, 2);
29248 +
29249 +                       /* we are done, give the connection to someone else */
29250 +                       chunkqueue_remove_finished_chunks(raw);
29251 +               } while (1);
29252 +       } else {
29253 +               /* no chunked encoding, ok, perhaps a content-length ? */
29254 +
29255 +               TRACE("content-lenght: %d", sess->content_length);
29256 +
29257 +               chunkqueue_remove_finished_chunks(raw);
29258 +               for (c = raw->first; c; c = c->next) {
29259 +                       buffer *b;
29260 +
29261 +                       if (c->mem->used == 0) continue;
29262 +                      
29263 +                       b = chunkqueue_get_append_buffer(decoded);
29264 +
29265 +                       sess->bytes_read += c->mem->used - c->offset - 1;
29266 +
29267 +                       buffer_copy_string_len(b, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
29268 +
29269 +                       c->offset = c->mem->used - 1;
29270 +
29271 +                       if (sess->bytes_read == sess->content_length) {
29272 +                               break;
29273 +                       }
29274 +
29275 +               }
29276 +               if (sess->bytes_read == sess->content_length) {
29277 +                       return 1; /* finished */
29278 +               }
29279 +       }
29280 +
29281 +       return 0;
29282 +}
29283 +/* don't call any proxy functions directly */
29284 +static handler_t proxy_handle_fdevent(void *s, void *ctx, int revents) {
29285 +       server      *srv  = (server *)s;
29286 +       proxy_session *sess = ctx;
29287 +
29288 +       if (revents & FDEVENT_OUT) {
29289 +               switch (sess->state) {
29290 +               case PROXY_STATE_CONNECTING: /* delayed connect */
29291 +               case PROXY_STATE_WRITE_REQUEST_HEADER:
29292 +               case PROXY_STATE_WRITE_REQUEST_BODY:
29293 +                       /* we are still connection */
29294 +
29295 +                       joblist_append(srv, sess->remote_con);
29296 +                       break;
29297 +               default:
29298 +                       ERROR("oops, unexpected state for fdevent-out %d", sess->state);
29299 +                       break;
29300 +               }
29301 +       } else if (revents & FDEVENT_IN) {
29302 +               chunk *c;
29303 +
29304 +               switch (sess->state) {
29305 +               case PROXY_STATE_READ_RESPONSE_HEADER:
29306 +                       /* call our header parser */
29307 +                       joblist_append(srv, sess->remote_con);
29308 +                       break;
29309 +               case PROXY_STATE_READ_RESPONSE_BODY:
29310 +                       /* we should be in the WRITE state now, 
29311 +                        * just read in the content and forward it to the outgoing connection
29312 +                        * */
29313 +
29314 +                       chunkqueue_remove_finished_chunks(sess->recv_raw);
29315 +                       switch (srv->network_backend_read(srv, sess->remote_con, sess->proxy_con->sock, sess->recv_raw)) {
29316 +                       case NETWORK_STATUS_CONNECTION_CLOSE:
29317 +                               fdevent_event_del(srv->ev,sess->proxy_con->sock);
29318 +
29319 +                               /* the connection is gone
29320 +                                * make the connect */
29321 +                               sess->remote_con->file_finished = 1;
29322 +                               sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29323 +
29324 +                       case NETWORK_STATUS_SUCCESS:
29325 +                               /* read even more, do we have all the content */
29326 +
29327 +                               /* how much do we want to read ? */
29328 +                               
29329 +                               /* call stream-decoder (HTTP-chunked, FastCGI, ... ) */
29330 +
29331 +                               switch (proxy_http_stream_decoder(srv, sess, sess->recv_raw, sess->recv)) {
29332 +                               case 0:
29333 +                                       /* need more */
29334 +                                       break;
29335 +                               case -1:
29336 +                                       /* error */
29337 +                                       break;
29338 +                               case 1:
29339 +                                       /* we are done */
29340 +                                       sess->remote_con->file_finished = 1;
29341 +
29342 +                                       break;
29343 +                               }
29344 +                               chunkqueue_remove_finished_chunks(sess->recv_raw);
29345 +
29346 +                               /* copy the content to the next cq */
29347 +                               for (c = sess->recv->first; c; c = c->next) {
29348 +                                       if (c->mem->used == 0) continue;
29349 +
29350 +                                       http_chunk_append_mem(srv, sess->remote_con, c->mem->ptr + c->offset, c->mem->used - c->offset);
29351 +       
29352 +                                       c->offset = c->mem->used - 1;
29353 +
29354 +                               }
29355 +                               chunkqueue_remove_finished_chunks(sess->recv);
29356 +
29357 +                               if (sess->remote_con->file_finished) {
29358 +                                       /* send final HTTP-Chunk packet */
29359 +                                       http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
29360 +                               }
29361 +                               
29362 +                               break;
29363 +                       default:
29364 +                               ERROR("%s", "oops, we failed to read");
29365 +                               break;
29366 +                       }
29367 +
29368 +                       joblist_append(srv, sess->remote_con);
29369 +                       break;
29370 +               default:
29371 +                       ERROR("oops, unexpected state for fdevent-in %d", sess->state);
29372 +                       break;
29373 +               }
29374 +       }
29375 +
29376 +       if (revents & FDEVENT_HUP) {
29377 +               /* someone closed our connection */
29378 +               switch (sess->state) {
29379 +               case PROXY_STATE_CONNECTING:
29380 +                       /* let the getsockopt() catch this */
29381 +                       joblist_append(srv, sess->remote_con);
29382 +                       break;
29383 +               default:
29384 +                       ERROR("oops, unexpected state for fdevent-hup %d", sess->state);
29385 +                       break;
29386 +               }
29387 +       }
29388 +
29389 +       return HANDLER_GO_ON;
29390 +}
29391 +
29392 +/**
29393 + * generate a HTTP/1.1 proxy request from the set of request-headers
29394 + *
29395 + * TODO: this is HTTP-proxy specific and will be moved moved into a separate backed
29396 + *
29397 + */
29398 +int proxy_get_request_chunk(server *srv, connection *con, proxy_session *sess, chunkqueue *cq) {
29399 +       buffer *b;
29400 +       size_t i;
29401 +
29402 +       b = chunkqueue_get_append_buffer(cq);
29403 +
29404 +       /* request line */
29405 +       buffer_copy_string(b, get_http_method_name(con->request.http_method));
29406 +       BUFFER_APPEND_STRING_CONST(b, " ");
29407 +
29408 +       buffer_append_string_buffer(b, con->request.uri);
29409 +       BUFFER_APPEND_STRING_CONST(b, " HTTP/1.1\r\n");
29410 +
29411 +       for (i = 0; i < sess->request_headers->used; i++) {
29412 +               data_string *ds;
29413 +
29414 +               ds = (data_string *)sess->request_headers->data[i];
29415 +
29416 +               buffer_append_string_buffer(b, ds->key);
29417 +               BUFFER_APPEND_STRING_CONST(b, ": ");
29418 +               buffer_append_string_buffer(b, ds->value);
29419 +               BUFFER_APPEND_STRING_CONST(b, "\r\n");
29420 +       }
29421 +
29422 +       BUFFER_APPEND_STRING_CONST(b, "\r\n");
29423 +
29424 +       return 0;
29425 +}
29426 +
29427 +void proxy_set_header(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
29428 +       data_string *ds_dst;
29429 +
29430 +       if (NULL == (ds_dst = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
29431 +               ds_dst = data_string_init();
29432 +       }
29433 +
29434 +       buffer_copy_string_len(ds_dst->key, key, key_len);
29435 +       buffer_copy_string_len(ds_dst->value, value, val_len);
29436 +       array_insert_unique(hdrs, (data_unset *)ds_dst);
29437 +}
29438 +
29439 +void proxy_append_header(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
29440 +       data_string *ds_dst;
29441 +
29442 +       if (NULL == (ds_dst = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
29443 +               ds_dst = data_string_init();
29444 +       }
29445 +
29446 +       buffer_copy_string_len(ds_dst->key, key, key_len);
29447 +       buffer_append_string_len(ds_dst->value, value, val_len);
29448 +       array_insert_unique(hdrs, (data_unset *)ds_dst);
29449 +}
29450 +
29451 +
29452 +/**
29453 + * build the request-header array and call the backend specific request formater
29454 + * to fill the chunkqueue
29455 + */
29456 +int proxy_get_request_header(server *srv, connection *con, proxy_session *sess) {
29457 +       /* request line */
29458 +       const char *remote_ip;
29459 +       size_t i;
29460 +
29461 +       remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
29462 +       proxy_append_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-For"), remote_ip, strlen(remote_ip));
29463 +
29464 +       /* http_host is NOT is just a pointer to a buffer
29465 +        * which is NULL if it is not set */
29466 +       if (con->request.http_host &&
29467 +           !buffer_is_empty(con->request.http_host)) {
29468 +               proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Host"), CONST_BUF_LEN(con->request.http_host));
29469 +       }
29470 +       if (con->conf.is_ssl) {
29471 +               proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-Proto"), CONST_STR_LEN("https"));
29472 +       } else {
29473 +               proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-Proto"), CONST_STR_LEN("http"));
29474 +       }
29475 +
29476 +       /* request header */
29477 +       for (i = 0; i < con->request.headers->used; i++) {
29478 +               data_string *ds;
29479 +
29480 +               ds = (data_string *)con->request.headers->data[i];
29481 +
29482 +               if (buffer_is_empty(ds->value) || buffer_is_empty(ds->key)) continue;
29483 +
29484 +               if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
29485 +               if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Keep-Alive"))) continue;
29486 +
29487 +               proxy_set_header(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
29488 +       }
29489 +
29490 +       proxy_get_request_chunk(srv, con, sess, sess->send_raw);
29491 +
29492 +       return 0;
29493 +}
29494 +
29495 +/**
29496 + * parse the response header
29497 + *
29498 + * NOTE: this can be used by all backends as they all send a HTTP-Response a clean block
29499 + * - fastcgi needs some decoding for the protocol
29500 + */
29501 +parse_status_t proxy_parse_response_header(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq) {
29502 +       int have_content_length = 0;
29503 +       size_t i;
29504 +
29505 +       http_response_reset(p->resp);
29506 +       
29507 +       switch (http_response_parse_cq(cq, p->resp)) {
29508 +       case PARSE_ERROR:
29509 +               /* parsing failed */
29510 +
29511 +               return PARSE_ERROR;
29512 +       case PARSE_NEED_MORE:
29513 +               return PARSE_NEED_MORE;
29514 +       case PARSE_SUCCESS:
29515 +               con->http_status = p->resp->status;
29516 +
29517 +               chunkqueue_remove_finished_chunks(cq);
29518 +
29519 +               sess->content_length = -1;
29520 +
29521 +               /* copy the http-headers */
29522 +               for (i = 0; i < p->resp->headers->used; i++) {
29523 +                       const char *ign[] = { "Status", "Connection", NULL };
29524 +                       size_t j;
29525 +                       data_string *ds;
29526 +
29527 +                       data_string *header = (data_string *)p->resp->headers->data[i];
29528 +
29529 +                       /* some headers are ignored by default */
29530 +                       for (j = 0; ign[j]; j++) {
29531 +                               if (0 == strcasecmp(ign[j], header->key->ptr)) break;
29532 +                       }
29533 +                       if (ign[j]) continue;
29534 +
29535 +                       if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
29536 +                               /* CGI/1.1 rev 03 - 7.2.1.2 */
29537 +                               if (con->http_status == 0) con->http_status = 302;
29538 +                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
29539 +                               have_content_length = 1;
29540 +
29541 +                               sess->content_length = strtol(header->value->ptr, NULL, 10);
29542 +
29543 +                               if (sess->content_length < 0) {
29544 +                                       return PARSE_ERROR;
29545 +                               }
29546 +                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Transfer-Encoding"))) {
29547 +                               if (strstr(header->value->ptr, "chunked")) {
29548 +                                       sess->is_chunked = 1;
29549 +                               }
29550 +                               /* ignore the header */
29551 +                               continue;
29552 +                       }
29553 +                       
29554 +                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
29555 +                               ds = data_response_init();
29556 +                       }
29557 +                       buffer_copy_string_buffer(ds->key, header->key);
29558 +                       buffer_copy_string_buffer(ds->value, header->value);
29559 +
29560 +                       array_insert_unique(con->response.headers, (data_unset *)ds);
29561 +               }
29562 +
29563 +               /* does the client allow us to send chunked encoding ? */
29564 +               if (con->request.http_version == HTTP_VERSION_1_1 &&
29565 +                   !have_content_length) {
29566 +                       con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
29567 +               }
29568 +
29569 +               break;
29570 +       }
29571 +
29572 +       return PARSE_SUCCESS; /* we have a full header */
29573 +}
29574 +
29575 +/* we are event-driven
29576 + * 
29577 + * the first entry is connect() call, if the doesn't need a event 
29578 + *
29579 + * a bit boring
29580 + * - connect (+ delayed connect)
29581 + * - write header + content
29582 + * - read header + content
29583 + *
29584 + * as soon as have read the response header we switch con->file_started and return HANDLER_GO_ON to
29585 + * tell the core we are ready to stream out the content.
29586 + *  */
29587 +handler_t proxy_state_engine(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
29588 +       /* do we have a connection ? */
29589 +
29590 +       if (sess->state == PROXY_STATE_UNSET) {
29591 +               /* we are not started yet */
29592 +               switch(proxy_connection_connect(sess->proxy_con)) {
29593 +               case HANDLER_WAIT_FOR_EVENT:
29594 +                       /* waiting on the connect call */
29595 +
29596 +                       fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
29597 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_OUT);
29598 +
29599 +                       sess->state = PROXY_STATE_CONNECTING;
29600 +                       sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTING;
29601 +                       
29602 +                       return HANDLER_WAIT_FOR_EVENT;
29603 +               case HANDLER_GO_ON:
29604 +                       /* we are connected */
29605 +                       sess->state = PROXY_STATE_CONNECTED;
29606 +                       sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
29607 +                       fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
29608 +
29609 +                       break;
29610 +               case HANDLER_ERROR:
29611 +               default:
29612 +                       /* not good, something failed */
29613 +                       return HANDLER_ERROR;
29614 +               
29615 +               }
29616 +       } else if (sess->state == PROXY_STATE_CONNECTING) {
29617 +               int socket_error;
29618 +               socklen_t socket_error_len = sizeof(socket_error);
29619 +
29620 +               fdevent_event_del(srv->ev, sess->proxy_con->sock);
29621 +
29622 +               if (0 != getsockopt(sess->proxy_con->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
29623 +                       ERROR("getsockopt failed:", strerror(errno));
29624 +
29625 +                       return HANDLER_ERROR;
29626 +               }
29627 +               if (socket_error != 0) {
29628 +                       switch (socket_error) {
29629 +                       case ECONNREFUSED:
29630 +                               /* there is no-one on the other side */
29631 +                               sess->proxy_con->address->disabled_until = srv->cur_ts + 2;
29632 +
29633 +                               TRACE("address %s refused us, disabling for 2 sec", sess->proxy_con->address->name->ptr);
29634 +                               break;
29635 +                       case EHOSTUNREACH:
29636 +                               /* there is no-one on the other side */
29637 +                               sess->proxy_con->address->disabled_until = srv->cur_ts + 60;
29638 +
29639 +                               TRACE("host %s is unreachable, disabling for 60 sec", sess->proxy_con->address->name->ptr);
29640 +                               break;
29641 +                       default:
29642 +                               sess->proxy_con->address->disabled_until = srv->cur_ts + 60;
29643 +
29644 +                               TRACE("connected finally failed: %s (%d)", strerror(socket_error), socket_error);
29645 +
29646 +                               TRACE("connect to address %s failed and I don't know why, disabling for 10 sec", sess->proxy_con->address->name->ptr);
29647 +
29648 +                               break;
29649 +                       }
29650 +
29651 +                       sess->proxy_con->address->state = PROXY_ADDRESS_STATE_DISABLED;
29652 +
29653 +                       sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29654 +                       return HANDLER_COMEBACK;
29655 +               }
29656 +
29657 +               sess->state = PROXY_STATE_CONNECTED;
29658 +               sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
29659 +       }
29660 +
29661 +       if (sess->state == PROXY_STATE_CONNECTED) {
29662 +               /* build the header */
29663 +               proxy_get_request_header(srv, con, sess);
29664 +
29665 +               sess->state = PROXY_STATE_WRITE_REQUEST_HEADER;
29666 +       }
29667 +
29668 +       switch (sess->state) {
29669 +       case PROXY_STATE_WRITE_REQUEST_HEADER:
29670 +               /* create the request-packet */ 
29671 +               fdevent_event_del(srv->ev, sess->proxy_con->sock);
29672 +
29673 +               switch (srv->network_backend_write(srv, con, sess->proxy_con->sock, sess->send_raw)) {
29674 +               case NETWORK_STATUS_SUCCESS:
29675 +                       sess->state = PROXY_STATE_WRITE_REQUEST_BODY;
29676 +                       break;
29677 +               case NETWORK_STATUS_WAIT_FOR_EVENT:
29678 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_OUT);
29679 +
29680 +                       return HANDLER_WAIT_FOR_EVENT;
29681 +               case NETWORK_STATUS_CONNECTION_CLOSE:
29682 +                       sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29683 +
29684 +                       /* this connection is closed, restart the request with a new connection */
29685 +
29686 +                       return HANDLER_COMEBACK;
29687 +               default:
29688 +                       return HANDLER_ERROR;
29689 +               }
29690 +               /* fall through */
29691 +       case PROXY_STATE_WRITE_REQUEST_BODY:
29692 +               fdevent_event_del(srv->ev, sess->proxy_con->sock);
29693 +               sess->state = PROXY_STATE_READ_RESPONSE_HEADER;
29694 +
29695 +       case PROXY_STATE_READ_RESPONSE_HEADER:
29696 +               fdevent_event_del(srv->ev, sess->proxy_con->sock);
29697 +
29698 +               chunkqueue_remove_finished_chunks(sess->recv_raw);
29699 +
29700 +               switch (srv->network_backend_read(srv, con, sess->proxy_con->sock, sess->recv_raw)) {
29701 +               case NETWORK_STATUS_SUCCESS:
29702 +                       /* we read everything from the socket, do we have a full header ? */
29703 +
29704 +                       switch (proxy_parse_response_header(srv, con, p, sess, sess->recv_raw)) {
29705 +                       case PARSE_ERROR:
29706 +                               con->http_status = 502; /* bad gateway */
29707 +
29708 +                               return HANDLER_FINISHED;
29709 +                       case PARSE_NEED_MORE:
29710 +                               /* we need more */
29711 +                               fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
29712 +
29713 +                               return HANDLER_WAIT_FOR_EVENT;
29714 +                       case PARSE_SUCCESS:
29715 +                               break;
29716 +                       default:
29717 +                               return HANDLER_ERROR;
29718 +                       }
29719 +                       
29720 +                       con->file_started = 1;
29721 +
29722 +                       sess->state = PROXY_STATE_READ_RESPONSE_BODY;
29723 +
29724 +                       /**
29725 +                        * set the event to pass the content through to the server
29726 +                        *
29727 +                        * this triggers the event-handler
29728 +                        * @see proxy_handle_fdevent
29729 +                        */
29730 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
29731 +
29732 +                       return HANDLER_GO_ON; /* tell http_response_prepare that we are done with the header */
29733 +               case NETWORK_STATUS_WAIT_FOR_EVENT:
29734 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
29735 +                       return HANDLER_WAIT_FOR_EVENT;
29736 +               case NETWORK_STATUS_CONNECTION_CLOSE:
29737 +                       if (chunkqueue_length(sess->recv_raw) == 0) {
29738 +                               /* the connection went away before we got something back */
29739 +                               sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29740 +
29741 +                               /**
29742 +                                * we might run into a 'race-condition' 
29743 +                                *
29744 +                                * 1. proxy-con is keep-alive, idling and just being closed (FDEVENT_IN) [fd=27]
29745 +                                * 2. new connection comes in, we use the idling connection [fd=14]
29746 +                                * 3. we write(), successful [to fd=27]
29747 +                                * 3. we read() ... and finally receive the close-event for the connection
29748 +                                */
29749 +
29750 +                               con->http_status = 500;
29751 +
29752 +                               ERROR("++ %s", "oops, connection got closed while we were reading from it");
29753 +                               return HANDLER_FINISHED;
29754 +                       }
29755 +
29756 +                       ERROR("%s", "conn-close after header-read");
29757 +                               
29758 +                       break;
29759 +               default:
29760 +                       ERROR("++ %s", "oops, something went wrong while reading");
29761 +                       return HANDLER_ERROR;
29762 +               }
29763 +       case PROXY_STATE_READ_RESPONSE_BODY:
29764 +               /* if we do everything right, we won't get call for this state-anymore */
29765 +
29766 +               ERROR("%s", "PROXY_STATE_READ_RESPONSE_BODY");
29767 +               
29768 +               break;
29769 +       }
29770 +
29771 +       return HANDLER_GO_ON;
29772 +}
29773 +
29774 +proxy_backend *proxy_get_backend(server *srv, connection *con, plugin_data *p, buffer *uri) {
29775 +       size_t i;
29776 +
29777 +       for (i = 0; i < p->conf.backends->used; i++) {
29778 +               proxy_backend *backend = p->conf.backends->ptr[i];
29779 +
29780 +               return backend;
29781 +       }
29782 +
29783 +       return NULL;
29784 +}
29785 +
29786 +/**
29787 + * choose a available address from the address-pool
29788 + *
29789 + * the backend has different balancers 
29790 + */
29791 +proxy_address *proxy_backend_balance(server *srv, connection *con, proxy_backend *backend) {
29792 +       size_t i;
29793 +       proxy_address_pool *address_pool = backend->address_pool;
29794 +       unsigned long last_max; /* for the HASH balancer */
29795 +       proxy_address *address = NULL, *cur_address = NULL;
29796 +       int active_addresses = 0, rand_ndx;
29797 +
29798 +       switch(backend->balancer) {
29799 +       case PROXY_BALANCE_HASH:
29800 +               /* hash balancing */
29801 +
29802 +               for (i = 0, last_max = ULONG_MAX; i < address_pool->used; i++) {
29803 +                       unsigned long cur_max;
29804 +
29805 +                       cur_address = address_pool->ptr[i];
29806 +
29807 +                       if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
29808 +
29809 +                       cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) +
29810 +                               generate_crc32c(CONST_BUF_LEN(cur_address->name)) + /* we can cache this */
29811 +                               generate_crc32c(CONST_BUF_LEN(con->uri.authority));
29812 +
29813 +                       TRACE("hash-election: %s - %s - %s: %ld", 
29814 +                                       con->uri.path->ptr,
29815 +                                       cur_address->name->ptr,
29816 +                                       con->uri.authority->ptr,
29817 +                                       cur_max);
29818 +
29819 +                       if (address == NULL || (cur_max > last_max)) {
29820 +                               last_max = cur_max;
29821 +
29822 +                               address = cur_address;
29823 +                       }
29824 +               }
29825 +
29826 +               break;
29827 +       case PROXY_BALANCE_FAIR:
29828 +               /* fair balancing */
29829 +
29830 +               for (i = 0; i < address_pool->used; i++) {
29831 +                       cur_address = address_pool->ptr[i];
29832 +
29833 +                       if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
29834 +
29835 +                       /* the address is up, use it */
29836 +
29837 +                       address = cur_address;
29838 +
29839 +                       break;
29840 +               }
29841 +
29842 +               break;
29843 +       case PROXY_BALANCE_RR:
29844 +               /* round robin */
29845 +
29846 +               /**
29847 +                * instead of real RoundRobin we just do a RandomSelect
29848 +                *
29849 +                * it is state-less and has the same distribution
29850 +                */
29851 +
29852 +               active_addresses = 0;
29853 +               
29854 +               for (i = 0; i < address_pool->used; i++) {
29855 +                       cur_address = address_pool->ptr[i];
29856 +
29857 +                       if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
29858 +
29859 +                       active_addresses++;
29860 +               }
29861 +
29862 +               rand_ndx = (int) (1.0 * active_addresses * rand()/(RAND_MAX));
29863 +       
29864 +               active_addresses = 0;
29865 +               for (i = 0; i < address_pool->used; i++) {
29866 +                       cur_address = address_pool->ptr[i];
29867 +
29868 +                       if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
29869 +
29870 +                       address = cur_address;
29871 +
29872 +                       if (rand_ndx == active_addresses++) break;
29873 +               }
29874 +
29875 +               break;
29876 +       default:
29877 +               break;
29878 +       }
29879 +
29880 +       return address;
29881 +}
29882 +
29883 +static int mod_proxy_core_patch_connection(server *srv, connection *con, plugin_data *p) {
29884 +       size_t i, j;
29885 +       plugin_config *s = p->config_storage[0];
29886 +
29887 +       /* global defaults */
29888 +       PATCH_OPTION(balancer);
29889 +       PATCH_OPTION(debug);
29890 +       PATCH_OPTION(backends);
29891 +       PATCH_OPTION(backlog);
29892 +       PATCH_OPTION(protocol);
29893 +
29894 +       /* skip the first, the global context */
29895 +       for (i = 1; i < srv->config_context->used; i++) {
29896 +               data_config *dc = (data_config *)srv->config_context->data[i];
29897 +               s = p->config_storage[i];
29898 +
29899 +               /* condition didn't match */
29900 +               if (!config_check_cond(srv, con, dc)) continue;
29901 +
29902 +               /* merge config */
29903 +               for (j = 0; j < dc->value->used; j++) {
29904 +                       data_unset *du = dc->value->data[j];
29905 +
29906 +                       if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.backends"))) {
29907 +                               PATCH_OPTION(backends);
29908 +                               PATCH_OPTION(backlog);
29909 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.debug"))) {
29910 +                               PATCH_OPTION(debug);
29911 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.balancer"))) {
29912 +                               PATCH_OPTION(balancer);
29913 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.protocol"))) {
29914 +                               PATCH_OPTION(protocol);
29915 +                       }
29916 +               }
29917 +       }
29918 +
29919 +       return 0;
29920 +}
29921 +
29922 +
29923 +SUBREQUEST_FUNC(mod_proxy_core_check_extension) {
29924 +       plugin_data *p = p_d;
29925 +       proxy_session *sess = con->plugin_ctx[p->id]; /* if this is the second round, sess is already prepared */
29926 +
29927 +       /* check if we have a matching conditional for this request */
29928 +
29929 +       if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
29930 +
29931 +       mod_proxy_core_patch_connection(srv, con, p);
29932 +
29933 +       /* 
29934 +        * 0. build session
29935 +        * 1. get a proxy connection
29936 +        * 2. create the http-request header
29937 +        * 3. stream the content to the backend 
29938 +        * 4. wait for http-response header 
29939 +        * 5. decode the response + parse the response
29940 +        * 6. stream the response-content to the client 
29941 +        * 7. kill session
29942 +        * */
29943 +
29944 +       if (!sess) {
29945 +               /* a session lives for a single request */
29946 +               sess = proxy_session_init();
29947 +
29948 +               con->plugin_ctx[p->id] = sess;
29949 +               con->mode = p->id;
29950 +
29951 +               sess->remote_con = con;
29952 +       }
29953 +
29954 +       switch (sess->state) {
29955 +       case PROXY_STATE_CONNECTING:
29956 +               /* this connections is waited 10 seconds to connect to the backend
29957 +                * and didn't got a successful connection yet, sending timeout */
29958 +               if (srv->cur_ts - con->request_start > 10) {
29959 +                       con->http_status = 504; /* gateway timeout */
29960 +
29961 +                       if (sess->proxy_con) {
29962 +                               /* if we are waiting for a proxy-connection right now, close it */
29963 +                               proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
29964 +       
29965 +                               fdevent_event_del(srv->ev, sess->proxy_con->sock);
29966 +                               fdevent_unregister(srv->ev, sess->proxy_con->sock);
29967 +
29968 +                               proxy_connection_free(sess->proxy_con);
29969 +                       
29970 +                               sess->proxy_con = NULL;
29971 +                       }
29972 +                       
29973 +                       return HANDLER_FINISHED;
29974 +               }
29975 +       default:
29976 +               /* handle-request-timeout,  */
29977 +               if (srv->cur_ts - con->request_start > 60) {
29978 +                       TRACE("request runs longer than 60sec: current state: %d", sess->state);
29979 +               }
29980 +               break;
29981 +       }
29982 +
29983 +       /* if the WRITE fails from the start, restart the connection */
29984 +       while (1) {
29985 +               if (sess->proxy_con == NULL) {
29986 +                       proxy_address *address = NULL;
29987 +                       if (NULL == (sess->proxy_backend = proxy_get_backend(srv, con, p, con->uri.path))) {
29988 +                               /* no connection pool for this location */
29989 +                               SEGFAULT();
29990 +                       }
29991 +
29992 +                       /**
29993 +                        * ask the balancer for the next address and
29994 +                        * check the connection pool if we have a connection open
29995 +                        * for that address
29996 +                        */
29997 +                       if (NULL == (address = proxy_backend_balance(srv, con, sess->proxy_backend))) {
29998 +                               /* we don't have any backends to connect to */
29999 +                               proxy_request *req;
30000 +
30001 +                               /* connection pool is full, queue the request for now */
30002 +                               req = proxy_request_init();
30003 +                               req->added_ts = srv->cur_ts;
30004 +                               req->con = con;
30005 +                               
30006 +                               TRACE("backlog: all backends are down, putting %s (%d) into the backlog", BUF_STR(con->uri.path), con->sock->fd);
30007 +                               proxy_backlog_push(p->conf.backlog, req);
30008 +
30009 +                               /* no, not really a event, 
30010 +                                * we just want to block the outer loop from stepping forward
30011 +                                *
30012 +                                * the trigger will bring this connection back into the game
30013 +                                * */
30014 +                               return HANDLER_WAIT_FOR_EVENT;
30015 +                       }
30016 +
30017 +                       if (PROXY_CONNECTIONPOOL_FULL == proxy_connection_pool_get_connection(
30018 +                                               sess->proxy_backend->pool, 
30019 +                                               address,
30020 +                                               &(sess->proxy_con))) {
30021 +                               proxy_request *req;
30022 +
30023 +                               /* connection pool is full, queue the request for now */
30024 +                               req = proxy_request_init();
30025 +                               req->added_ts = srv->cur_ts;
30026 +                               req->con = con;
30027 +                               
30028 +                               TRACE("backlog: the con-pool is full, putting %s (%d) into the backlog", con->uri.path->ptr, con->sock->fd);
30029 +                               proxy_backlog_push(p->conf.backlog, req);
30030 +
30031 +                               /* no, not really a event, 
30032 +                                * we just want to block the outer loop from stepping forward
30033 +                                *
30034 +                                * the trigger will bring this connection back into the game
30035 +                                * */
30036 +                               return HANDLER_WAIT_FOR_EVENT;
30037 +                       }
30038 +
30039 +                       /* a fresh connection, we need address for it */
30040 +                       if (sess->proxy_con->state == PROXY_CONNECTION_STATE_CONNECTING) {
30041 +                               sess->state = PROXY_STATE_UNSET;
30042 +                               sess->bytes_read = 0;
30043 +                       } else {
30044 +                               /* we are already connected */
30045 +                               sess->state = PROXY_STATE_CONNECTED;
30046 +                               
30047 +                               /* the connection was idling and using the fdevent_idle-handler 
30048 +                                * switch it back to the normal proxy-event-handler */
30049 +                               fdevent_event_del(srv->ev, sess->proxy_con->sock);
30050 +                               fdevent_unregister(srv->ev, sess->proxy_con->sock);
30051 +
30052 +                               fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
30053 +                               fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
30054 +                       }
30055 +               }
30056 +
30057 +               switch (proxy_state_engine(srv, con, p, sess)) {
30058 +               case HANDLER_WAIT_FOR_EVENT:
30059 +                       return HANDLER_WAIT_FOR_EVENT;
30060 +               case HANDLER_COMEBACK:
30061 +                       proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
30062 +       
30063 +                       fdevent_event_del(srv->ev, sess->proxy_con->sock);
30064 +                       fdevent_unregister(srv->ev, sess->proxy_con->sock);
30065 +
30066 +                       proxy_connection_free(sess->proxy_con);
30067 +
30068 +                       sess->proxy_con = NULL;
30069 +                       /* restart the connection to the backend */
30070 +                       TRACE("%s", "write failed, restarting request");
30071 +                       break;
30072 +               case HANDLER_GO_ON:
30073 +                       return HANDLER_GO_ON;
30074 +               default:
30075 +                       return HANDLER_ERROR;
30076 +               }
30077 +       }
30078 +
30079 +       /* should not be reached */
30080 +       return HANDLER_ERROR;
30081 +}
30082 +
30083 +/**
30084 + * end of the connection to the client
30085 + */
30086 +REQUESTDONE_FUNC(mod_proxy_connection_close_callback) {
30087 +       plugin_data *p = p_d;
30088 +       
30089 +       if (con->mode != p->id) return HANDLER_GO_ON;
30090 +
30091 +       return HANDLER_GO_ON;
30092 +}
30093 +
30094 +/**
30095 + * end of a request
30096 + */
30097 +CONNECTION_FUNC(mod_proxy_connection_reset) {
30098 +       plugin_data *p = p_d;
30099 +       proxy_session *sess = con->plugin_ctx[p->id]; 
30100 +
30101 +       if (con->mode != p->id) return HANDLER_GO_ON;
30102 +
30103 +       if (sess->proxy_con) {
30104 +               switch (sess->proxy_con->state) {
30105 +               case PROXY_CONNECTION_STATE_CONNECTED:
30106 +                       sess->proxy_con->state = PROXY_CONNECTION_STATE_IDLE;
30107 +
30108 +                       /* ignore events as the FD is idle, we might get a HUP as the remote connection might close */
30109 +                       fdevent_event_del(srv->ev, sess->proxy_con->sock);
30110 +                       fdevent_unregister(srv->ev, sess->proxy_con->sock);
30111 +
30112 +                       fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent_idle, sess->proxy_con);
30113 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
30114 +
30115 +                       break;
30116 +               case PROXY_CONNECTION_STATE_CLOSED:
30117 +                       proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
30118 +       
30119 +                       fdevent_event_del(srv->ev, sess->proxy_con->sock);
30120 +                       fdevent_unregister(srv->ev, sess->proxy_con->sock);
30121 +
30122 +                       proxy_connection_free(sess->proxy_con);
30123 +                       break;
30124 +               case PROXY_CONNECTION_STATE_IDLE:
30125 +                       TRACE("%s", "... connection is already back in the pool");
30126 +                       break;
30127 +               default:
30128 +                       ERROR("connection is in a unexpected state at close-time: %d", sess->proxy_con->state);
30129 +                       break;
30130 +               }
30131 +       } else {
30132 +               /* if we have the connection in the backlog, remove it */
30133 +               proxy_backlog_remove_connection(p->conf.backlog, con);
30134 +       }
30135 +       
30136 +
30137 +       proxy_session_free(sess);
30138 +
30139 +       con->plugin_ctx[p->id] = NULL;
30140 +       
30141 +       return HANDLER_GO_ON;
30142 +}
30143 +
30144 +
30145 +
30146 +/**
30147 + * cleanup dead connections once a second
30148 + *
30149 + * the idling event-handler can't cleanup connections itself and has to wait until the 
30150 + * trigger cleans up
30151 + */
30152 +handler_t mod_proxy_trigger_context(server *srv, plugin_config *p) {
30153 +       size_t i, j;
30154 +       proxy_request *req;
30155 +
30156 +       for (i = 0; i < p->backends->used; i++) {
30157 +               proxy_backend *backend = p->backends->ptr[i];
30158 +               proxy_connection_pool *pool = backend->pool;
30159 +               proxy_address_pool *address_pool = backend->address_pool;
30160 +
30161 +               for (j = 0; j < pool->used; ) {
30162 +                       proxy_connection *proxy_con = pool->ptr[j];
30163 +
30164 +                       /* remove-con is removing the current con and moves the good connections to the left
30165 +                        * no need to increment i */
30166 +                       if (proxy_con->state == PROXY_CONNECTION_STATE_CLOSED) {
30167 +                               proxy_connection_pool_remove_connection(backend->pool, proxy_con);
30168 +       
30169 +                               fdevent_event_del(srv->ev, proxy_con->sock);
30170 +                               fdevent_unregister(srv->ev, proxy_con->sock);
30171 +
30172 +                               proxy_connection_free(proxy_con);
30173 +                       } else {
30174 +                               j++;
30175 +                       }
30176 +               }
30177 +
30178 +               /* active the disabled addresses again */
30179 +               for (j = 0; j < address_pool->used; j++) {
30180 +                       proxy_address *address = address_pool->ptr[j];
30181 +
30182 +                       if (address->state != PROXY_ADDRESS_STATE_DISABLED) continue;
30183 +
30184 +                       if (srv->cur_ts > address->disabled_until) {
30185 +                               address->disabled_until = 0;
30186 +                               address->state = PROXY_ADDRESS_STATE_ACTIVE;
30187 +                       }
30188 +               }
30189 +       }
30190 +
30191 +       /* wake up the connections from the backlog */
30192 +       while ((req = proxy_backlog_shift(p->backlog))) {
30193 +               connection *con = req->con;
30194 +
30195 +               joblist_append(srv, con);
30196 +
30197 +               proxy_request_free(req);
30198 +       }
30199 +       
30200 +       return HANDLER_GO_ON;
30201 +}
30202 +
30203 +TRIGGER_FUNC(mod_proxy_trigger) {
30204 +       plugin_data *p = p_d;
30205 +       size_t i;
30206 +       
30207 +       for (i = 0; i < srv->config_context->used; i++) {
30208 +               mod_proxy_trigger_context(srv, p->config_storage[i]);
30209 +       }
30210 +
30211 +       return HANDLER_GO_ON;
30212 +}
30213 +
30214 +int mod_proxy_core_plugin_init(plugin *p) {
30215 +       p->version      = LIGHTTPD_VERSION_ID;
30216 +       p->name         = buffer_init_string("mod_proxy_core");
30217 +
30218 +       p->init         = mod_proxy_core_init;
30219 +       p->cleanup      = mod_proxy_core_free;
30220 +       p->set_defaults = mod_proxy_core_set_defaults;
30221 +       p->handle_uri_clean        = mod_proxy_core_check_extension;
30222 +       p->handle_subrequest_start = mod_proxy_core_check_extension;
30223 +       p->handle_subrequest       = mod_proxy_core_check_extension;
30224 +       p->connection_reset        = mod_proxy_connection_reset;
30225 +       p->handle_connection_close = mod_proxy_connection_close_callback;
30226 +       p->handle_trigger          = mod_proxy_trigger;
30227 +
30228 +       p->data         = NULL;
30229 +
30230 +       return 0;
30231 +}
30232 --- ../lighttpd-1.4.11/src/mod_proxy_core.h     1970-01-01 03:00:00.000000000 +0300
30233 +++ lighttpd-1.4.12/src/mod_proxy_core.h        2006-07-18 13:03:40.000000000 +0300
30234 @@ -0,0 +1,18 @@
30235 +#ifndef _MOD_PROXY_CORE_H_
30236 +#define _MOD_PROXY_CORE_H_
30237 +
30238 +#include "buffer.h"
30239 +#include "base.h"
30240 +
30241 +#define PROXY_BACKEND_CONNECT_PARAMS \
30242 +       (server *srv, connection *con, void *p_d)
30243 +
30244 +#define PROXY_BACKEND_CONNECT_RETVAL handler_t
30245 +
30246 +#define PROXY_BACKEND_CONNECT(name) \
30247 +       PROXY_BACKEND_CONNECT_RETVAL name PROXY_BACKEND_CONNECT_PARAMS
30248 +
30249 +#define PROXY_BACKEND_CONNECT_PTR(name) \
30250 +       PROXY_BACKEND_CONNECT_RETVAL (* name)PROXY_BACKEND_CONNECT_PARAMS
30251 +
30252 +#endif
30253 --- ../lighttpd-1.4.11/src/mod_proxy_core_address.c     1970-01-01 03:00:00.000000000 +0300
30254 +++ lighttpd-1.4.12/src/mod_proxy_core_address.c        2006-07-18 13:03:40.000000000 +0300
30255 @@ -0,0 +1,85 @@
30256 +#include <stdlib.h>
30257 +#include <string.h>
30258 +
30259 +#include "log.h"
30260 +#include "sys-socket.h"
30261 +#include "mod_proxy_core_address.h"
30262 +
30263 +proxy_address *proxy_address_init(void) {
30264 +       proxy_address *address;
30265 +
30266 +       address = calloc(1, sizeof(*address));
30267 +
30268 +       address->name = buffer_init();
30269 +
30270 +       return address;
30271 +}
30272 +
30273 +void proxy_address_free(proxy_address *address) {
30274 +       if (!address) return;
30275 +
30276 +       buffer_free(address->name);
30277 +
30278 +       free(address);
30279 +}
30280 +
30281 +
30282 +proxy_address_pool *proxy_address_pool_init(void) {
30283 +       proxy_address_pool *address_pool;
30284 +
30285 +       address_pool = calloc(1, sizeof(*address_pool));
30286 +
30287 +       return address_pool;
30288 +}
30289 +
30290 +void proxy_address_pool_free(proxy_address_pool *address_pool) {
30291 +       if (!address_pool) return;
30292 +
30293 +       FOREACH(address_pool, element, proxy_address_free(element))
30294 +
30295 +       free(address_pool);
30296 +}
30297 +
30298 +void proxy_address_pool_add(proxy_address_pool *address_pool, proxy_address *address) {
30299 +       ARRAY_STATIC_PREPARE_APPEND(address_pool);
30300 +       
30301 +       address_pool->ptr[address_pool->used++] = address;
30302 +}
30303 +
30304 +int  proxy_address_pool_add_string(proxy_address_pool *address_pool, buffer *name) {
30305 +       struct addrinfo *res = NULL, pref, *cur;
30306 +       int ret;
30307 +
30308 +       pref.ai_flags = 0;
30309 +       pref.ai_family = PF_UNSPEC;
30310 +       pref.ai_socktype = SOCK_STREAM;
30311 +       pref.ai_protocol = 0;
30312 +       pref.ai_addrlen = 0;
30313 +       pref.ai_addr = NULL;
30314 +       pref.ai_canonname = NULL;
30315 +       pref.ai_next = NULL;
30316 +
30317 +       if (0 != (ret = getaddrinfo(name->ptr, "80", &pref, &res))) {
30318 +               ERROR("getaddrinfo failed: %s", gai_strerror(ret));
30319 +
30320 +               return -1;
30321 +       }
30322 +
30323 +       for (cur = res; cur; cur = cur->ai_next) {
30324 +               proxy_address *a = proxy_address_init();
30325 +
30326 +               memcpy(&(a->addr), cur->ai_addr, cur->ai_addrlen);
30327 +
30328 +               a->state = PROXY_ADDRESS_STATE_ACTIVE;
30329 +
30330 +               buffer_copy_string(a->name, inet_ntoa(a->addr.ipv4.sin_addr));
30331 +
30332 +               proxy_address_pool_add(address_pool, a);
30333 +       }
30334 +
30335 +       freeaddrinfo(res);
30336 +
30337 +       return 0;
30338 +}
30339 +
30340 +
30341 --- ../lighttpd-1.4.11/src/mod_proxy_core_address.h     1970-01-01 03:00:00.000000000 +0300
30342 +++ lighttpd-1.4.12/src/mod_proxy_core_address.h        2006-07-18 13:03:40.000000000 +0300
30343 @@ -0,0 +1,33 @@
30344 +#ifndef _MOD_PROXY_CORE_ADDRESS_H_
30345 +#define _MOD_PROXY_CORE_ADDRESS_H_
30346 +
30347 +#include <time.h>
30348 +#include "buffer.h"
30349 +#include "sys-socket.h"
30350 +#include "array-static.h"
30351 +
30352 +typedef enum {
30353 +       PROXY_ADDRESS_STATE_UNSET,
30354 +       PROXY_ADDRESS_STATE_ACTIVE,
30355 +       PROXY_ADDRESS_STATE_DISABLED,
30356 +} proxy_address_state_t;
30357 +
30358 +typedef struct {
30359 +       sock_addr addr;
30360 +
30361 +       buffer *name; /* a inet_ntoa() prepresentation of the address */
30362 +
30363 +       time_t last_used;
30364 +       time_t disabled_until;
30365 +
30366 +       proxy_address_state_t state;
30367 +} proxy_address;
30368 +
30369 +ARRAY_STATIC_DEF(proxy_address_pool, proxy_address, );
30370 +
30371 +proxy_address_pool *proxy_address_pool_init(void); 
30372 +void proxy_address_pool_free(proxy_address_pool *address_pool); 
30373 +void proxy_address_pool_add(proxy_address_pool *address_pool, proxy_address *address);
30374 +int proxy_address_pool_add_string(proxy_address_pool *address_pool, buffer *address);
30375 +
30376 +#endif
30377 --- ../lighttpd-1.4.11/src/mod_proxy_core_backend.c     1970-01-01 03:00:00.000000000 +0300
30378 +++ lighttpd-1.4.12/src/mod_proxy_core_backend.c        2006-07-18 13:03:40.000000000 +0300
30379 @@ -0,0 +1,45 @@
30380 +#include <stdlib.h>
30381 +
30382 +#include "mod_proxy_core_backend.h"
30383 +#include "mod_proxy_core_pool.h"
30384 +#include "mod_proxy_core_address.h"
30385 +
30386 +proxy_backend *proxy_backend_init(void) {
30387 +       proxy_backend *backend;
30388 +
30389 +       backend = calloc(1, sizeof(*backend));
30390 +       backend->pool = proxy_connection_pool_init();
30391 +       backend->address_pool = proxy_address_pool_init();
30392 +       backend->balancer = PROXY_BALANCE_RR;
30393 +
30394 +       return backend;
30395 +}
30396 +
30397 +void proxy_backend_free(proxy_backend *backend) {
30398 +       if (!backend) return;
30399 +
30400 +       proxy_address_pool_free(backend->address_pool);
30401 +       proxy_connection_pool_free(backend->pool);
30402 +       
30403 +       free(backend);
30404 +}
30405 +
30406 +proxy_backends *proxy_backends_init(void) {
30407 +       proxy_backends *backends;
30408 +
30409 +       backends = calloc(1, sizeof(*backends));
30410 +
30411 +       return backends;
30412 +}
30413 +
30414 +void proxy_backends_free(proxy_backends *backends) {
30415 +       FOREACH(backends, element, proxy_backend_free(element))
30416 +
30417 +       free(backends);
30418 +}
30419 +
30420 +void proxy_backends_add(proxy_backends *backends, proxy_backend *backend) {
30421 +       ARRAY_STATIC_PREPARE_APPEND(backends);
30422 +
30423 +       backends->ptr[backends->used++] = backend;
30424 +}
30425 --- ../lighttpd-1.4.11/src/mod_proxy_core_backend.h     1970-01-01 03:00:00.000000000 +0300
30426 +++ lighttpd-1.4.12/src/mod_proxy_core_backend.h        2006-07-18 13:03:40.000000000 +0300
30427 @@ -0,0 +1,54 @@
30428 +#ifndef _MOD_PROXY_CORE_BACKEND_H_
30429 +#define _MOD_PROXY_CORE_BACKEND_H_
30430 +
30431 +#include "array-static.h"
30432 +#include "buffer.h"
30433 +#include "mod_proxy_core_address.h"
30434 +#include "mod_proxy_core_pool.h"
30435 +#include "sys-socket.h"
30436 +
30437 +/**
30438 + * a single DNS name might explode to several IP addresses 
30439 + * 
30440 + * url: 
30441 + * - http://foo.bar/suburl/
30442 + * - https://foo.bar/suburl/
30443 + * - unix:/tmp/socket
30444 + * - tcp://foobar:1025/
30445 + *
30446 + * backend:
30447 + * - scgi
30448 + * - http
30449 + * - fastcgi
30450 + *
30451 + * request-url-rewrite
30452 + * response-url-rewrite
30453 + */ 
30454 +typedef enum {
30455 +       PROXY_BALANCE_UNSET,
30456 +       PROXY_BALANCE_FAIR,
30457 +       PROXY_BALANCE_HASH,
30458 +       PROXY_BALANCE_RR
30459 +} proxy_balance_t;
30460 +
30461 +typedef struct {
30462 +       buffer *url;
30463 +
30464 +       proxy_connection_pool *pool;  /* pool of active connections */
30465 +       int use_keepalive;
30466 +
30467 +       proxy_address_pool *address_pool; /* possible destination-addresses, disabling is done here */
30468 +       proxy_balance_t balancer; /* how to choose a address from the address-pool */
30469 +} proxy_backend;
30470 +
30471 +ARRAY_STATIC_DEF(proxy_backends, proxy_backend, );
30472 +
30473 +proxy_backend *proxy_backend_init(void);
30474 +void proxy_backend_free(proxy_backend *backend);
30475 +
30476 +proxy_backends *proxy_backends_init(void);
30477 +void proxy_backends_free(proxy_backends *backends);
30478 +void proxy_backends_add(proxy_backends *backends, proxy_backend *backend);
30479 +
30480 +#endif
30481 +
30482 --- ../lighttpd-1.4.11/src/mod_proxy_core_backlog.c     1970-01-01 03:00:00.000000000 +0300
30483 +++ lighttpd-1.4.12/src/mod_proxy_core_backlog.c        2006-07-18 13:03:40.000000000 +0300
30484 @@ -0,0 +1,109 @@
30485 +#include <stdlib.h>
30486 +
30487 +#include "mod_proxy_core_backlog.h"
30488 +#include "array-static.h"
30489 +
30490 +proxy_backlog *proxy_backlog_init(void) {
30491 +       STRUCT_INIT(proxy_backlog, backlog);
30492 +
30493 +       return backlog;
30494 +}
30495 +
30496 +void proxy_backlog_free(proxy_backlog *backlog) {
30497 +       if (!backlog) return;
30498 +
30499 +       free(backlog);
30500 +}
30501 +
30502 +int proxy_backlog_push(proxy_backlog *backlog, proxy_request *req) {
30503 +       /* first entry */
30504 +       if (NULL == backlog->first) {
30505 +               backlog->first = backlog->last = req;
30506 +       } else {
30507 +               backlog->last->next = req;
30508 +               backlog->last = req;
30509 +       }
30510 +       backlog->length++;
30511 +
30512 +       return 0;
30513 +}
30514 +
30515 +/**
30516 + * remove the first element from the backlog
30517 + */
30518 +proxy_request *proxy_backlog_shift(proxy_backlog *backlog) {
30519 +       proxy_request *req = NULL;
30520 +
30521 +       if (!backlog->first) return req;
30522 +
30523 +       backlog->length--;
30524 +
30525 +       req = backlog->first;
30526 +
30527 +       backlog->first = req->next;
30528 +
30529 +       /* the backlog is empty */
30530 +       if (backlog->first == NULL) backlog->last = NULL;
30531 +
30532 +       return req;
30533 +}
30534 +
30535 +int proxy_backlog_remove_connection(proxy_backlog *backlog, void *con) {
30536 +       proxy_request *req = NULL;
30537 +
30538 +       if (!backlog->first) return -1;
30539 +       if (!con) return -1;
30540 +
30541 +       /* the first element is what we look for */
30542 +       if (backlog->first->con == con) {
30543 +               req = backlog->first;
30544 +               
30545 +               backlog->first = req->next;
30546 +               if (backlog->first == NULL) backlog->last = NULL;
30547 +
30548 +               backlog->length--;
30549 +               
30550 +               proxy_request_free(req);
30551 +
30552 +               return 0;
30553 +       }
30554 +
30555 +
30556 +       for (req = backlog->first; req && req->next; req = req->next) {
30557 +               proxy_request *cur;
30558 +
30559 +               if (req->next->con != con) continue;
30560 +
30561 +               backlog->length--;
30562 +               /* the next node is our searched connection */
30563 +
30564 +               cur = req->next;
30565 +               req->next = cur->next;
30566 +
30567 +               /* the next node is the last one, make the current the new last */
30568 +               if (cur == backlog->last) {
30569 +                       backlog->last = req;
30570 +               }
30571 +               cur->next = NULL;
30572 +
30573 +               proxy_request_free(req);
30574 +
30575 +               return 0;
30576 +       }
30577 +
30578 +       return -1;
30579 +}
30580 +
30581 +proxy_request *proxy_request_init(void) {
30582 +       STRUCT_INIT(proxy_request, request);
30583 +
30584 +       return request;
30585 +}
30586 +
30587 +void proxy_request_free(proxy_request *request) {
30588 +       if (!request) return;
30589 +
30590 +       free(request);
30591 +}
30592 +
30593 +
30594 --- ../lighttpd-1.4.11/src/mod_proxy_core_backlog.h     1970-01-01 03:00:00.000000000 +0300
30595 +++ lighttpd-1.4.12/src/mod_proxy_core_backlog.h        2006-07-18 13:03:40.000000000 +0300
30596 @@ -0,0 +1,56 @@
30597 +#ifndef _MOD_PROXY_CORE_BACKLOG_H_
30598 +#define _MOD_PROXY_CORE_BACKLOG_H_
30599 +
30600 +#include <sys/types.h>
30601 +#include <sys/time.h>
30602 +
30603 +typedef struct _proxy_request {
30604 +       void *con; /* a pointer to the client-connection, (type: connection) */
30605 +
30606 +       time_t added_ts; /* when was the entry added (for timeout handling) */
30607 +
30608 +       struct _proxy_request *next;
30609 +} proxy_request;
30610 +
30611 +/**
30612 + * a we can't get a connection from the pool, queue the request in the
30613 + * request queue (FIFO)
30614 + *
30615 + * - the queue is infinite
30616 + * - entries are removed after a timeout (status 504)
30617 + */
30618 +typedef struct {
30619 +       proxy_request *first; /* pull() does q->first = q->first->next */
30620 +       proxy_request *last; /* push() does q->last = r */
30621 +
30622 +       size_t length;
30623 +} proxy_backlog;
30624 +
30625 +proxy_backlog *proxy_backlog_init(void);
30626 +void proxy_backlog_free(proxy_backlog *backlog);
30627 +
30628 +/**
30629 + * append a request to the end
30630 + * 
30631 + * @return 0 in success, -1 if full
30632 + */ 
30633 +int proxy_backlog_push(proxy_backlog *backlog, proxy_request *req);
30634 +
30635 +/**
30636 + * remove the first request from the backlog
30637 + *
30638 + * @return NULL if backlog is empty, the request otherwise
30639 + */
30640 +proxy_request *proxy_backlog_shift(proxy_backlog *backlog);
30641 +/**
30642 + * remove the request with the connection 'con' from the backlog
30643 + *
30644 + * @return -1 if not found, 0 otherwise
30645 + */
30646 +int proxy_backlog_remove_connection(proxy_backlog *backlog, void *con);
30647 +
30648 +proxy_request *proxy_request_init(void);
30649 +void proxy_request_free(proxy_request *req);
30650 +
30651 +#endif
30652 +
30653 --- ../lighttpd-1.4.11/src/mod_proxy_core_pool.c        1970-01-01 03:00:00.000000000 +0300
30654 +++ lighttpd-1.4.12/src/mod_proxy_core_pool.c   2006-07-18 13:03:40.000000000 +0300
30655 @@ -0,0 +1,127 @@
30656 +
30657 +#include <stdlib.h>
30658 +
30659 +#include "array-static.h"
30660 +#include "sys-files.h"
30661 +#include "log.h"
30662 +#include "mod_proxy_core_pool.h"
30663 +
30664 +proxy_connection * proxy_connection_init(void) {
30665 +       proxy_connection *con;
30666 +
30667 +       con = calloc(1, sizeof(*con));
30668 +
30669 +       con->sock = iosocket_init();
30670 +
30671 +       return con;
30672 +}
30673 +
30674 +void proxy_connection_free(proxy_connection *con) {
30675 +       if (!con) return;
30676 +
30677 +       iosocket_free(con->sock);
30678 +
30679 +       free(con);
30680 +}
30681 +
30682 +proxy_connection_pool *proxy_connection_pool_init(void) {
30683 +       proxy_connection_pool *pool;
30684 +
30685 +       pool = calloc(1, sizeof(*pool));
30686 +
30687 +               /* default: max parallel connections to the backend
30688 +        * 
30689 +        * this should match max-procs if we manage the procs ourself
30690 +                */
30691 +
30692 +       pool->max_size = 8;
30693 +
30694 +       return pool;
30695 +}
30696 +
30697 +void proxy_connection_pool_free(proxy_connection_pool *pool) {
30698 +       size_t i;
30699 +
30700 +       if (!pool) return;
30701 +
30702 +       for (i = 0; i < pool->used; i++) {
30703 +               proxy_connection_free(pool->ptr[i]);
30704 +       }
30705 +
30706 +       if (pool->size) free(pool->ptr);
30707 +
30708 +       free(pool);
30709 +}
30710 +
30711 +void proxy_connection_pool_add_connection(proxy_connection_pool *pool, proxy_connection *c) {
30712 +       ARRAY_STATIC_PREPARE_APPEND(pool);
30713 +
30714 +       pool->ptr[pool->used++] = c;
30715 +}
30716 +/**
30717 + * remove the connection from the pool
30718 + *
30719 + * usually called on conn-shutdown
30720 + */
30721 +int proxy_connection_pool_remove_connection(proxy_connection_pool *pool, proxy_connection *c) {
30722 +       size_t i;
30723 +
30724 +       if (pool->used == 0) return -1; /* empty */
30725 +
30726 +       for (i = 0; i < pool->used; i++) {
30727 +               if (pool->ptr[i] == c) {
30728 +                       break;
30729 +               }
30730 +       }
30731 +
30732 +       if (i == pool->used) return -1; /* not found */
30733 +
30734 +       /**
30735 +        * move all elements one to the left
30736 +        *
30737 +        * if the last element is going to be removed, skip the loop
30738 +        */
30739 +       for (; i < pool->used - 1; i++) {
30740 +               pool->ptr[i] = pool->ptr[i + 1];
30741 +       }
30742 +
30743 +       pool->used--;
30744 +
30745 +       return 0;
30746 +}
30747 +
30748 +proxy_connection_pool_t proxy_connection_pool_get_connection(proxy_connection_pool *pool, proxy_address *address, proxy_connection **rcon) {
30749 +       proxy_connection *proxy_con = NULL;
30750 +       size_t i;
30751 +
30752 +       /* search for a idling proxy connection with the given address */
30753 +       for (i = 0; i < pool->used; i++) {
30754 +               proxy_con = pool->ptr[i];
30755 +
30756 +               if (proxy_con->address == address &&
30757 +                   proxy_con->state == PROXY_CONNECTION_STATE_IDLE) {
30758 +                       break;
30759 +               }
30760 +       }
30761 +
30762 +       if (i == pool->used) {
30763 +               /* no idling connection found */
30764 +
30765 +               if (pool->used == pool->max_size) return PROXY_CONNECTIONPOOL_FULL;
30766 +               
30767 +               proxy_con = proxy_connection_init();
30768 +
30769 +               proxy_con->state = PROXY_CONNECTION_STATE_CONNECTING;
30770 +               proxy_con->address = address;
30771 +
30772 +               proxy_connection_pool_add_connection(pool, proxy_con);
30773 +       } else {
30774 +               proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
30775 +       }
30776 +
30777 +       *rcon = proxy_con;
30778 +
30779 +       return PROXY_CONNECTIONPOOL_GOT_CONNECTION;
30780 +}
30781 +
30782 +
30783 --- ../lighttpd-1.4.11/src/mod_proxy_core_pool.h        1970-01-01 03:00:00.000000000 +0300
30784 +++ lighttpd-1.4.12/src/mod_proxy_core_pool.h   2006-07-18 13:03:40.000000000 +0300
30785 @@ -0,0 +1,52 @@
30786 +#ifndef _MOD_PROXY_CORE_POOL_H_
30787 +#define _MOD_PROXY_CORE_POOL_H_
30788 +
30789 +#include <sys/time.h>
30790 +
30791 +#include "iosocket.h"
30792 +#include "array-static.h"
30793 +#include "mod_proxy_core_address.h"
30794 +
30795 +typedef enum {
30796 +       PROXY_CONNECTION_STATE_UNSET,
30797 +       PROXY_CONNECTION_STATE_CONNECTING,
30798 +       PROXY_CONNECTION_STATE_CONNECTED,
30799 +       PROXY_CONNECTION_STATE_IDLE,
30800 +       PROXY_CONNECTION_STATE_CLOSED,
30801 +} proxy_connection_state_t;
30802 +
30803 +/**
30804 + * a connection to a proxy backend
30805 + * 
30806 + * the connection is independent of the incoming request to allow keep-alive
30807 + */
30808 +typedef struct { 
30809 +       iosocket *sock;
30810 +
30811 +       time_t last_read; /* timeout handling for keep-alive connections */
30812 +       time_t last_write;
30813 +
30814 +       proxy_address *address; /* the struct sock_addr for the sock */
30815 +
30816 +       proxy_connection_state_t state;
30817 +} proxy_connection;
30818 +
30819 +ARRAY_STATIC_DEF(proxy_connection_pool, proxy_connection, size_t max_size;);
30820 +
30821 +typedef enum {
30822 +       PROXY_CONNECTIONPOOL_UNSET,
30823 +       PROXY_CONNECTIONPOOL_FULL,
30824 +       PROXY_CONNECTIONPOOL_GOT_CONNECTION,
30825 +} proxy_connection_pool_t;
30826 +
30827 +proxy_connection_pool *proxy_connection_pool_init(void); 
30828 +void proxy_connection_pool_free(proxy_connection_pool *pool); 
30829 +
30830 +proxy_connection_pool_t proxy_connection_pool_get_connection(proxy_connection_pool *pool, proxy_address *address, proxy_connection **rcon);
30831 +int proxy_connection_pool_remove_connection(proxy_connection_pool *pool, proxy_connection *c);
30832 +
30833 +proxy_connection * proxy_connection_init(void);
30834 +void proxy_connection_free(proxy_connection *pool);
30835 +
30836 +#endif
30837 +
30838 --- ../lighttpd-1.4.11/src/mod_redirect.c       2006-02-08 15:38:06.000000000 +0200
30839 +++ lighttpd-1.4.12/src/mod_redirect.c  2006-07-16 00:26:04.000000000 +0300
30840 @@ -22,35 +22,35 @@
30841         PLUGIN_DATA;
30842         buffer *match_buf;
30843         buffer *location;
30844 -       
30845 +
30846         plugin_config **config_storage;
30847 -       
30848 -       plugin_config conf; 
30849 +
30850 +       plugin_config conf;
30851  } plugin_data;
30852  
30853  INIT_FUNC(mod_redirect_init) {
30854         plugin_data *p;
30855 -       
30856 +
30857         p = calloc(1, sizeof(*p));
30858 -       
30859 +
30860         p->match_buf = buffer_init();
30861         p->location = buffer_init();
30862 -       
30863 +
30864         return p;
30865  }
30866  
30867  FREE_FUNC(mod_redirect_free) {
30868         plugin_data *p = p_d;
30869 -       
30870 +
30871         if (!p) return HANDLER_GO_ON;
30872  
30873         if (p->config_storage) {
30874                 size_t i;
30875                 for (i = 0; i < srv->config_context->used; i++) {
30876                         plugin_config *s = p->config_storage[i];
30877 -                       
30878 +
30879                         pcre_keyvalue_buffer_free(s->redirect);
30880 -                       
30881 +
30882                         free(s);
30883                 }
30884                 free(p->config_storage);
30885 @@ -59,9 +59,9 @@
30886  
30887         buffer_free(p->match_buf);
30888         buffer_free(p->location);
30889 -       
30890 +
30891         free(p);
30892 -       
30893 +
30894         return HANDLER_GO_ON;
30895  }
30896  
30897 @@ -69,195 +69,137 @@
30898         plugin_data *p = p_d;
30899         data_unset *du;
30900         size_t i = 0;
30901 -       
30902 -       config_values_t cv[] = { 
30903 +
30904 +       config_values_t cv[] = {
30905                 { "url.redirect",               NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
30906                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
30907         };
30908 -       
30909 +
30910         if (!p) return HANDLER_ERROR;
30911 -       
30912 +
30913         /* 0 */
30914         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
30915 -       
30916 +
30917         for (i = 0; i < srv->config_context->used; i++) {
30918                 plugin_config *s;
30919                 size_t j;
30920                 array *ca;
30921                 data_array *da = (data_array *)du;
30922 -               
30923 +
30924                 s = calloc(1, sizeof(plugin_config));
30925                 s->redirect   = pcre_keyvalue_buffer_init();
30926 -               
30927 +
30928                 cv[0].destination = s->redirect;
30929 -               
30930 +
30931                 p->config_storage[i] = s;
30932                 ca = ((data_config *)srv->config_context->data[i])->value;
30933 -       
30934 +
30935                 if (0 != config_insert_values_global(srv, ca, cv)) {
30936                         return HANDLER_ERROR;
30937                 }
30938 -               
30939 +
30940                 if (NULL == (du = array_get_element(ca, "url.redirect"))) {
30941                         /* no url.redirect defined */
30942                         continue;
30943                 }
30944 -               
30945 +
30946                 if (du->type != TYPE_ARRAY) {
30947 -                       log_error_write(srv, __FILE__, __LINE__, "sss", 
30948 +                       log_error_write(srv, __FILE__, __LINE__, "sss",
30949                                         "unexpected type for key: ", "url.redirect", "array of strings");
30950 -                       
30951 +
30952                         return HANDLER_ERROR;
30953                 }
30954 -               
30955 +
30956                 da = (data_array *)du;
30957 -                               
30958 +
30959                 for (j = 0; j < da->value->used; j++) {
30960                         if (da->value->data[j]->type != TYPE_STRING) {
30961 -                               log_error_write(srv, __FILE__, __LINE__, "sssbs", 
30962 -                                               "unexpected type for key: ", 
30963 -                                               "url.redirect", 
30964 +                               log_error_write(srv, __FILE__, __LINE__, "sssbs",
30965 +                                               "unexpected type for key: ",
30966 +                                               "url.redirect",
30967                                                 "[", da->value->data[j]->key, "](string)");
30968 -                               
30969 +
30970                                 return HANDLER_ERROR;
30971                         }
30972 -                               
30973 -                       if (0 != pcre_keyvalue_buffer_append(s->redirect, 
30974 +
30975 +                       if (0 != pcre_keyvalue_buffer_append(s->redirect,
30976                                                              ((data_string *)(da->value->data[j]))->key->ptr,
30977                                                              ((data_string *)(da->value->data[j]))->value->ptr)) {
30978 -                                       
30979 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
30980 +
30981 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
30982                                                 "pcre-compile failed for", da->value->data[j]->key);
30983                         }
30984                 }
30985         }
30986 -       
30987 +
30988         return HANDLER_GO_ON;
30989  }
30990  #ifdef HAVE_PCRE_H
30991  static int mod_redirect_patch_connection(server *srv, connection *con, plugin_data *p) {
30992         size_t i, j;
30993         plugin_config *s = p->config_storage[0];
30994 -       
30995 +
30996         p->conf.redirect = s->redirect;
30997 -       
30998 +
30999         /* skip the first, the global context */
31000         for (i = 1; i < srv->config_context->used; i++) {
31001                 data_config *dc = (data_config *)srv->config_context->data[i];
31002                 s = p->config_storage[i];
31003 -               
31004 +
31005                 /* condition didn't match */
31006                 if (!config_check_cond(srv, con, dc)) continue;
31007 -               
31008 +
31009                 /* merge config */
31010                 for (j = 0; j < dc->value->used; j++) {
31011                         data_unset *du = dc->value->data[j];
31012 -                       
31013 +
31014                         if (0 == strcmp(du->key->ptr, "url.redirect")) {
31015                                 p->conf.redirect = s->redirect;
31016                                 p->conf.context = dc;
31017                         }
31018                 }
31019         }
31020 -       
31021 +
31022         return 0;
31023  }
31024  #endif
31025  static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_data) {
31026  #ifdef HAVE_PCRE_H
31027         plugin_data *p = p_data;
31028 -       size_t i;
31029 +       int i;
31030  
31031 -       /* 
31032 +       /*
31033          * REWRITE URL
31034 -        * 
31035 +        *
31036          * e.g. redirect /base/ to /index.php?section=base
31037 -        * 
31038 +        *
31039          */
31040 -       
31041 +
31042         mod_redirect_patch_connection(srv, con, p);
31043 -       
31044 +
31045         buffer_copy_string_buffer(p->match_buf, con->request.uri);
31046 -       
31047 -       for (i = 0; i < p->conf.redirect->used; i++) {
31048 -               pcre *match;
31049 -               pcre_extra *extra;
31050 -               const char *pattern;
31051 -               size_t pattern_len;
31052 -               int n;
31053 -               pcre_keyvalue *kv = p->conf.redirect->kv[i];
31054 -# define N 10
31055 -               int ovec[N * 3];
31056 -               
31057 -               match       = kv->key;
31058 -               extra       = kv->key_extra;
31059 -               pattern     = kv->value->ptr;
31060 -               pattern_len = kv->value->used - 1;
31061 -               
31062 -               if ((n = pcre_exec(match, extra, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
31063 -                       if (n != PCRE_ERROR_NOMATCH) {
31064 -                               log_error_write(srv, __FILE__, __LINE__, "sd",
31065 -                                               "execution error while matching: ", n);
31066 -                               return HANDLER_ERROR;
31067 -                       }
31068 -               } else {
31069 -                       const char **list;
31070 -                       size_t start, end;
31071 -                       size_t k;
31072 -                       
31073 -                       /* it matched */
31074 -                       pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list);
31075 -                       
31076 -                       /* search for $[0-9] */
31077 -                       
31078 -                       buffer_reset(p->location);
31079 -                       
31080 -                       start = 0; end = pattern_len;
31081 -                       for (k = 0; k < pattern_len; k++) {
31082 -                               if ((pattern[k] == '$' || pattern[k] == '%') &&
31083 -                                   isdigit((unsigned char)pattern[k + 1])) {
31084 -                                       /* got one */
31085 -                                       
31086 -                                       size_t num = pattern[k + 1] - '0';
31087 -                                       
31088 -                                       end = k;
31089 -                                       
31090 -                                       buffer_append_string_len(p->location, pattern + start, end - start);
31091 -                                       
31092 -                                       if (pattern[k] == '$') {
31093 -                                               /* n is always > 0 */
31094 -                                               if (num < (size_t)n) {
31095 -                                                       buffer_append_string(p->location, list[num]);
31096 -                                               }
31097 -                                       } else {
31098 -                                               config_append_cond_match_buffer(con, p->conf.context, p->location, num);
31099 -                                       }
31100 -                                       
31101 -                                       k++;
31102 -                                       start = k + 1;
31103 -                               } 
31104 -                       }
31105 -                       
31106 -                       buffer_append_string_len(p->location, pattern + start, pattern_len - start);
31107 -                       
31108 -                       pcre_free(list);
31109 -                       
31110 -                       response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location));
31111 -                       
31112 -                       con->http_status = 301;
31113 -                       con->file_finished = 1;
31114 -                       
31115 -                       return HANDLER_FINISHED;
31116 -               }
31117 +       i = config_exec_pcre_keyvalue_buffer(con, p->conf.redirect, p->conf.context, p->match_buf, p->location);
31118 +
31119 +       if (i >= 0) {
31120 +               response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location));
31121 +
31122 +               con->http_status = 301;
31123 +               con->file_finished = 1;
31124 +
31125 +               return HANDLER_FINISHED;
31126 +       }
31127 +       else if (i != PCRE_ERROR_NOMATCH) {
31128 +               log_error_write(srv, __FILE__, __LINE__, "s",
31129 +                               "execution error while matching", i);
31130         }
31131  #undef N
31132 -               
31133 +
31134  #else
31135         UNUSED(srv);
31136         UNUSED(con);
31137         UNUSED(p_data);
31138  #endif
31139 -       
31140 +
31141         return HANDLER_GO_ON;
31142  }
31143  
31144 @@ -265,13 +207,13 @@
31145  int mod_redirect_plugin_init(plugin *p) {
31146         p->version     = LIGHTTPD_VERSION_ID;
31147         p->name        = buffer_init_string("redirect");
31148 -       
31149 +
31150         p->init        = mod_redirect_init;
31151         p->handle_uri_clean  = mod_redirect_uri_handler;
31152         p->set_defaults  = mod_redirect_set_defaults;
31153         p->cleanup     = mod_redirect_free;
31154 -       
31155 +
31156         p->data        = NULL;
31157 -       
31158 +
31159         return 0;
31160  }
31161 --- ../lighttpd-1.4.11/src/mod_rewrite.c        2005-09-29 20:59:10.000000000 +0300
31162 +++ lighttpd-1.4.12/src/mod_rewrite.c   2006-07-16 00:26:03.000000000 +0300
31163 @@ -13,24 +13,8 @@
31164  #endif
31165  
31166  typedef struct {
31167 -#ifdef HAVE_PCRE_H
31168 -       pcre *key;
31169 -#endif
31170 -       
31171 -       buffer *value;
31172 -       
31173 -       int once;
31174 -} rewrite_rule;
31175 -
31176 -typedef struct {
31177 -       rewrite_rule **ptr;
31178 -       
31179 -       size_t used;
31180 -       size_t size;
31181 -} rewrite_rule_buffer;
31182 -
31183 -typedef struct {
31184 -       rewrite_rule_buffer *rewrite;
31185 +       pcre_keyvalue_buffer *rewrite;
31186 +       buffer *once;
31187         data_config *context; /* to which apply me */
31188  } plugin_config;
31189  
31190 @@ -42,20 +26,20 @@
31191  typedef struct {
31192         PLUGIN_DATA;
31193         buffer *match_buf;
31194 -       
31195 +
31196         plugin_config **config_storage;
31197 -       
31198 -       plugin_config conf; 
31199 +
31200 +       plugin_config conf;
31201  } plugin_data;
31202  
31203  static handler_ctx * handler_ctx_init() {
31204         handler_ctx * hctx;
31205 -       
31206 +
31207         hctx = calloc(1, sizeof(*hctx));
31208 -       
31209 +
31210         hctx->state = REWRITE_STATE_UNSET;
31211         hctx->loops = 0;
31212 -       
31213 +
31214         return hctx;
31215  }
31216  
31217 @@ -63,207 +47,136 @@
31218         free(hctx);
31219  }
31220  
31221 -rewrite_rule_buffer *rewrite_rule_buffer_init(void) {
31222 -       rewrite_rule_buffer *kvb;
31223 -       
31224 -       kvb = calloc(1, sizeof(*kvb));
31225 -       
31226 -       return kvb;
31227 -}
31228 -
31229 -int rewrite_rule_buffer_append(rewrite_rule_buffer *kvb, buffer *key, buffer *value, int once) {
31230 -#ifdef HAVE_PCRE_H
31231 -       size_t i;
31232 -       const char *errptr;
31233 -       int erroff;
31234 -       
31235 -       if (!key) return -1;
31236 -
31237 -       if (kvb->size == 0) {
31238 -               kvb->size = 4;
31239 -               kvb->used = 0;
31240 -               
31241 -               kvb->ptr = malloc(kvb->size * sizeof(*kvb->ptr));
31242 -               
31243 -               for(i = 0; i < kvb->size; i++) {
31244 -                       kvb->ptr[i] = calloc(1, sizeof(**kvb->ptr));
31245 -               }
31246 -       } else if (kvb->used == kvb->size) {
31247 -               kvb->size += 4;
31248 -               
31249 -               kvb->ptr = realloc(kvb->ptr, kvb->size * sizeof(*kvb->ptr));
31250 -               
31251 -               for(i = kvb->used; i < kvb->size; i++) {
31252 -                       kvb->ptr[i] = calloc(1, sizeof(**kvb->ptr));
31253 -               }
31254 -       }
31255 -       
31256 -       if (NULL == (kvb->ptr[kvb->used]->key = pcre_compile(key->ptr,
31257 -                                                           0, &errptr, &erroff, NULL))) {
31258 -               
31259 -               return -1;
31260 -       }
31261 -       
31262 -       kvb->ptr[kvb->used]->value = buffer_init();
31263 -       buffer_copy_string_buffer(kvb->ptr[kvb->used]->value, value);
31264 -       kvb->ptr[kvb->used]->once = once;
31265 -       
31266 -       kvb->used++;
31267 -       
31268 -       return 0;
31269 -#else
31270 -       UNUSED(kvb);
31271 -       UNUSED(value);
31272 -       UNUSED(once);
31273 -       UNUSED(key);
31274 -
31275 -       return -1;
31276 -#endif
31277 -}
31278 -
31279 -void rewrite_rule_buffer_free(rewrite_rule_buffer *kvb) {
31280 -#ifdef HAVE_PCRE_H
31281 -       size_t i;
31282 -
31283 -       for (i = 0; i < kvb->size; i++) {
31284 -               if (kvb->ptr[i]->key) pcre_free(kvb->ptr[i]->key);
31285 -               if (kvb->ptr[i]->value) buffer_free(kvb->ptr[i]->value);
31286 -               free(kvb->ptr[i]);
31287 -       }
31288 -       
31289 -       if (kvb->ptr) free(kvb->ptr);
31290 -#endif
31291 -       
31292 -       free(kvb);
31293 -}
31294 -
31295  
31296  INIT_FUNC(mod_rewrite_init) {
31297         plugin_data *p;
31298 -       
31299 +
31300         p = calloc(1, sizeof(*p));
31301 -       
31302 +
31303         p->match_buf = buffer_init();
31304 -       
31305 +
31306         return p;
31307  }
31308  
31309  FREE_FUNC(mod_rewrite_free) {
31310         plugin_data *p = p_d;
31311 -       
31312 +
31313         UNUSED(srv);
31314  
31315         if (!p) return HANDLER_GO_ON;
31316 -       
31317 +
31318         buffer_free(p->match_buf);
31319         if (p->config_storage) {
31320                 size_t i;
31321                 for (i = 0; i < srv->config_context->used; i++) {
31322                         plugin_config *s = p->config_storage[i];
31323 -                       rewrite_rule_buffer_free(s->rewrite);
31324 -                       
31325 +                       pcre_keyvalue_buffer_free(s->rewrite);
31326 +                       buffer_free(s->once);
31327 +
31328                         free(s);
31329                 }
31330                 free(p->config_storage);
31331         }
31332 -       
31333 +
31334         free(p);
31335 -       
31336 +
31337         return HANDLER_GO_ON;
31338  }
31339  
31340  static int parse_config_entry(server *srv, plugin_config *s, array *ca, const char *option, int once) {
31341         data_unset *du;
31342 -       
31343 +
31344         if (NULL != (du = array_get_element(ca, option))) {
31345                 data_array *da = (data_array *)du;
31346                 size_t j;
31347 -               
31348 +
31349                 if (du->type != TYPE_ARRAY) {
31350 -                       log_error_write(srv, __FILE__, __LINE__, "sss", 
31351 +                       log_error_write(srv, __FILE__, __LINE__, "sss",
31352                                         "unexpected type for key: ", option, "array of strings");
31353 -                       
31354 +
31355                         return HANDLER_ERROR;
31356                 }
31357 -               
31358 +
31359                 da = (data_array *)du;
31360 -               
31361 +
31362                 for (j = 0; j < da->value->used; j++) {
31363                         if (da->value->data[j]->type != TYPE_STRING) {
31364 -                               log_error_write(srv, __FILE__, __LINE__, "sssbs", 
31365 -                                               "unexpected type for key: ", 
31366 -                                               option, 
31367 +                               log_error_write(srv, __FILE__, __LINE__, "sssbs",
31368 +                                               "unexpected type for key: ",
31369 +                                               option,
31370                                                 "[", da->value->data[j]->key, "](string)");
31371 -                               
31372 +
31373                                 return HANDLER_ERROR;
31374                         }
31375 -                       
31376 -                       if (0 != rewrite_rule_buffer_append(s->rewrite, 
31377 -                                                           ((data_string *)(da->value->data[j]))->key,
31378 -                                                           ((data_string *)(da->value->data[j]))->value,
31379 -                                                           once)) {
31380 +
31381 +                       if (0 != pcre_keyvalue_buffer_append(s->rewrite,
31382 +                                                           ((data_string *)(da->value->data[j]))->key->ptr,
31383 +                                                           ((data_string *)(da->value->data[j]))->value->ptr)) {
31384  #ifdef HAVE_PCRE_H
31385 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
31386 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
31387                                                 "pcre-compile failed for", da->value->data[j]->key);
31388  #else
31389 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
31390 +                               log_error_write(srv, __FILE__, __LINE__, "s",
31391                                                 "pcre support is missing, please install libpcre and the headers");
31392  #endif
31393                         }
31394 +
31395 +                       if (once) {
31396 +                               buffer_append_string_len(s->once, CONST_STR_LEN("1"));
31397 +                       } else {
31398 +                               buffer_append_string_len(s->once, CONST_STR_LEN("0"));
31399 +                       }
31400                 }
31401         }
31402 -       
31403 +
31404         return 0;
31405  }
31406  
31407  SETDEFAULTS_FUNC(mod_rewrite_set_defaults) {
31408         plugin_data *p = p_d;
31409         size_t i = 0;
31410 -       
31411 -       config_values_t cv[] = { 
31412 +
31413 +       config_values_t cv[] = {
31414                 { "url.rewrite-repeat",        NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
31415                 { "url.rewrite-once",          NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
31416 -               
31417 -               /* old names, still supported 
31418 -                * 
31419 +
31420 +               /* old names, still supported
31421 +                *
31422                  * url.rewrite remapped to url.rewrite-once
31423                  * url.rewrite-final    is url.rewrite-once
31424 -                * 
31425 +                *
31426                  */
31427                 { "url.rewrite",               NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
31428                 { "url.rewrite-final",         NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
31429                 { NULL,                        NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
31430         };
31431 -       
31432 +
31433         if (!p) return HANDLER_ERROR;
31434 -       
31435 +
31436         /* 0 */
31437         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
31438 -       
31439 +
31440         for (i = 0; i < srv->config_context->used; i++) {
31441                 plugin_config *s;
31442                 array *ca;
31443 -               
31444 +
31445                 s = calloc(1, sizeof(plugin_config));
31446 -               s->rewrite   = rewrite_rule_buffer_init();
31447 -               
31448 -               cv[0].destination = s->rewrite;
31449 -               cv[1].destination = s->rewrite;
31450 -               cv[2].destination = s->rewrite;
31451 -               
31452 +               s->rewrite   = pcre_keyvalue_buffer_init();
31453 +               s->once      = buffer_init();
31454 +
31455                 p->config_storage[i] = s;
31456                 ca = ((data_config *)srv->config_context->data[i])->value;
31457 -       
31458 +
31459                 if (0 != config_insert_values_global(srv, ca, cv)) {
31460                         return HANDLER_ERROR;
31461                 }
31462 -               
31463 +
31464                 parse_config_entry(srv, s, ca, "url.rewrite-once",   1);
31465                 parse_config_entry(srv, s, ca, "url.rewrite-final",  1);
31466                 parse_config_entry(srv, s, ca, "url.rewrite",        1);
31467                 parse_config_entry(srv, s, ca, "url.rewrite-repeat", 0);
31468         }
31469 -       
31470 +
31471         return HANDLER_GO_ON;
31472  }
31473  #ifdef HAVE_PCRE_H
31474 @@ -271,157 +184,107 @@
31475         size_t i, j;
31476         plugin_config *s = p->config_storage[0];
31477         p->conf.rewrite = s->rewrite;
31478 -       
31479 +       p->conf.once    = s->once;
31480 +
31481         /* skip the first, the global context */
31482         for (i = 1; i < srv->config_context->used; i++) {
31483                 data_config *dc = (data_config *)srv->config_context->data[i];
31484                 s = p->config_storage[i];
31485 -               
31486 +
31487                 if (COMP_HTTP_URL == dc->comp) continue;
31488 -               
31489 +
31490                 /* condition didn't match */
31491                 if (!config_check_cond(srv, con, dc)) continue;
31492 -               
31493 +
31494                 /* merge config */
31495                 for (j = 0; j < dc->value->used; j++) {
31496                         data_unset *du = dc->value->data[j];
31497 -                       
31498 +
31499                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite"))) {
31500                                 p->conf.rewrite = s->rewrite;
31501 +                               p->conf.once    = s->once;
31502                                 p->conf.context = dc;
31503                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-once"))) {
31504                                 p->conf.rewrite = s->rewrite;
31505 +                               p->conf.once    = s->once;
31506                                 p->conf.context = dc;
31507                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-repeat"))) {
31508                                 p->conf.rewrite = s->rewrite;
31509 +                               p->conf.once    = s->once;
31510                                 p->conf.context = dc;
31511                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-final"))) {
31512                                 p->conf.rewrite = s->rewrite;
31513 +                               p->conf.once    = s->once;
31514                                 p->conf.context = dc;
31515                         }
31516                 }
31517         }
31518 -       
31519 +
31520         return 0;
31521  }
31522  #endif
31523  URIHANDLER_FUNC(mod_rewrite_con_reset) {
31524         plugin_data *p = p_d;
31525 -       
31526 +
31527         UNUSED(srv);
31528 -       
31529 +
31530         if (con->plugin_ctx[p->id]) {
31531                 handler_ctx_free(con->plugin_ctx[p->id]);
31532                 con->plugin_ctx[p->id] = NULL;
31533         }
31534 -       
31535 +
31536         return HANDLER_GO_ON;
31537  }
31538  
31539  URIHANDLER_FUNC(mod_rewrite_uri_handler) {
31540  #ifdef HAVE_PCRE_H
31541         plugin_data *p = p_d;
31542 -       size_t i;
31543 +       int i;
31544         handler_ctx *hctx;
31545  
31546 -       /* 
31547 +       /*
31548          * REWRITE URL
31549 -        * 
31550 +        *
31551          * e.g. rewrite /base/ to /index.php?section=base
31552 -        * 
31553 +        *
31554          */
31555 -       
31556 +
31557         if (con->plugin_ctx[p->id]) {
31558                 hctx = con->plugin_ctx[p->id];
31559 -               
31560 +
31561                 if (hctx->loops++ > 100) {
31562 -                       log_error_write(srv, __FILE__, __LINE__,  "s",  
31563 +                       log_error_write(srv, __FILE__, __LINE__,  "s",
31564                                         "ENDLESS LOOP IN rewrite-rule DETECTED ... aborting request, perhaps you want to use url.rewrite-once instead of url.rewrite-repeat");
31565 -                       
31566 +
31567                         return HANDLER_ERROR;
31568                 }
31569 -               
31570 +
31571                 if (hctx->state == REWRITE_STATE_FINISHED) return HANDLER_GO_ON;
31572         }
31573 -       
31574 +
31575         mod_rewrite_patch_connection(srv, con, p);
31576  
31577         if (!p->conf.rewrite) return HANDLER_GO_ON;
31578 -       
31579 +
31580         buffer_copy_string_buffer(p->match_buf, con->request.uri);
31581 -       
31582 -       for (i = 0; i < p->conf.rewrite->used; i++) {
31583 -               pcre *match;
31584 -               const char *pattern;
31585 -               size_t pattern_len;
31586 -               int n;
31587 -               rewrite_rule *rule = p->conf.rewrite->ptr[i];
31588 -# define N 10
31589 -               int ovec[N * 3];
31590 -               
31591 -               match       = rule->key;
31592 -               pattern     = rule->value->ptr;
31593 -               pattern_len = rule->value->used - 1;
31594 -               
31595 -               if ((n = pcre_exec(match, NULL, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
31596 -                       if (n != PCRE_ERROR_NOMATCH) {
31597 -                               log_error_write(srv, __FILE__, __LINE__, "sd",
31598 -                                               "execution error while matching: ", n);
31599 -                               return HANDLER_ERROR;
31600 -                       }
31601 -               } else {
31602 -                       const char **list;
31603 -                       size_t start, end;
31604 -                       size_t k;
31605 -                       
31606 -                       /* it matched */
31607 -                       pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list);
31608 -                       
31609 -                       /* search for $[0-9] */
31610 -                       
31611 -                       buffer_reset(con->request.uri);
31612 -                       
31613 -                       start = 0; end = pattern_len;
31614 -                       for (k = 0; k < pattern_len; k++) {
31615 -                               if ((pattern[k] == '$' || pattern[k] == '%') &&
31616 -                                   isdigit((unsigned char)pattern[k + 1])) {
31617 -                                       /* got one */
31618 -                                       
31619 -                                       size_t num = pattern[k + 1] - '0';
31620 -                                       
31621 -                                       end = k;
31622 -                                       
31623 -                                       buffer_append_string_len(con->request.uri, pattern + start, end - start);
31624 -                                       
31625 -                                       if (pattern[k] == '$') {
31626 -                                               /* n is always > 0 */
31627 -                                               if (num < (size_t)n) {
31628 -                                                       buffer_append_string(con->request.uri, list[num]);
31629 -                                               }
31630 -                                       } else {
31631 -                                               config_append_cond_match_buffer(con, p->conf.context, con->request.uri, num);
31632 -                                       }
31633 -                                       
31634 -                                       k++;
31635 -                                       start = k + 1;
31636 -                               } 
31637 -                       }
31638 -                       
31639 -                       buffer_append_string_len(con->request.uri, pattern + start, pattern_len - start);
31640 -                       
31641 -                       pcre_free(list);
31642 -                       
31643 -                       hctx = handler_ctx_init();
31644 -                               
31645 -                       con->plugin_ctx[p->id] = hctx;
31646 -                       
31647 -                       if (rule->once) hctx->state = REWRITE_STATE_FINISHED;
31648 -                       
31649 -                       return HANDLER_COMEBACK;
31650 -               }
31651 +       i = config_exec_pcre_keyvalue_buffer(con, p->conf.rewrite, p->conf.context, p->match_buf, con->request.uri);
31652 +
31653 +       if (i >= 0) {
31654 +               hctx = handler_ctx_init();
31655 +
31656 +               con->plugin_ctx[p->id] = hctx;
31657 +
31658 +               if (p->conf.once->ptr[i] == '1')
31659 +                       hctx->state = REWRITE_STATE_FINISHED;
31660 +
31661 +               return HANDLER_COMEBACK;
31662 +       }
31663 +       else if (i != PCRE_ERROR_NOMATCH) {
31664 +               log_error_write(srv, __FILE__, __LINE__, "s",
31665 +                               "execution error while matching", i);
31666         }
31667  #undef N
31668 -               
31669 +
31670  #else
31671         UNUSED(srv);
31672         UNUSED(con);
31673 @@ -434,17 +297,17 @@
31674  int mod_rewrite_plugin_init(plugin *p) {
31675         p->version     = LIGHTTPD_VERSION_ID;
31676         p->name        = buffer_init_string("rewrite");
31677 -       
31678 +
31679         p->init        = mod_rewrite_init;
31680         /* it has to stay _raw as we are matching on uri + querystring
31681          */
31682 -       
31683 +
31684         p->handle_uri_raw = mod_rewrite_uri_handler;
31685         p->set_defaults = mod_rewrite_set_defaults;
31686         p->cleanup     = mod_rewrite_free;
31687         p->connection_reset = mod_rewrite_con_reset;
31688 -       
31689 +
31690         p->data        = NULL;
31691 -       
31692 +
31693         return 0;
31694  }
31695 --- ../lighttpd-1.4.11/src/mod_rrdtool.c        2005-08-22 01:52:24.000000000 +0300
31696 +++ lighttpd-1.4.12/src/mod_rrdtool.c   2006-07-18 13:03:40.000000000 +0300
31697 @@ -5,7 +5,6 @@
31698  #include <stdlib.h>
31699  #include <stdio.h>
31700  #include <string.h>
31701 -#include <unistd.h>
31702  #include <errno.h>
31703  #include <time.h>
31704  
31705 @@ -20,10 +19,14 @@
31706  /* no need for waitpid if we don't have fork */
31707  #include <sys/wait.h>
31708  #endif
31709 +
31710 +#include "sys-files.h"
31711 +#include "sys-process.h"
31712 +
31713  typedef struct {
31714         buffer *path_rrdtool_bin;
31715         buffer *path_rrd;
31716 -       
31717 +
31718         double requests, *requests_ptr;
31719         double bytes_written, *bytes_written_ptr;
31720         double bytes_read, *bytes_read_ptr;
31721 @@ -31,84 +34,84 @@
31722  
31723  typedef struct {
31724         PLUGIN_DATA;
31725 -       
31726 +
31727         buffer *cmd;
31728         buffer *resp;
31729 -       
31730 +
31731         int read_fd, write_fd;
31732         pid_t rrdtool_pid;
31733 -       
31734 +
31735         int rrdtool_running;
31736 -       
31737 +
31738         plugin_config **config_storage;
31739         plugin_config conf;
31740  } plugin_data;
31741  
31742  INIT_FUNC(mod_rrd_init) {
31743         plugin_data *p;
31744 -       
31745 +
31746         p = calloc(1, sizeof(*p));
31747 -       
31748 +
31749         p->resp = buffer_init();
31750         p->cmd = buffer_init();
31751 -       
31752 +
31753         return p;
31754  }
31755  
31756  FREE_FUNC(mod_rrd_free) {
31757         plugin_data *p = p_d;
31758         size_t i;
31759 -       
31760 +
31761         if (!p) return HANDLER_GO_ON;
31762 -       
31763 +
31764         if (p->config_storage) {
31765                 for (i = 0; i < srv->config_context->used; i++) {
31766                         plugin_config *s = p->config_storage[i];
31767 -                       
31768 +
31769                         buffer_free(s->path_rrdtool_bin);
31770                         buffer_free(s->path_rrd);
31771 -                       
31772 +
31773                         free(s);
31774                 }
31775         }
31776         buffer_free(p->cmd);
31777         buffer_free(p->resp);
31778 -       
31779 +
31780         free(p->config_storage);
31781 -       
31782 +
31783         if (p->rrdtool_pid) {
31784                 int status;
31785                 close(p->read_fd);
31786                 close(p->write_fd);
31787 -#ifdef HAVE_FORK       
31788 +#ifdef HAVE_FORK
31789                 /* collect status */
31790                 waitpid(p->rrdtool_pid, &status, 0);
31791  #endif
31792         }
31793 -       
31794 +
31795         free(p);
31796 -       
31797 +
31798         return HANDLER_GO_ON;
31799  }
31800  
31801  int mod_rrd_create_pipe(server *srv, plugin_data *p) {
31802         pid_t pid;
31803 -       
31804 +
31805         int to_rrdtool_fds[2];
31806         int from_rrdtool_fds[2];
31807 -#ifdef HAVE_FORK       
31808 +#ifdef HAVE_FORK
31809         if (pipe(to_rrdtool_fds)) {
31810 -               log_error_write(srv, __FILE__, __LINE__, "ss", 
31811 +               log_error_write(srv, __FILE__, __LINE__, "ss",
31812                                 "pipe failed: ", strerror(errno));
31813                 return -1;
31814         }
31815 -       
31816 +
31817         if (pipe(from_rrdtool_fds)) {
31818 -               log_error_write(srv, __FILE__, __LINE__, "ss", 
31819 +               log_error_write(srv, __FILE__, __LINE__, "ss",
31820                                 "pipe failed: ", strerror(errno));
31821                 return -1;
31822         }
31823 -       
31824 +
31825         /* fork, execve */
31826         switch (pid = fork()) {
31827         case 0: {
31828 @@ -117,33 +120,28 @@
31829                 int argc;
31830                 int i = 0;
31831                 char *dash = "-";
31832 -               
31833 +
31834                 /* move stdout to from_rrdtool_fd[1] */
31835                 close(STDOUT_FILENO);
31836                 dup2(from_rrdtool_fds[1], STDOUT_FILENO);
31837                 close(from_rrdtool_fds[1]);
31838                 /* not needed */
31839                 close(from_rrdtool_fds[0]);
31840 -               
31841 +
31842                 /* move the stdin to to_rrdtool_fd[0] */
31843                 close(STDIN_FILENO);
31844                 dup2(to_rrdtool_fds[0], STDIN_FILENO);
31845                 close(to_rrdtool_fds[0]);
31846                 /* not needed */
31847                 close(to_rrdtool_fds[1]);
31848 -               
31849 +
31850                 close(STDERR_FILENO);
31851 -               
31852 -               if (srv->errorlog_mode == ERRORLOG_FILE) {
31853 -                       dup2(srv->errorlog_fd, STDERR_FILENO);
31854 -                       close(srv->errorlog_fd);
31855 -               }
31856 -               
31857 +
31858                 /* set up args */
31859                 argc = 3;
31860                 args = malloc(sizeof(*args) * argc);
31861                 i = 0;
31862 -               
31863 +
31864                 args[i++] = p->conf.path_rrdtool_bin->ptr;
31865                 args[i++] = dash;
31866                 args[i++] = NULL;
31867 @@ -152,12 +150,12 @@
31868                 for (i = 3; i < 256; i++) {
31869                         close(i);
31870                 }
31871 -               
31872 +
31873                 /* exec the cgi */
31874                 execv(args[0], args);
31875 -               
31876 +
31877                 log_error_write(srv, __FILE__, __LINE__, "sss", "spawing rrdtool failed: ", strerror(errno), args[0]);
31878 -               
31879 +
31880                 /* */
31881                 SEGFAULT();
31882                 break;
31883 @@ -168,19 +166,19 @@
31884                 break;
31885         default: {
31886                 /* father */
31887 -               
31888 +
31889                 close(from_rrdtool_fds[1]);
31890                 close(to_rrdtool_fds[0]);
31891 -               
31892 +
31893                 /* register PID and wait for them asyncronously */
31894                 p->write_fd = to_rrdtool_fds[1];
31895                 p->read_fd = from_rrdtool_fds[0];
31896                 p->rrdtool_pid = pid;
31897 -               
31898 +
31899                 break;
31900         }
31901         }
31902 -       
31903 +
31904         return 0;
31905  #else
31906         return -1;
31907 @@ -189,19 +187,19 @@
31908  
31909  static int mod_rrdtool_create_rrd(server *srv, plugin_data *p, plugin_config *s) {
31910         struct stat st;
31911 -       
31912 +
31913         /* check if DB already exists */
31914         if (0 == stat(s->path_rrd->ptr, &st)) {
31915                 /* check if it is plain file */
31916                 if (!S_ISREG(st.st_mode)) {
31917 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
31918 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
31919                                         "not a regular file:", s->path_rrd);
31920                         return HANDLER_ERROR;
31921                 }
31922         } else {
31923                 int r ;
31924                 /* create a new one */
31925 -               
31926 +
31927                 BUFFER_COPY_STRING_CONST(p->cmd, "create ");
31928                 buffer_append_string_buffer(p->cmd, s->path_rrd);
31929                 buffer_append_string(p->cmd, " --step 60 ");
31930 @@ -220,158 +218,155 @@
31931                 buffer_append_string(p->cmd, "RRA:MIN:0.5:6:700 ");
31932                 buffer_append_string(p->cmd, "RRA:MIN:0.5:24:775 ");
31933                 buffer_append_string(p->cmd, "RRA:MIN:0.5:288:797\n");
31934 -               
31935 +
31936                 if (-1 == (r = write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
31937 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
31938 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
31939                                 "rrdtool-write: failed", strerror(errno));
31940 -                       
31941 +
31942                         return HANDLER_ERROR;
31943                 }
31944 -               
31945 +
31946                 buffer_prepare_copy(p->resp, 4096);
31947                 if (-1 == (r = read(p->read_fd, p->resp->ptr, p->resp->size))) {
31948 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
31949 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
31950                                 "rrdtool-read: failed", strerror(errno));
31951 -                       
31952 +
31953                         return HANDLER_ERROR;
31954                 }
31955 -               
31956 +
31957                 p->resp->used = r;
31958 -               
31959 +
31960                 if (p->resp->ptr[0] != 'O' ||
31961                     p->resp->ptr[1] != 'K') {
31962 -                       log_error_write(srv, __FILE__, __LINE__, "sbb", 
31963 +                       log_error_write(srv, __FILE__, __LINE__, "sbb",
31964                                 "rrdtool-response:", p->cmd, p->resp);
31965 -                       
31966 +
31967                         return HANDLER_ERROR;
31968                 }
31969         }
31970 -       
31971 +
31972         return HANDLER_GO_ON;
31973  }
31974  
31975 -#define PATCH(x) \
31976 -       p->conf.x = s->x;
31977  static int mod_rrd_patch_connection(server *srv, connection *con, plugin_data *p) {
31978         size_t i, j;
31979         plugin_config *s = p->config_storage[0];
31980 -       
31981 -       PATCH(path_rrdtool_bin);
31982 -       PATCH(path_rrd);
31983 -       
31984 +
31985 +       PATCH_OPTION(path_rrdtool_bin);
31986 +       PATCH_OPTION(path_rrd);
31987 +
31988         p->conf.bytes_written_ptr = &(s->bytes_written);
31989         p->conf.bytes_read_ptr = &(s->bytes_read);
31990         p->conf.requests_ptr = &(s->requests);
31991 -       
31992 +
31993         /* skip the first, the global context */
31994         for (i = 1; i < srv->config_context->used; i++) {
31995                 data_config *dc = (data_config *)srv->config_context->data[i];
31996                 s = p->config_storage[i];
31997 -               
31998 +
31999                 /* condition didn't match */
32000                 if (!config_check_cond(srv, con, dc)) continue;
32001 -               
32002 +
32003                 /* merge config */
32004                 for (j = 0; j < dc->value->used; j++) {
32005                         data_unset *du = dc->value->data[j];
32006 -                       
32007 +
32008                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("rrdtool.db-name"))) {
32009 -                               PATCH(path_rrd);
32010 +                               PATCH_OPTION(path_rrd);
32011                                 /* get pointers to double values */
32012 -                               
32013 +
32014                                 p->conf.bytes_written_ptr = &(s->bytes_written);
32015                                 p->conf.bytes_read_ptr = &(s->bytes_read);
32016                                 p->conf.requests_ptr = &(s->requests);
32017                         }
32018                 }
32019         }
32020 -       
32021 +
32022         return 0;
32023  }
32024 -#undef PATCH
32025  
32026  SETDEFAULTS_FUNC(mod_rrd_set_defaults) {
32027         plugin_data *p = p_d;
32028         size_t i;
32029 -       
32030 -       config_values_t cv[] = { 
32031 +
32032 +       config_values_t cv[] = {
32033                 { "rrdtool.binary",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
32034                 { "rrdtool.db-name",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
32035                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
32036         };
32037 -       
32038 +
32039         if (!p) return HANDLER_ERROR;
32040 -       
32041 +
32042         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
32043 -       
32044 +
32045         for (i = 0; i < srv->config_context->used; i++) {
32046                 plugin_config *s;
32047 -               
32048 +
32049                 s = calloc(1, sizeof(plugin_config));
32050                 s->path_rrdtool_bin = buffer_init();
32051                 s->path_rrd = buffer_init();
32052                 s->requests = 0;
32053                 s->bytes_written = 0;
32054                 s->bytes_read = 0;
32055 -               
32056 +
32057                 cv[0].destination = s->path_rrdtool_bin;
32058                 cv[1].destination = s->path_rrd;
32059 -               
32060 +
32061                 p->config_storage[i] = s;
32062 -       
32063 +
32064                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
32065                         return HANDLER_ERROR;
32066                 }
32067 -               
32068 +
32069                 if (i > 0 && !buffer_is_empty(s->path_rrdtool_bin)) {
32070                         /* path_rrdtool_bin is a global option */
32071 -                       
32072 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
32073 +
32074 +                       log_error_write(srv, __FILE__, __LINE__, "s",
32075                                         "rrdtool.binary can only be set as a global option.");
32076 -                       
32077 +
32078                         return HANDLER_ERROR;
32079                 }
32080 -               
32081 +
32082         }
32083 -       
32084 +
32085         p->conf.path_rrdtool_bin = p->config_storage[0]->path_rrdtool_bin;
32086         p->rrdtool_running = 0;
32087 -       
32088 +
32089         /* check for dir */
32090 -       
32091 +
32092         if (buffer_is_empty(p->conf.path_rrdtool_bin)) {
32093 -               log_error_write(srv, __FILE__, __LINE__, "s", 
32094 +               log_error_write(srv, __FILE__, __LINE__, "s",
32095                                 "rrdtool.binary has to be set");
32096                 return HANDLER_ERROR;
32097         }
32098 -       
32099 +
32100         /* open the pipe to rrdtool */
32101         if (mod_rrd_create_pipe(srv, p)) {
32102                 return HANDLER_ERROR;
32103         }
32104 -       
32105 +
32106         p->rrdtool_running = 1;
32107 -               
32108 +
32109         return HANDLER_GO_ON;
32110  }
32111  
32112  TRIGGER_FUNC(mod_rrd_trigger) {
32113         plugin_data *p = p_d;
32114         size_t i;
32115 -       
32116 +
32117         if (!p->rrdtool_running) return HANDLER_GO_ON;
32118         if ((srv->cur_ts % 60) != 0) return HANDLER_GO_ON;
32119 -       
32120 +
32121         for (i = 0; i < srv->config_context->used; i++) {
32122                 plugin_config *s = p->config_storage[i];
32123                 int r;
32124 -               
32125 +
32126                 if (buffer_is_empty(s->path_rrd)) continue;
32127 -       
32128 +
32129                 /* write the data down every minute */
32130 -               
32131 +
32132                 if (HANDLER_GO_ON != mod_rrdtool_create_rrd(srv, p, s)) return HANDLER_ERROR;
32133 -               
32134 +
32135                 BUFFER_COPY_STRING_CONST(p->cmd, "update ");
32136                 buffer_append_string_buffer(p->cmd, s->path_rrd);
32137                 BUFFER_APPEND_STRING_CONST(p->cmd, " N:");
32138 @@ -381,69 +376,69 @@
32139                 BUFFER_APPEND_STRING_CONST(p->cmd, ":");
32140                 buffer_append_long(p->cmd, s->requests);
32141                 BUFFER_APPEND_STRING_CONST(p->cmd, "\n");
32142 -               
32143 +
32144                 if (-1 == (r = write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
32145                         p->rrdtool_running = 0;
32146 -                       
32147 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
32148 +
32149 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
32150                                         "rrdtool-write: failed", strerror(errno));
32151 -                       
32152 +
32153                         return HANDLER_ERROR;
32154                 }
32155 -               
32156 +
32157                 buffer_prepare_copy(p->resp, 4096);
32158                 if (-1 == (r = read(p->read_fd, p->resp->ptr, p->resp->size))) {
32159                         p->rrdtool_running = 0;
32160 -                       
32161 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
32162 +
32163 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
32164                                         "rrdtool-read: failed", strerror(errno));
32165 -                       
32166 +
32167                         return HANDLER_ERROR;
32168                 }
32169 -               
32170 +
32171                 p->resp->used = r;
32172 -               
32173 +
32174                 if (p->resp->ptr[0] != 'O' ||
32175                     p->resp->ptr[1] != 'K') {
32176                         p->rrdtool_running = 0;
32177 -                       
32178 -                       log_error_write(srv, __FILE__, __LINE__, "sbb", 
32179 +
32180 +                       log_error_write(srv, __FILE__, __LINE__, "sbb",
32181                                         "rrdtool-response:", p->cmd, p->resp);
32182 -                       
32183 +
32184                         return HANDLER_ERROR;
32185                 }
32186                 s->requests = 0;
32187                 s->bytes_written = 0;
32188                 s->bytes_read = 0;
32189         }
32190 -       
32191 +
32192         return HANDLER_GO_ON;
32193  }
32194  
32195  REQUESTDONE_FUNC(mod_rrd_account) {
32196         plugin_data *p = p_d;
32197 -       
32198 +
32199         mod_rrd_patch_connection(srv, con, p);
32200 -       
32201 +
32202         *(p->conf.requests_ptr)      += 1;
32203         *(p->conf.bytes_written_ptr) += con->bytes_written;
32204         *(p->conf.bytes_read_ptr)    += con->bytes_read;
32205 -       
32206 +
32207         return HANDLER_GO_ON;
32208  }
32209  
32210  int mod_rrdtool_plugin_init(plugin *p) {
32211         p->version     = LIGHTTPD_VERSION_ID;
32212         p->name        = buffer_init_string("rrd");
32213 -       
32214 +
32215         p->init        = mod_rrd_init;
32216         p->cleanup     = mod_rrd_free;
32217         p->set_defaults= mod_rrd_set_defaults;
32218 -       
32219 +
32220         p->handle_trigger      = mod_rrd_trigger;
32221         p->handle_request_done = mod_rrd_account;
32222 -       
32223 +
32224         p->data        = NULL;
32225 -       
32226 +
32227         return 0;
32228  }
32229 --- ../lighttpd-1.4.11/src/mod_scgi.c   2006-03-04 17:15:26.000000000 +0200
32230 +++ lighttpd-1.4.12/src/mod_scgi.c      2006-07-18 13:03:40.000000000 +0300
32231 @@ -1,5 +1,4 @@
32232  #include <sys/types.h>
32233 -#include <unistd.h>
32234  #include <errno.h>
32235  #include <fcntl.h>
32236  #include <string.h>
32237 @@ -18,6 +17,7 @@
32238  #include "connections.h"
32239  #include "response.h"
32240  #include "joblist.h"
32241 +#include "http_resp.h"
32242  
32243  #include "plugin.h"
32244  
32245 @@ -30,7 +30,9 @@
32246  #endif
32247  
32248  #include "sys-socket.h"
32249 -
32250 +#include "sys-files.h"
32251 +#include "sys-strings.h"
32252 +#include "sys-process.h"
32253  
32254  #ifndef UNIX_PATH_MAX
32255  # define UNIX_PATH_MAX 108
32256 @@ -46,30 +48,29 @@
32257  enum {EOL_UNSET, EOL_N, EOL_RN};
32258  
32259  /*
32260 - * 
32261 + *
32262   * TODO:
32263 - * 
32264 + *
32265   * - add timeout for a connect to a non-scgi process
32266   *   (use state_timestamp + state)
32267 - * 
32268 + *
32269   */
32270  
32271  typedef struct scgi_proc {
32272         size_t id; /* id will be between 1 and max_procs */
32273         buffer *socket; /* config.socket + "-" + id */
32274         unsigned port;  /* config.port + pno */
32275 -       
32276 -       pid_t pid;   /* PID of the spawned process (0 if not spawned locally) */
32277  
32278 +       pid_t pid;   /* PID of the spawned process (0 if not spawned locally) */
32279  
32280         size_t load; /* number of requests waiting on this process */
32281  
32282         time_t last_used; /* see idle_timeout */
32283         size_t requests;  /* see max_requests */
32284         struct scgi_proc *prev, *next; /* see first */
32285 -       
32286 +
32287         time_t disable_ts; /* replace by host->something */
32288 -       
32289 +
32290         int is_local;
32291  
32292         enum { PROC_STATE_UNSET,            /* init-phase */
32293 @@ -78,7 +79,7 @@
32294                         PROC_STATE_KILLED,  /* was killed as we don't have the load anymore */
32295                         PROC_STATE_DIED,    /* marked as dead, should be restarted */
32296                         PROC_STATE_DISABLED /* proc disabled as it resulted in an error */
32297 -       } state; 
32298 +       } state;
32299  } scgi_proc;
32300  
32301  typedef struct {
32302 @@ -86,20 +87,20 @@
32303          * sorted by lowest load
32304          *
32305          * whenever a job is done move it up in the list
32306 -        * until it is sorted, move it down as soon as the 
32307 +        * until it is sorted, move it down as soon as the
32308          * job is started
32309          */
32310 -       scgi_proc *first; 
32311 -       scgi_proc *unused_procs; 
32312 +       scgi_proc *first;
32313 +       scgi_proc *unused_procs;
32314  
32315 -       /* 
32316 +       /*
32317          * spawn at least min_procs, at max_procs.
32318          *
32319 -        * as soon as the load of the first entry 
32320 +        * as soon as the load of the first entry
32321          * is max_load_per_proc we spawn a new one
32322 -        * and add it to the first entry and give it 
32323 +        * and add it to the first entry and give it
32324          * the load
32325 -        * 
32326 +        *
32327          */
32328  
32329         unsigned short min_procs;
32330 @@ -111,44 +112,44 @@
32331  
32332         /*
32333          * kick the process from the list if it was not
32334 -        * used for idle_timeout until min_procs is 
32335 +        * used for idle_timeout until min_procs is
32336          * reached. this helps to get the processlist
32337          * small again we had a small peak load.
32338          *
32339          */
32340 -       
32341 +
32342         unsigned short idle_timeout;
32343 -       
32344 +
32345         /*
32346          * time after a disabled remote connection is tried to be re-enabled
32347 -        * 
32348 -        * 
32349 +        *
32350 +        *
32351          */
32352 -       
32353 +
32354         unsigned short disable_time;
32355  
32356         /*
32357          * same scgi processes get a little bit larger
32358 -        * than wanted. max_requests_per_proc kills a 
32359 +        * than wanted. max_requests_per_proc kills a
32360          * process after a number of handled requests.
32361          *
32362          */
32363         size_t max_requests_per_proc;
32364 -       
32365 +
32366  
32367         /* config */
32368  
32369 -       /* 
32370 -        * host:port 
32371 +       /*
32372 +        * host:port
32373          *
32374 -        * if host is one of the local IP adresses the 
32375 +        * if host is one of the local IP adresses the
32376          * whole connection is local
32377          *
32378          * if tcp/ip should be used host AND port have
32379 -        * to be specified 
32380 -        * 
32381 -        */ 
32382 -       buffer *host; 
32383 +        * to be specified
32384 +        *
32385 +        */
32386 +       buffer *host;
32387         unsigned short port;
32388  
32389         /*
32390 @@ -161,7 +162,7 @@
32391          */
32392         buffer *unixsocket;
32393  
32394 -       /* if socket is local we can start the scgi 
32395 +       /* if socket is local we can start the scgi
32396          * process ourself
32397          *
32398          * bin-path is the path to the binary
32399 @@ -169,19 +170,19 @@
32400          * check min_procs and max_procs for the number
32401          * of process to start-up
32402          */
32403 -       buffer *bin_path; 
32404 -       
32405 -       /* bin-path is set bin-environment is taken to 
32406 +       buffer *bin_path;
32407 +
32408 +       /* bin-path is set bin-environment is taken to
32409          * create the environement before starting the
32410          * FastCGI process
32411 -        * 
32412 +        *
32413          */
32414         array *bin_env;
32415 -       
32416 +
32417         array *bin_env_copy;
32418 -       
32419 +
32420         /*
32421 -        * docroot-translation between URL->phys and the 
32422 +        * docroot-translation between URL->phys and the
32423          * remote host
32424          *
32425          * reasons:
32426 @@ -192,7 +193,7 @@
32427         buffer *docroot;
32428  
32429         /*
32430 -        * check_local tell you if the phys file is stat()ed 
32431 +        * check_local tell you if the phys file is stat()ed
32432          * or not. FastCGI doesn't care if the service is
32433          * remote. If the web-server side doesn't contain
32434          * the scgi-files we should not stat() for them
32435 @@ -202,33 +203,33 @@
32436  
32437         /*
32438          * append PATH_INFO to SCRIPT_FILENAME
32439 -        * 
32440 +        *
32441          * php needs this if cgi.fix_pathinfo is provied
32442 -        * 
32443 +        *
32444          */
32445 -       
32446 +
32447         ssize_t load; /* replace by host->load */
32448  
32449         size_t max_id; /* corresponds most of the time to
32450         num_procs.
32451 -       
32452 +
32453         only if a process is killed max_id waits for the process itself
32454         to die and decrements its afterwards */
32455  } scgi_extension_host;
32456  
32457  /*
32458   * one extension can have multiple hosts assigned
32459 - * one host can spawn additional processes on the same 
32460 + * one host can spawn additional processes on the same
32461   *   socket (if we control it)
32462   *
32463   * ext -> host -> procs
32464   *    1:n     1:n
32465   *
32466 - * if the scgi process is remote that whole goes down 
32467 + * if the scgi process is remote that whole goes down
32468   * to
32469   *
32470   * ext -> host -> procs
32471 - *    1:n     1:1 
32472 + *    1:n     1:1
32473   *
32474   * in case of PHP and FCGI_CHILDREN we have again a procs
32475   * but we don't control it directly.
32476 @@ -239,7 +240,7 @@
32477         buffer *key; /* like .php */
32478  
32479         scgi_extension_host **hosts;
32480 -       
32481 +
32482         size_t used;
32483         size_t size;
32484  } scgi_extension;
32485 @@ -253,14 +254,14 @@
32486  
32487  
32488  typedef struct {
32489 -       scgi_exts *exts; 
32490 -       
32491 +       scgi_exts *exts;
32492 +
32493         int debug;
32494  } plugin_config;
32495  
32496  typedef struct {
32497         char **ptr;
32498 -       
32499 +
32500         size_t size;
32501         size_t used;
32502  } char_array;
32503 @@ -268,52 +269,51 @@
32504  /* generic plugin data, shared between all connections */
32505  typedef struct {
32506         PLUGIN_DATA;
32507 -       
32508 +
32509         buffer *scgi_env;
32510 -       
32511 +
32512         buffer *path;
32513 -       buffer *parse_response;
32514 -       
32515 +
32516 +       http_resp *resp;
32517 +
32518         plugin_config **config_storage;
32519 -       
32520 +
32521         plugin_config conf; /* this is only used as long as no handler_ctx is setup */
32522  } plugin_data;
32523  
32524  /* connection specific data */
32525 -typedef enum { FCGI_STATE_INIT, FCGI_STATE_CONNECT, FCGI_STATE_PREPARE_WRITE, 
32526 -               FCGI_STATE_WRITE, FCGI_STATE_READ 
32527 +typedef enum {
32528 +       SCGI_STATE_INIT,
32529 +       SCGI_STATE_CONNECT,
32530 +       SCGI_STATE_PREPARE_WRITE,
32531 +       SCGI_STATE_WRITE,
32532 +       SCGI_STATE_RESPONSE_HEADER,
32533 +       SCGI_STATE_RESPONSE_CONTENT,
32534 +       SCGI_STATE_ERROR
32535  } scgi_connection_state_t;
32536  
32537  typedef struct {
32538 -       buffer  *response; 
32539 -       size_t   response_len;
32540 -       int      response_type;
32541 -       int      response_padding;
32542 -       
32543         scgi_proc *proc;
32544         scgi_extension_host *host;
32545 -       
32546 +
32547         scgi_connection_state_t state;
32548         time_t   state_timestamp;
32549 -       
32550 +
32551         int      reconnects; /* number of reconnect attempts */
32552 -       
32553 -       read_buffer *rb;
32554 +
32555 +       chunkqueue *rb;
32556         chunkqueue *wb;
32557 -       
32558 -       buffer   *response_header;
32559 -       
32560 +
32561         int       delayed;   /* flag to mark that the connect() is delayed */
32562 -       
32563 +
32564         size_t    request_id;
32565 -       int       fd;        /* fd to the scgi process */
32566 -       int       fde_ndx;   /* index into the fd-event buffer */
32567 +       iosocket  *sock;        /* fd to the scgi process */
32568  
32569         pid_t     pid;
32570         int       got_proc;
32571 -       
32572 +
32573         plugin_config conf;
32574 -       
32575 +
32576         connection *remote_conn;  /* dumb pointer */
32577         plugin_data *plugin_data; /* dumb pointer */
32578  } handler_ctx;
32579 @@ -328,42 +328,30 @@
32580  
32581  static handler_ctx * handler_ctx_init() {
32582         handler_ctx * hctx;
32583 -       
32584 +
32585         hctx = calloc(1, sizeof(*hctx));
32586         assert(hctx);
32587 -       
32588 -       hctx->fde_ndx = -1;
32589 -       
32590 -       hctx->response = buffer_init();
32591 -       hctx->response_header = buffer_init();
32592 -       
32593 +
32594 +       hctx->sock = iosocket_init();;
32595 +
32596         hctx->request_id = 0;
32597 -       hctx->state = FCGI_STATE_INIT;
32598 +       hctx->state = SCGI_STATE_INIT;
32599         hctx->proc = NULL;
32600 -       
32601 -       hctx->response_len = 0;
32602 -       hctx->response_type = 0;
32603 -       hctx->response_padding = 0;
32604 -       hctx->fd = -1;
32605 -       
32606 +
32607         hctx->reconnects = 0;
32608  
32609         hctx->wb = chunkqueue_init();
32610 -       
32611 +       hctx->rb = chunkqueue_init();
32612 +
32613         return hctx;
32614  }
32615  
32616  static void handler_ctx_free(handler_ctx *hctx) {
32617 -       buffer_free(hctx->response);
32618 -       buffer_free(hctx->response_header);
32619 -
32620         chunkqueue_free(hctx->wb);
32621 -       
32622 -       if (hctx->rb) {
32623 -               if (hctx->rb->ptr) free(hctx->rb->ptr);
32624 -               free(hctx->rb);
32625 -       }
32626 -       
32627 +       chunkqueue_free(hctx->rb);
32628 +
32629 +       iosocket_free(hctx->sock);
32630 +
32631         free(hctx);
32632  }
32633  
32634 @@ -372,20 +360,20 @@
32635  
32636         f = calloc(1, sizeof(*f));
32637         f->socket = buffer_init();
32638 -       
32639 +
32640         f->prev = NULL;
32641         f->next = NULL;
32642 -       
32643 +
32644         return f;
32645  }
32646  
32647  void scgi_process_free(scgi_proc *f) {
32648         if (!f) return;
32649 -       
32650 +
32651         scgi_process_free(f->next);
32652 -       
32653 +
32654         buffer_free(f->socket);
32655 -       
32656 +
32657         free(f);
32658  }
32659  
32660 @@ -400,62 +388,62 @@
32661         f->bin_path = buffer_init();
32662         f->bin_env = array_init();
32663         f->bin_env_copy = array_init();
32664 -       
32665 +
32666         return f;
32667  }
32668  
32669  void scgi_host_free(scgi_extension_host *h) {
32670         if (!h) return;
32671 -       
32672 +
32673         buffer_free(h->host);
32674         buffer_free(h->unixsocket);
32675         buffer_free(h->docroot);
32676         buffer_free(h->bin_path);
32677         array_free(h->bin_env);
32678         array_free(h->bin_env_copy);
32679 -       
32680 +
32681         scgi_process_free(h->first);
32682         scgi_process_free(h->unused_procs);
32683 -       
32684 +
32685         free(h);
32686 -       
32687 +
32688  }
32689  
32690  scgi_exts *scgi_extensions_init() {
32691         scgi_exts *f;
32692  
32693         f = calloc(1, sizeof(*f));
32694 -       
32695 +
32696         return f;
32697  }
32698  
32699  void scgi_extensions_free(scgi_exts *f) {
32700         size_t i;
32701 -       
32702 +
32703         if (!f) return;
32704 -       
32705 +
32706         for (i = 0; i < f->used; i++) {
32707                 scgi_extension *fe;
32708                 size_t j;
32709 -               
32710 +
32711                 fe = f->exts[i];
32712 -               
32713 +
32714                 for (j = 0; j < fe->used; j++) {
32715                         scgi_extension_host *h;
32716 -                       
32717 +
32718                         h = fe->hosts[j];
32719 -                       
32720 +
32721                         scgi_host_free(h);
32722                 }
32723 -               
32724 +
32725                 buffer_free(fe->key);
32726                 free(fe->hosts);
32727 -               
32728 +
32729                 free(fe);
32730         }
32731 -       
32732 +
32733         free(f->exts);
32734 -       
32735 +
32736         free(f);
32737  }
32738  
32739 @@ -504,99 +492,103 @@
32740                 assert(fe->hosts);
32741         }
32742  
32743 -       fe->hosts[fe->used++] = fh; 
32744 +       fe->hosts[fe->used++] = fh;
32745  
32746         return 0;
32747 -       
32748 +
32749  }
32750  
32751  INIT_FUNC(mod_scgi_init) {
32752         plugin_data *p;
32753 -       
32754 +
32755         p = calloc(1, sizeof(*p));
32756 -       
32757 +
32758         p->scgi_env = buffer_init();
32759 -       
32760 +
32761         p->path = buffer_init();
32762 -       p->parse_response = buffer_init();
32763 -       
32764 +       p->resp = http_response_init();
32765 +
32766         return p;
32767  }
32768  
32769  
32770  FREE_FUNC(mod_scgi_free) {
32771         plugin_data *p = p_d;
32772 -       
32773 +
32774         UNUSED(srv);
32775  
32776         buffer_free(p->scgi_env);
32777         buffer_free(p->path);
32778 -       buffer_free(p->parse_response);
32779 -       
32780 +       http_response_free(p->resp);
32781 +
32782         if (p->config_storage) {
32783                 size_t i, j, n;
32784                 for (i = 0; i < srv->config_context->used; i++) {
32785                         plugin_config *s = p->config_storage[i];
32786                         scgi_exts *exts;
32787 -                       
32788 +
32789                         if (!s) continue;
32790 -                       
32791 +
32792                         exts = s->exts;
32793  
32794                         for (j = 0; j < exts->used; j++) {
32795                                 scgi_extension *ex;
32796 -                               
32797 +
32798                                 ex = exts->exts[j];
32799 -                               
32800 +
32801                                 for (n = 0; n < ex->used; n++) {
32802                                         scgi_proc *proc;
32803                                         scgi_extension_host *host;
32804 -                                       
32805 +
32806                                         host = ex->hosts[n];
32807 -                                       
32808 +
32809                                         for (proc = host->first; proc; proc = proc->next) {
32810 +#ifndef _WIN32
32811                                                 if (proc->pid != 0) kill(proc->pid, SIGTERM);
32812 -                                               
32813 -                                               if (proc->is_local && 
32814 +#endif
32815 +
32816 +                                               if (proc->is_local &&
32817                                                     !buffer_is_empty(proc->socket)) {
32818                                                         unlink(proc->socket->ptr);
32819                                                 }
32820                                         }
32821 -                                       
32822 +
32823                                         for (proc = host->unused_procs; proc; proc = proc->next) {
32824 +#ifndef _WIN32
32825                                                 if (proc->pid != 0) kill(proc->pid, SIGTERM);
32826 -                                               
32827 -                                               if (proc->is_local && 
32828 +#endif
32829 +
32830 +                                               if (proc->is_local &&
32831                                                     !buffer_is_empty(proc->socket)) {
32832                                                         unlink(proc->socket->ptr);
32833                                                 }
32834                                         }
32835                                 }
32836                         }
32837 -                       
32838 +
32839                         scgi_extensions_free(s->exts);
32840 -                       
32841 +
32842                         free(s);
32843                 }
32844                 free(p->config_storage);
32845         }
32846 -       
32847 +
32848         free(p);
32849 -       
32850 +
32851         return HANDLER_GO_ON;
32852  }
32853  
32854  static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
32855         char *dst;
32856 -       
32857 +
32858         if (!key || !val) return -1;
32859 -       
32860 +
32861         dst = malloc(key_len + val_len + 3);
32862         memcpy(dst, key, key_len);
32863         dst[key_len] = '=';
32864         /* add the \0 from the value */
32865         memcpy(dst + key_len + 1, val, val_len + 1);
32866 -       
32867 +
32868         if (env->size == 0) {
32869                 env->size = 16;
32870                 env->ptr = malloc(env->size * sizeof(*env->ptr));
32871 @@ -604,13 +596,13 @@
32872                 env->size += 16;
32873                 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
32874         }
32875 -       
32876 +
32877         env->ptr[env->used++] = dst;
32878 -       
32879 +
32880         return 0;
32881  }
32882  
32883 -static int scgi_spawn_connection(server *srv, 
32884 +static int scgi_spawn_connection(server *srv,
32885                                  plugin_data *p,
32886                                  scgi_extension_host *host,
32887                                  scgi_proc *proc) {
32888 @@ -622,31 +614,27 @@
32889  #endif
32890         struct sockaddr_in scgi_addr_in;
32891         struct sockaddr *scgi_addr;
32892 -       
32893 +
32894         socklen_t servlen;
32895 -       
32896 +
32897  #ifndef HAVE_FORK
32898         return -1;
32899  #endif
32900 -       
32901 +
32902         if (p->conf.debug) {
32903                 log_error_write(srv, __FILE__, __LINE__, "sdb",
32904                                 "new proc, socket:", proc->port, proc->socket);
32905         }
32906 -               
32907 +
32908         if (!buffer_is_empty(proc->socket)) {
32909                 memset(&scgi_addr, 0, sizeof(scgi_addr));
32910 -               
32911 +
32912  #ifdef HAVE_SYS_UN_H
32913                 scgi_addr_un.sun_family = AF_UNIX;
32914                 strcpy(scgi_addr_un.sun_path, proc->socket->ptr);
32915 -               
32916 -#ifdef SUN_LEN
32917 +
32918                 servlen = SUN_LEN(&scgi_addr_un);
32919 -#else
32920 -               /* stevens says: */
32921 -               servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family);
32922 -#endif
32923 +
32924                 socket_type = AF_UNIX;
32925                 scgi_addr = (struct sockaddr *) &scgi_addr_un;
32926  #else
32927 @@ -656,115 +644,115 @@
32928  #endif
32929         } else {
32930                 scgi_addr_in.sin_family = AF_INET;
32931 -               
32932 +
32933                 if (buffer_is_empty(host->host)) {
32934                         scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
32935                 } else {
32936                         struct hostent *he;
32937 -                       
32938 +
32939                         /* set a usefull default */
32940                         scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
32941 -                       
32942 -                       
32943 +
32944 +
32945                         if (NULL == (he = gethostbyname(host->host->ptr))) {
32946 -                               log_error_write(srv, __FILE__, __LINE__, 
32947 -                                               "sdb", "gethostbyname failed: ", 
32948 +                               log_error_write(srv, __FILE__, __LINE__,
32949 +                                               "sdb", "gethostbyname failed: ",
32950                                                 h_errno, host->host);
32951                                 return -1;
32952                         }
32953 -                       
32954 +
32955                         if (he->h_addrtype != AF_INET) {
32956                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
32957                                 return -1;
32958                         }
32959 -                       
32960 +
32961                         if (he->h_length != sizeof(struct in_addr)) {
32962                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
32963                                 return -1;
32964                         }
32965 -                       
32966 +
32967                         memcpy(&(scgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
32968 -                       
32969 +
32970                 }
32971                 scgi_addr_in.sin_port = htons(proc->port);
32972                 servlen = sizeof(scgi_addr_in);
32973 -               
32974 +
32975                 socket_type = AF_INET;
32976                 scgi_addr = (struct sockaddr *) &scgi_addr_in;
32977         }
32978 -       
32979 +
32980         if (-1 == (scgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
32981 -               log_error_write(srv, __FILE__, __LINE__, "ss", 
32982 +               log_error_write(srv, __FILE__, __LINE__, "ss",
32983                                 "failed:", strerror(errno));
32984                 return -1;
32985         }
32986 -       
32987 +
32988         if (-1 == connect(scgi_fd, scgi_addr, servlen)) {
32989                 /* server is not up, spawn in  */
32990                 pid_t child;
32991                 int val;
32992 -               
32993 +
32994                 if (!buffer_is_empty(proc->socket)) {
32995                         unlink(proc->socket->ptr);
32996                 }
32997 -               
32998 +
32999                 close(scgi_fd);
33000 -               
33001 +
33002                 /* reopen socket */
33003                 if (-1 == (scgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
33004 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
33005 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
33006                                 "socket failed:", strerror(errno));
33007                         return -1;
33008                 }
33009 -               
33010 +
33011                 val = 1;
33012                 if (setsockopt(scgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
33013 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
33014 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
33015                                         "socketsockopt failed:", strerror(errno));
33016                         return -1;
33017                 }
33018 -               
33019 +
33020                 /* create socket */
33021                 if (-1 == bind(scgi_fd, scgi_addr, servlen)) {
33022 -                       log_error_write(srv, __FILE__, __LINE__, "sbds", 
33023 -                               "bind failed for:", 
33024 -                               proc->socket, 
33025 -                               proc->port, 
33026 +                       log_error_write(srv, __FILE__, __LINE__, "sbds",
33027 +                               "bind failed for:",
33028 +                               proc->socket,
33029 +                               proc->port,
33030                                 strerror(errno));
33031                         return -1;
33032                 }
33033 -               
33034 +
33035                 if (-1 == listen(scgi_fd, 1024)) {
33036 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
33037 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
33038                                 "listen failed:", strerror(errno));
33039                         return -1;
33040                 }
33041 -               
33042 -#ifdef HAVE_FORK       
33043 +
33044 +#ifdef HAVE_FORK
33045                 switch ((child = fork())) {
33046                 case 0: {
33047                         buffer *b;
33048                         size_t i = 0;
33049                         int fd = 0;
33050                         char_array env;
33051 -                       
33052 -                       
33053 +
33054 +
33055                         /* create environment */
33056                         env.ptr = NULL;
33057                         env.size = 0;
33058                         env.used = 0;
33059 -                       
33060 +
33061                         /* we don't need the client socket */
33062                         for (fd = 3; fd < 256; fd++) {
33063                                 if (fd != 2 && fd != scgi_fd) close(fd);
33064                         }
33065 -                       
33066 +
33067                         /* build clean environment */
33068                         if (host->bin_env_copy->used) {
33069                                 for (i = 0; i < host->bin_env_copy->used; i++) {
33070                                         data_string *ds = (data_string *)host->bin_env_copy->data[i];
33071                                         char *ge;
33072 -                                       
33073 +
33074                                         if (NULL != (ge = getenv(ds->value->ptr))) {
33075                                                 env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge));
33076                                         }
33077 @@ -772,44 +760,44 @@
33078                         } else {
33079                                 for (i = 0; environ[i]; i++) {
33080                                         char *eq;
33081 -                                       
33082 +
33083                                         if (NULL != (eq = strchr(environ[i], '='))) {
33084                                                 env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));
33085                                         }
33086                                 }
33087                         }
33088 -                       
33089 +
33090                         /* create environment */
33091                         for (i = 0; i < host->bin_env->used; i++) {
33092                                 data_string *ds = (data_string *)host->bin_env->data[i];
33093 -                               
33094 +
33095                                 env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
33096                         }
33097 -                       
33098 +
33099                         for (i = 0; i < env.used; i++) {
33100                                 /* search for PHP_FCGI_CHILDREN */
33101                                 if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break;
33102                         }
33103 -                       
33104 +
33105                         /* not found, add a default */
33106                         if (i == env.used) {
33107                                 env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1"));
33108                         }
33109 -                       
33110 +
33111                         env.ptr[env.used] = NULL;
33112 -                       
33113 +
33114                         b = buffer_init();
33115                         buffer_copy_string(b, "exec ");
33116                         buffer_append_string_buffer(b, host->bin_path);
33117 -                       
33118 +
33119                         /* exec the cgi */
33120                         execle("/bin/sh", "sh", "-c", b->ptr, NULL, env.ptr);
33121 -                       
33122 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
33123 +
33124 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
33125                                         "execl failed for:", host->bin_path, strerror(errno));
33126 -                       
33127 +
33128                         exit(errno);
33129 -                       
33130 +
33131                         break;
33132                 }
33133                 case -1:
33134 @@ -817,32 +805,32 @@
33135                         break;
33136                 default:
33137                         /* father */
33138 -                       
33139 +
33140                         /* wait */
33141                         select(0, NULL, NULL, NULL, &tv);
33142 -                       
33143 +
33144                         switch (waitpid(child, &status, WNOHANG)) {
33145                         case 0:
33146                                 /* child still running after timeout, good */
33147                                 break;
33148                         case -1:
33149                                 /* no PID found ? should never happen */
33150 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
33151 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
33152                                                 "pid not found:", strerror(errno));
33153                                 return -1;
33154                         default:
33155                                 /* the child should not terminate at all */
33156                                 if (WIFEXITED(status)) {
33157 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
33158 -                                                       "child exited (is this a SCGI binary ?):", 
33159 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
33160 +                                                       "child exited (is this a SCGI binary ?):",
33161                                                         WEXITSTATUS(status));
33162                                 } else if (WIFSIGNALED(status)) {
33163 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
33164 -                                                       "child signaled:", 
33165 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
33166 +                                                       "child signaled:",
33167                                                         WTERMSIG(status));
33168                                 } else {
33169 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
33170 -                                                       "child died somehow:", 
33171 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
33172 +                                                       "child died somehow:",
33173                                                         status);
33174                                 }
33175                                 return -1;
33176 @@ -852,26 +840,26 @@
33177                         proc->pid = child;
33178                         proc->last_used = srv->cur_ts;
33179                         proc->is_local = 1;
33180 -                                               
33181 +
33182                         break;
33183                 }
33184  #endif
33185         } else {
33186                 proc->is_local = 0;
33187                 proc->pid = 0;
33188 -               
33189 +
33190                 if (p->conf.debug) {
33191                         log_error_write(srv, __FILE__, __LINE__, "sb",
33192                                         "(debug) socket is already used, won't spawn:",
33193                                         proc->socket);
33194                 }
33195         }
33196 -       
33197 +
33198         proc->state = PROC_STATE_RUNNING;
33199         host->active_procs++;
33200 -       
33201 +
33202         close(scgi_fd);
33203 -       
33204 +
33205         return 0;
33206  }
33207  
33208 @@ -880,89 +868,89 @@
33209         plugin_data *p = p_d;
33210         data_unset *du;
33211         size_t i = 0;
33212 -       
33213 -       config_values_t cv[] = { 
33214 +
33215 +       config_values_t cv[] = {
33216                 { "scgi.server",              NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
33217                 { "scgi.debug",               NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
33218                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
33219         };
33220 -       
33221 +
33222         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
33223 -       
33224 +
33225         for (i = 0; i < srv->config_context->used; i++) {
33226                 plugin_config *s;
33227                 array *ca;
33228 -               
33229 +
33230                 s = malloc(sizeof(plugin_config));
33231                 s->exts          = scgi_extensions_init();
33232                 s->debug         = 0;
33233 -               
33234 +
33235                 cv[0].destination = s->exts;
33236                 cv[1].destination = &(s->debug);
33237 -               
33238 +
33239                 p->config_storage[i] = s;
33240                 ca = ((data_config *)srv->config_context->data[i])->value;
33241 -       
33242 +
33243                 if (0 != config_insert_values_global(srv, ca, cv)) {
33244                         return HANDLER_ERROR;
33245                 }
33246 -               
33247 -               /* 
33248 +
33249 +               /*
33250                  * <key> = ( ... )
33251                  */
33252 -               
33253 +
33254                 if (NULL != (du = array_get_element(ca, "scgi.server"))) {
33255                         size_t j;
33256                         data_array *da = (data_array *)du;
33257 -                       
33258 +
33259                         if (du->type != TYPE_ARRAY) {
33260 -                               log_error_write(srv, __FILE__, __LINE__, "sss", 
33261 +                               log_error_write(srv, __FILE__, __LINE__, "sss",
33262                                                 "unexpected type for key: ", "scgi.server", "array of strings");
33263 -                               
33264 +
33265                                 return HANDLER_ERROR;
33266                         }
33267 -                       
33268 -                       
33269 -                       /* 
33270 -                        * scgi.server = ( "<ext>" => ( ... ), 
33271 +
33272 +
33273 +                       /*
33274 +                        * scgi.server = ( "<ext>" => ( ... ),
33275                          *                    "<ext>" => ( ... ) )
33276                          */
33277 -                       
33278 +
33279                         for (j = 0; j < da->value->used; j++) {
33280                                 size_t n;
33281                                 data_array *da_ext = (data_array *)da->value->data[j];
33282 -                               
33283 +
33284                                 if (da->value->data[j]->type != TYPE_ARRAY) {
33285 -                                       log_error_write(srv, __FILE__, __LINE__, "sssbs", 
33286 -                                                       "unexpected type for key: ", "scgi.server", 
33287 +                                       log_error_write(srv, __FILE__, __LINE__, "sssbs",
33288 +                                                       "unexpected type for key: ", "scgi.server",
33289                                                         "[", da->value->data[j]->key, "](string)");
33290 -                                       
33291 +
33292                                         return HANDLER_ERROR;
33293                                 }
33294 -                               
33295 -                               /* 
33296 -                                * da_ext->key == name of the extension 
33297 +
33298 +                               /*
33299 +                                * da_ext->key == name of the extension
33300                                  */
33301 -                               
33302 -                               /* 
33303 -                                * scgi.server = ( "<ext>" => 
33304 -                                *                     ( "<host>" => ( ... ), 
33305 +
33306 +                               /*
33307 +                                * scgi.server = ( "<ext>" =>
33308 +                                *                     ( "<host>" => ( ... ),
33309                                  *                       "<host>" => ( ... )
33310 -                                *                     ), 
33311 +                                *                     ),
33312                                  *                    "<ext>" => ... )
33313                                  */
33314 -                                       
33315 +
33316                                 for (n = 0; n < da_ext->value->used; n++) {
33317                                         data_array *da_host = (data_array *)da_ext->value->data[n];
33318 -                                       
33319 +
33320                                         scgi_extension_host *df;
33321 -                                       
33322 -                                       config_values_t fcv[] = { 
33323 +
33324 +                                       config_values_t fcv[] = {
33325                                                 { "host",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
33326                                                 { "docroot",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
33327                                                 { "socket",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
33328                                                 { "bin-path",          NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
33329 -                                               
33330 +
33331                                                 { "check-local",       NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 4 */
33332                                                 { "port",              NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 5 */
33333                                                 { "min-procs-not-working",         NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 7 this is broken for now */
33334 @@ -970,37 +958,37 @@
33335                                                 { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 8 */
33336                                                 { "idle-timeout",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 9 */
33337                                                 { "disable-time",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 10 */
33338 -                                               
33339 +
33340                                                 { "bin-environment",   NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },        /* 11 */
33341                                                 { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },     /* 12 */
33342 -                                               
33343 -                                               
33344 +
33345 +
33346                                                 { NULL,                NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
33347                                         };
33348 -                                       
33349 +
33350                                         if (da_host->type != TYPE_ARRAY) {
33351 -                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS", 
33352 -                                                               "unexpected type for key:", 
33353 -                                                               "scgi.server", 
33354 +                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS",
33355 +                                                               "unexpected type for key:",
33356 +                                                               "scgi.server",
33357                                                                 "[", da_host->key, "](string)");
33358 -                                               
33359 +
33360                                                 return HANDLER_ERROR;
33361                                         }
33362 -                                       
33363 +
33364                                         df = scgi_host_init();
33365 -                                       
33366 +
33367                                         df->check_local  = 1;
33368                                         df->min_procs    = 4;
33369                                         df->max_procs    = 4;
33370                                         df->max_load_per_proc = 1;
33371                                         df->idle_timeout = 60;
33372                                         df->disable_time = 60;
33373 -                                       
33374 +
33375                                         fcv[0].destination = df->host;
33376                                         fcv[1].destination = df->docroot;
33377                                         fcv[2].destination = df->unixsocket;
33378                                         fcv[3].destination = df->bin_path;
33379 -                                       
33380 +
33381                                         fcv[4].destination = &(df->check_local);
33382                                         fcv[5].destination = &(df->port);
33383                                         fcv[6].destination = &(df->min_procs);
33384 @@ -1008,47 +996,47 @@
33385                                         fcv[8].destination = &(df->max_load_per_proc);
33386                                         fcv[9].destination = &(df->idle_timeout);
33387                                         fcv[10].destination = &(df->disable_time);
33388 -                                       
33389 +
33390                                         fcv[11].destination = df->bin_env;
33391                                         fcv[12].destination = df->bin_env_copy;
33392 -                                       
33393 -                                       
33394 +
33395 +
33396                                         if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
33397                                                 return HANDLER_ERROR;
33398                                         }
33399 -                                                       
33400 -                                       if ((!buffer_is_empty(df->host) || df->port) && 
33401 +
33402 +                                       if ((!buffer_is_empty(df->host) || df->port) &&
33403                                             !buffer_is_empty(df->unixsocket)) {
33404 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
33405 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
33406                                                                 "either host+port or socket");
33407 -                                               
33408 +
33409                                                 return HANDLER_ERROR;
33410                                         }
33411 -                                       
33412 +
33413                                         if (!buffer_is_empty(df->unixsocket)) {
33414                                                 /* unix domain socket */
33415 -                                               
33416 +
33417                                                 if (df->unixsocket->used > UNIX_PATH_MAX - 2) {
33418 -                                                       log_error_write(srv, __FILE__, __LINE__, "s", 
33419 +                                                       log_error_write(srv, __FILE__, __LINE__, "s",
33420                                                                         "path of the unixdomain socket is too large");
33421                                                         return HANDLER_ERROR;
33422                                                 }
33423                                         } else {
33424                                                 /* tcp/ip */
33425 -                                               
33426 -                                               if (buffer_is_empty(df->host) && 
33427 +
33428 +                                               if (buffer_is_empty(df->host) &&
33429                                                     buffer_is_empty(df->bin_path)) {
33430 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbbbs", 
33431 -                                                                       "missing key (string):", 
33432 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbbbs",
33433 +                                                                       "missing key (string):",
33434                                                                         da->key,
33435                                                                         da_ext->key,
33436                                                                         da_host->key,
33437                                                                         "host");
33438 -                                                       
33439 +
33440                                                         return HANDLER_ERROR;
33441                                                 } else if (df->port == 0) {
33442 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbbbs", 
33443 -                                                                       "missing key (short):", 
33444 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbbbs",
33445 +                                                                       "missing key (short):",
33446                                                                         da->key,
33447                                                                         da_ext->key,
33448                                                                         da_host->key,
33449 @@ -1056,14 +1044,14 @@
33450                                                         return HANDLER_ERROR;
33451                                                 }
33452                                         }
33453 -                                               
33454 -                                       if (!buffer_is_empty(df->bin_path)) { 
33455 +
33456 +                                       if (!buffer_is_empty(df->bin_path)) {
33457                                                 /* a local socket + self spawning */
33458                                                 size_t pno;
33459 -                                               
33460 +
33461                                                 if (df->min_procs > df->max_procs) df->max_procs = df->min_procs;
33462                                                 if (df->max_load_per_proc < 1) df->max_load_per_proc = 0;
33463 -                                               
33464 +
33465                                                 if (s->debug) {
33466                                                         log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
33467                                                                         "--- scgi spawning local",
33468 @@ -1073,7 +1061,7 @@
33469                                                                         "\n\tmin-procs:", df->min_procs,
33470                                                                         "\n\tmax-procs:", df->max_procs);
33471                                                 }
33472 -                                               
33473 +
33474                                                 for (pno = 0; pno < df->min_procs; pno++) {
33475                                                         scgi_proc *proc;
33476  
33477 @@ -1088,7 +1076,7 @@
33478                                                                 buffer_append_string(proc->socket, "-");
33479                                                                 buffer_append_long(proc->socket, pno);
33480                                                         }
33481 -                                                       
33482 +
33483                                                         if (s->debug) {
33484                                                                 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
33485                                                                                 "--- scgi spawning",
33486 @@ -1096,53 +1084,53 @@
33487                                                                                 "\n\tsocket", df->unixsocket,
33488                                                                                 "\n\tcurrent:", pno, "/", df->min_procs);
33489                                                         }
33490 -                                                       
33491 +
33492                                                         if (scgi_spawn_connection(srv, p, df, proc)) {
33493                                                                 log_error_write(srv, __FILE__, __LINE__, "s",
33494                                                                                 "[ERROR]: spawning fcgi failed.");
33495                                                                 return HANDLER_ERROR;
33496                                                         }
33497 -                                                       
33498 +
33499                                                         proc->next = df->first;
33500                                                         if (df->first)  df->first->prev = proc;
33501 -                                                       
33502 +
33503                                                         df->first = proc;
33504                                                 }
33505                                         } else {
33506                                                 scgi_proc *fp;
33507 -                                               
33508 +
33509                                                 fp = scgi_process_init();
33510                                                 fp->id = df->num_procs++;
33511                                                 df->max_id++;
33512                                                 df->active_procs++;
33513                                                 fp->state = PROC_STATE_RUNNING;
33514 -                                               
33515 +
33516                                                 if (buffer_is_empty(df->unixsocket)) {
33517                                                         fp->port = df->port;
33518                                                 } else {
33519                                                         buffer_copy_string_buffer(fp->socket, df->unixsocket);
33520                                                 }
33521 -                                               
33522 +
33523                                                 df->first = fp;
33524 -                                               
33525 +
33526                                                 df->min_procs = 1;
33527                                                 df->max_procs = 1;
33528                                         }
33529 -                                       
33530 +
33531                                         /* if extension already exists, take it */
33532                                         scgi_extension_insert(s->exts, da_ext->key, df);
33533                                 }
33534                         }
33535                 }
33536         }
33537 -       
33538 +
33539         return HANDLER_GO_ON;
33540  }
33541  
33542  static int scgi_set_state(server *srv, handler_ctx *hctx, scgi_connection_state_t state) {
33543         hctx->state = state;
33544         hctx->state_timestamp = srv->cur_ts;
33545 -       
33546 +
33547         return 0;
33548  }
33549  
33550 @@ -1150,35 +1138,35 @@
33551  void scgi_connection_cleanup(server *srv, handler_ctx *hctx) {
33552         plugin_data *p;
33553         connection  *con;
33554 -       
33555 +
33556         if (NULL == hctx) return;
33557 -       
33558 +
33559         p    = hctx->plugin_data;
33560         con  = hctx->remote_conn;
33561 -       
33562 +
33563         if (con->mode != p->id) {
33564 -               WP();
33565                 return;
33566         }
33567 -       
33568 -       if (hctx->fd != -1) {
33569 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
33570 -               fdevent_unregister(srv->ev, hctx->fd);
33571 -               close(hctx->fd);
33572 +
33573 +       if (hctx->sock->fd != -1) {
33574 +               fdevent_event_del(srv->ev, hctx->sock);
33575 +               fdevent_unregister(srv->ev, hctx->sock);
33576 +               closesocket(hctx->sock->fd);
33577 +               hctx->sock->fd = -1;
33578                 srv->cur_fds--;
33579         }
33580 -       
33581 +
33582         if (hctx->host && hctx->proc) {
33583                 hctx->host->load--;
33584 -               
33585 +
33586                 if (hctx->got_proc) {
33587                         /* after the connect the process gets a load */
33588                         hctx->proc->load--;
33589 -                       
33590 +
33591                         if (p->conf.debug) {
33592                                 log_error_write(srv, __FILE__, __LINE__, "sddb",
33593 -                                               "release proc:", 
33594 -                                               hctx->fd,
33595 +                                               "release proc:",
33596 +                                               hctx->sock->fd,
33597                                                 hctx->proc->pid, hctx->proc->socket);
33598                         }
33599                 }
33600 @@ -1186,87 +1174,87 @@
33601                 scgi_proclist_sort_down(srv, hctx->host, hctx->proc);
33602         }
33603  
33604 -       
33605 +
33606         handler_ctx_free(hctx);
33607 -       con->plugin_ctx[p->id] = NULL;  
33608 +       con->plugin_ctx[p->id] = NULL;
33609  }
33610  
33611  static int scgi_reconnect(server *srv, handler_ctx *hctx) {
33612         plugin_data *p    = hctx->plugin_data;
33613 -       
33614 -       /* child died 
33615 -        * 
33616 -        * 1. 
33617 -        * 
33618 +
33619 +       /* child died
33620 +        *
33621 +        * 1.
33622 +        *
33623          * connect was ok, connection was accepted
33624          * but the php accept loop checks after the accept if it should die or not.
33625 -        * 
33626 -        * if yes we can only detect it at a write() 
33627 -        * 
33628 +        *
33629 +        * if yes we can only detect it at a write()
33630 +        *
33631          * next step is resetting this attemp and setup a connection again
33632 -        * 
33633 +        *
33634          * if we have more then 5 reconnects for the same request, die
33635 -        * 
33636 -        * 2. 
33637 -        * 
33638 +        *
33639 +        * 2.
33640 +        *
33641          * we have a connection but the child died by some other reason
33642 -        * 
33643 +        *
33644          */
33645 -       
33646 -       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
33647 -       fdevent_unregister(srv->ev, hctx->fd);
33648 -       close(hctx->fd);
33649 +
33650 +       fdevent_event_del(srv->ev, hctx->sock);
33651 +       fdevent_unregister(srv->ev, hctx->sock);
33652 +       closesocket(hctx->sock->fd);
33653         srv->cur_fds--;
33654 -       
33655 -       scgi_set_state(srv, hctx, FCGI_STATE_INIT);
33656 -       
33657 +
33658 +       scgi_set_state(srv, hctx, SCGI_STATE_INIT);
33659 +
33660         hctx->request_id = 0;
33661         hctx->reconnects++;
33662 -       
33663 +
33664         if (p->conf.debug) {
33665                 log_error_write(srv, __FILE__, __LINE__, "sddb",
33666 -                               "release proc:", 
33667 -                               hctx->fd,
33668 +                               "release proc:",
33669 +                               hctx->sock->fd,
33670                                 hctx->proc->pid, hctx->proc->socket);
33671         }
33672 -       
33673 +
33674         hctx->proc->load--;
33675         scgi_proclist_sort_down(srv, hctx->host, hctx->proc);
33676 -       
33677 +
33678         return 0;
33679  }
33680  
33681  
33682  static handler_t scgi_connection_reset(server *srv, connection *con, void *p_d) {
33683         plugin_data *p = p_d;
33684 -       
33685 +
33686         scgi_connection_cleanup(srv, con->plugin_ctx[p->id]);
33687 -       
33688 +
33689         return HANDLER_GO_ON;
33690  }
33691  
33692  
33693  static int scgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
33694         size_t len;
33695 -       
33696 +
33697         if (!key || !val) return -1;
33698 -       
33699 +
33700         len = key_len + val_len + 2;
33701 -       
33702 +
33703         buffer_prepare_append(env, len);
33704  
33705 -       /* include the NUL */   
33706 +       /* include the NUL */
33707         memcpy(env->ptr + env->used, key, key_len + 1);
33708         env->used += key_len + 1;
33709         memcpy(env->ptr + env->used, val, val_len + 1);
33710         env->used += val_len + 1;
33711 -       
33712 +
33713         return 0;
33714  }
33715  
33716  
33717  /**
33718 - * 
33719 + *
33720   * returns
33721   *   -1 error
33722   *    0 connected
33723 @@ -1280,24 +1268,21 @@
33724         struct sockaddr_un scgi_addr_un;
33725  #endif
33726         socklen_t servlen;
33727 -       
33728 +
33729         scgi_extension_host *host = hctx->host;
33730         scgi_proc *proc   = hctx->proc;
33731 -       int scgi_fd       = hctx->fd;
33732 -       
33733 +       int scgi_fd       = hctx->sock->fd;
33734 +
33735         memset(&scgi_addr, 0, sizeof(scgi_addr));
33736 -       
33737 +
33738         if (!buffer_is_empty(proc->socket)) {
33739  #ifdef HAVE_SYS_UN_H
33740                 /* use the unix domain socket */
33741                 scgi_addr_un.sun_family = AF_UNIX;
33742                 strcpy(scgi_addr_un.sun_path, proc->socket->ptr);
33743 -#ifdef SUN_LEN
33744 +               
33745                 servlen = SUN_LEN(&scgi_addr_un);
33746 -#else
33747 -               /* stevens says: */
33748 -               servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family);
33749 -#endif
33750 +
33751                 scgi_addr = (struct sockaddr *) &scgi_addr_un;
33752  #else
33753                 return -1;
33754 @@ -1305,105 +1290,105 @@
33755         } else {
33756                 scgi_addr_in.sin_family = AF_INET;
33757                 if (0 == inet_aton(host->host->ptr, &(scgi_addr_in.sin_addr))) {
33758 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
33759 -                                       "converting IP-adress failed for", host->host, 
33760 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
33761 +                                       "converting IP-adress failed for", host->host,
33762                                         "\nBe sure to specify an IP address here");
33763 -                       
33764 +
33765                         return -1;
33766                 }
33767                 scgi_addr_in.sin_port = htons(proc->port);
33768                 servlen = sizeof(scgi_addr_in);
33769 -               
33770 +
33771                 scgi_addr = (struct sockaddr *) &scgi_addr_in;
33772         }
33773 -       
33774 +
33775         if (-1 == connect(scgi_fd, scgi_addr, servlen)) {
33776 -               if (errno == EINPROGRESS || 
33777 +               if (errno == EINPROGRESS ||
33778                     errno == EALREADY ||
33779                     errno == EINTR) {
33780                         if (hctx->conf.debug) {
33781 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
33782 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
33783                                                 "connect delayed, will continue later:", scgi_fd);
33784                         }
33785 -                       
33786 +
33787                         return 1;
33788                 } else {
33789 -                       log_error_write(srv, __FILE__, __LINE__, "sdsddb", 
33790 -                                       "connect failed:", scgi_fd, 
33791 +                       log_error_write(srv, __FILE__, __LINE__, "sdsddb",
33792 +                                       "connect failed:", scgi_fd,
33793                                         strerror(errno), errno,
33794                                         proc->port, proc->socket);
33795  
33796                         if (errno == EAGAIN) {
33797                                 /* this is Linux only */
33798 -                               
33799 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
33800 +
33801 +                               log_error_write(srv, __FILE__, __LINE__, "s",
33802                                                 "If this happend on Linux: You have been run out of local ports. "
33803                                                 "Check the manual, section Performance how to handle this.");
33804 -                       } 
33805 -                       
33806 +                       }
33807 +
33808                         return -1;
33809                 }
33810         }
33811         if (hctx->conf.debug > 1) {
33812 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
33813 +               log_error_write(srv, __FILE__, __LINE__, "sd",
33814                                 "connect succeeded: ", scgi_fd);
33815         }
33816  
33817  
33818 -       
33819 +
33820         return 0;
33821  }
33822  
33823  static int scgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
33824         size_t i;
33825 -       
33826 +
33827         for (i = 0; i < con->request.headers->used; i++) {
33828                 data_string *ds;
33829 -               
33830 +
33831                 ds = (data_string *)con->request.headers->data[i];
33832 -               
33833 +
33834                 if (ds->value->used && ds->key->used) {
33835                         size_t j;
33836                         buffer_reset(srv->tmp_buf);
33837 -                       
33838 +
33839                         if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
33840                                 BUFFER_COPY_STRING_CONST(srv->tmp_buf, "HTTP_");
33841                                 srv->tmp_buf->used--;
33842                         }
33843 -                       
33844 +
33845                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
33846                         for (j = 0; j < ds->key->used - 1; j++) {
33847 -                               srv->tmp_buf->ptr[srv->tmp_buf->used++] = 
33848 -                                       light_isalpha(ds->key->ptr[j]) ? 
33849 +                               srv->tmp_buf->ptr[srv->tmp_buf->used++] =
33850 +                                       light_isalpha(ds->key->ptr[j]) ?
33851                                         ds->key->ptr[j] & ~32 : '_';
33852                         }
33853                         srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
33854 -                       
33855 +
33856                         scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
33857                 }
33858         }
33859 -       
33860 +
33861         for (i = 0; i < con->environment->used; i++) {
33862                 data_string *ds;
33863 -               
33864 +
33865                 ds = (data_string *)con->environment->data[i];
33866 -               
33867 +
33868                 if (ds->value->used && ds->key->used) {
33869                         size_t j;
33870                         buffer_reset(srv->tmp_buf);
33871 -                       
33872 +
33873                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
33874                         for (j = 0; j < ds->key->used - 1; j++) {
33875 -                               srv->tmp_buf->ptr[srv->tmp_buf->used++] = 
33876 -                                       isalpha((unsigned char)ds->key->ptr[j]) ? 
33877 +                               srv->tmp_buf->ptr[srv->tmp_buf->used++] =
33878 +                                       isalpha((unsigned char)ds->key->ptr[j]) ?
33879                                         toupper((unsigned char)ds->key->ptr[j]) : '_';
33880                         }
33881                         srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
33882 -                       
33883 +
33884                         scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
33885                 }
33886         }
33887 -       
33888 +
33889         return 0;
33890  }
33891  
33892 @@ -1415,20 +1400,20 @@
33893         char b2[INET6_ADDRSTRLEN + 1];
33894  #endif
33895         buffer *b;
33896 -       
33897 +
33898         plugin_data *p    = hctx->plugin_data;
33899         scgi_extension_host *host= hctx->host;
33900  
33901         connection *con   = hctx->remote_conn;
33902         server_socket *srv_sock = con->srv_socket;
33903 -       
33904 +
33905         sock_addr our_addr;
33906         socklen_t our_addr_len;
33907 -       
33908 +
33909         buffer_prepare_copy(p->scgi_env, 1024);
33910  
33911         /* CGI-SPEC 6.1.2, FastCGI spec 6.3 and SCGI spec */
33912 -               
33913 +
33914         /* request.content_length < SSIZE_MAX, see request.c */
33915         ltostr(buf, con->request.content_length);
33916         scgi_env_add(p->scgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
33917 @@ -1436,13 +1421,13 @@
33918  
33919  
33920         scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
33921 -       
33922 +
33923         if (con->server_name->used) {
33924                 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
33925         } else {
33926  #ifdef HAVE_IPV6
33927 -               s = inet_ntop(srv_sock->addr.plain.sa_family, 
33928 -                             srv_sock->addr.plain.sa_family == AF_INET6 ? 
33929 +               s = inet_ntop(srv_sock->addr.plain.sa_family,
33930 +                             srv_sock->addr.plain.sa_family == AF_INET6 ?
33931                               (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
33932                               (const void *) &(srv_sock->addr.ipv4.sin_addr),
33933                               b2, sizeof(b2)-1);
33934 @@ -1451,47 +1436,47 @@
33935  #endif
33936                 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
33937         }
33938 -       
33939 +
33940         scgi_env_add(p->scgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
33941 -       
33942 -       ltostr(buf, 
33943 +
33944 +       ltostr(buf,
33945  #ifdef HAVE_IPV6
33946                ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
33947  #else
33948                ntohs(srv_sock->addr.ipv4.sin_port)
33949  #endif
33950                );
33951 -       
33952 +
33953         scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
33954 -       
33955 +
33956         /* get the server-side of the connection to the client */
33957         our_addr_len = sizeof(our_addr);
33958 -       
33959 -       if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
33960 +
33961 +       if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
33962                 s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
33963         } else {
33964                 s = inet_ntop_cache_get_ip(srv, &(our_addr));
33965         }
33966         scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
33967 -       
33968 -       ltostr(buf, 
33969 +
33970 +       ltostr(buf,
33971  #ifdef HAVE_IPV6
33972                ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
33973  #else
33974                ntohs(con->dst_addr.ipv4.sin_port)
33975  #endif
33976                );
33977 -       
33978 +
33979         scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
33980 -       
33981 +
33982         s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
33983         scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
33984 -       
33985 +
33986         if (!buffer_is_empty(con->authed_user)) {
33987                 scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_USER"),
33988                              CONST_BUF_LEN(con->authed_user));
33989         }
33990 -       
33991 +
33992  
33993         /*
33994          * SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to
33995 @@ -1500,12 +1485,12 @@
33996          */
33997  
33998         scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
33999 -               
34000 +
34001         if (!buffer_is_empty(con->request.pathinfo)) {
34002                 scgi_env_add(p->scgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
34003 -               
34004 +
34005                 /* PATH_TRANSLATED is only defined if PATH_INFO is set */
34006 -               
34007 +
34008                 if (!buffer_is_empty(host->docroot)) {
34009                         buffer_copy_string_buffer(p->path, host->docroot);
34010                 } else {
34011 @@ -1526,19 +1511,19 @@
34012          */
34013  
34014         if (!buffer_is_empty(host->docroot)) {
34015 -               /* 
34016 -                * rewrite SCRIPT_FILENAME 
34017 -                * 
34018 +               /*
34019 +                * rewrite SCRIPT_FILENAME
34020 +                *
34021                  */
34022 -               
34023 +
34024                 buffer_copy_string_buffer(p->path, host->docroot);
34025                 buffer_append_string_buffer(p->path, con->uri.path);
34026 -               
34027 +
34028                 scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
34029                 scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot));
34030         } else {
34031                 buffer_copy_string_buffer(p->path, con->physical.path);
34032 -               
34033 +
34034                 scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
34035                 scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
34036         }
34037 @@ -1551,30 +1536,30 @@
34038         } else {
34039                 scgi_env_add(p->scgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
34040         }
34041 -       
34042 +
34043         s = get_http_method_name(con->request.http_method);
34044         scgi_env_add(p->scgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
34045         scgi_env_add(p->scgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
34046         s = get_http_version_name(con->request.http_version);
34047         scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
34048 -       
34049 +
34050  #ifdef USE_OPENSSL
34051         if (srv_sock->is_ssl) {
34052                 scgi_env_add(p->scgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
34053         }
34054  #endif
34055 -       
34056 +
34057         scgi_env_add_request_headers(srv, con, p);
34058  
34059         b = chunkqueue_get_append_buffer(hctx->wb);
34060 -       
34061 +
34062         buffer_append_long(b, p->scgi_env->used);
34063         buffer_append_string_len(b, CONST_STR_LEN(":"));
34064         buffer_append_string_len(b, (const char *)p->scgi_env->ptr, p->scgi_env->used);
34065         buffer_append_string_len(b, CONST_STR_LEN(","));
34066  
34067         hctx->wb->bytes_in += b->used - 1;
34068 -       
34069 +
34070         if (con->request.content_length) {
34071                 chunkqueue *req_cq = con->request_content_queue;
34072                 chunk *req_c;
34073 @@ -1587,7 +1572,7 @@
34074  
34075                         /* we announce toWrite octects
34076                          * now take all the request_content chunk that we need to fill this request
34077 -                        * */   
34078 +                        * */
34079  
34080                         switch (req_c->type) {
34081                         case FILE_CHUNK:
34082 @@ -1615,293 +1600,170 @@
34083  
34084                                 req_c->offset += weHave;
34085                                 req_cq->bytes_out += weHave;
34086 -                               
34087 +
34088                                 hctx->wb->bytes_in += weHave;
34089  
34090                                 break;
34091                         default:
34092                                 break;
34093                         }
34094 -                       
34095 +
34096                         offset += weHave;
34097                 }
34098         }
34099 -       
34100 +
34101  #if 0
34102         for (i = 0; i < hctx->write_buffer->used; i++) {
34103                 fprintf(stderr, "%02x ", hctx->write_buffer->ptr[i]);
34104                 if ((i+1) % 16 == 0) {
34105                         size_t j;
34106                         for (j = i-15; j <= i; j++) {
34107 -                               fprintf(stderr, "%c", 
34108 +                               fprintf(stderr, "%c",
34109                                         isprint((unsigned char)hctx->write_buffer->ptr[j]) ? hctx->write_buffer->ptr[j] : '.');
34110                         }
34111                         fprintf(stderr, "\n");
34112                 }
34113         }
34114  #endif
34115 -       
34116 -       return 0;
34117 -}
34118  
34119 -static int scgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in, int eol) {
34120 -       char *ns;
34121 -       const char *s;
34122 -       int line = 0;
34123 -       
34124 -       UNUSED(srv);
34125 -       
34126 -       buffer_copy_string_buffer(p->parse_response, in);
34127 -       
34128 -       for (s = p->parse_response->ptr; 
34129 -            NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n'))); 
34130 -            s = ns + (eol == EOL_RN ? 2 : 1), line++) {
34131 -               const char *key, *value;
34132 -               int key_len;
34133 -               data_string *ds;
34134 -               
34135 -               ns[0] = '\0';
34136 -               
34137 -               if (line == 0 && 
34138 -                   0 == strncmp(s, "HTTP/1.", 7)) {
34139 -                       /* non-parsed header ... we parse them anyway */
34140 -                       
34141 -                       if ((s[7] == '1' ||
34142 -                            s[7] == '0') &&
34143 -                           s[8] == ' ') {
34144 -                               int status;
34145 -                               /* after the space should be a status code for us */
34146 -                               
34147 -                               status = strtol(s+9, NULL, 10);
34148 -                               
34149 -                               if (con->http_status >= 100 &&
34150 -                                   con->http_status < 1000) {
34151 -                                       /* we expected 3 digits and didn't got them */
34152 -                                       con->parsed_response |= HTTP_STATUS;
34153 -                                       con->http_status = status;
34154 -                               }
34155 -                       }
34156 -               } else {
34157 -               
34158 -                       key = s;
34159 -                       if (NULL == (value = strchr(s, ':'))) {
34160 -                               /* we expect: "<key>: <value>\r\n" */
34161 -                               continue;
34162 -                       }
34163 -                       
34164 -                       key_len = value - key;
34165 -                       value += 1;
34166 -                       
34167 -                       /* skip LWS */
34168 -                       while (*value == ' ' || *value == '\t') value++;
34169 -                       
34170 -                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
34171 -                               ds = data_response_init();
34172 -                       }
34173 -                       buffer_copy_string_len(ds->key, key, key_len);
34174 -                       buffer_copy_string(ds->value, value);
34175 -                       
34176 -                       array_insert_unique(con->response.headers, (data_unset *)ds);
34177 -                       
34178 -                       switch(key_len) {
34179 -                       case 4:
34180 -                               if (0 == strncasecmp(key, "Date", key_len)) {
34181 -                                       con->parsed_response |= HTTP_DATE;
34182 -                               }
34183 -                               break;
34184 -                       case 6:
34185 -                               if (0 == strncasecmp(key, "Status", key_len)) {
34186 -                                       con->http_status = strtol(value, NULL, 10);
34187 -                                       con->parsed_response |= HTTP_STATUS;
34188 -                               }
34189 -                               break;
34190 -                       case 8:
34191 -                               if (0 == strncasecmp(key, "Location", key_len)) {
34192 -                                       con->parsed_response |= HTTP_LOCATION;
34193 -                               }
34194 -                               break;
34195 -                       case 10:
34196 -                               if (0 == strncasecmp(key, "Connection", key_len)) {
34197 -                                       con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
34198 -                                       con->parsed_response |= HTTP_CONNECTION;
34199 -                               }
34200 -                               break;
34201 -                       case 14:
34202 -                               if (0 == strncasecmp(key, "Content-Length", key_len)) {
34203 -                                       con->response.content_length = strtol(value, NULL, 10);
34204 -                                       con->parsed_response |= HTTP_CONTENT_LENGTH;
34205 -                               }
34206 -                               break;
34207 -                       default:
34208 -                               break;
34209 -                       }
34210 -               }
34211 -       }
34212 -       
34213 -       /* CGI/1.1 rev 03 - 7.2.1.2 */
34214 -       if ((con->parsed_response & HTTP_LOCATION) &&
34215 -           !(con->parsed_response & HTTP_STATUS)) {
34216 -               con->http_status = 302;
34217 -       }
34218 -       
34219         return 0;
34220  }
34221  
34222 -
34223  static int scgi_demux_response(server *srv, handler_ctx *hctx) {
34224         plugin_data *p    = hctx->plugin_data;
34225         connection  *con  = hctx->remote_conn;
34226 -       
34227 -       while(1) {
34228 -               int n;
34229 -               
34230 -               buffer_prepare_copy(hctx->response, 1024);
34231 -               if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {
34232 -                       if (errno == EAGAIN || errno == EINTR) {
34233 -                               /* would block, wait for signal */
34234 -                               return 0;
34235 -                       }
34236 -                       /* error */
34237 -                       log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd);
34238 -                       return -1;
34239 -               }
34240 -               
34241 -               if (n == 0) {
34242 -                       /* read finished */
34243 -                       
34244 -                       con->file_finished = 1;
34245 -                       
34246 -                       /* send final chunk */
34247 -                       http_chunk_append_mem(srv, con, NULL, 0);
34248 -                       joblist_append(srv, con);
34249 -                       
34250 +       chunk *c;
34251 +
34252 +       switch(srv->network_backend_read(srv, con, hctx->sock, hctx->rb)) {
34253 +       case NETWORK_STATUS_SUCCESS:
34254 +               /* we got content */
34255 +               break;
34256 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
34257 +               /* the ioctl will return WAIT_FOR_EVENT on a read */
34258 +               if (0 == con->file_started) return -1;
34259 +       case NETWORK_STATUS_CONNECTION_CLOSE:
34260 +               /* we are done, get out of here */
34261 +               con->file_finished = 1;
34262 +
34263 +               /* close the chunk-queue with a empty chunk */
34264 +
34265 +               return 1;
34266 +       default:
34267 +               /* oops */
34268 +               return -1;
34269 +       }
34270 +
34271 +       /* looks like we got some content
34272 +       *
34273 +       * split off the header from the incoming stream
34274 +       */
34275 +
34276 +       if (hctx->state == SCGI_STATE_RESPONSE_HEADER) {
34277 +               size_t i;
34278 +               int have_content_length = 0;
34279 +
34280 +               http_response_reset(p->resp);
34281 +
34282 +               /* the response header is not fully received yet,
34283 +               *
34284 +               * extract the http-response header from the rb-cq
34285 +               */
34286 +               switch (http_response_parse_cq(hctx->rb, p->resp)) {
34287 +               case PARSE_ERROR:
34288 +                       /* parsing failed */
34289 +
34290 +                       con->http_status = 502; /* Bad Gateway */
34291                         return 1;
34292 -               }
34293 -               
34294 -               hctx->response->ptr[n] = '\0';
34295 -               hctx->response->used = n+1;
34296 -               
34297 -               /* split header from body */
34298 -               
34299 -               if (con->file_started == 0) {
34300 -                       char *c;
34301 -                       int in_header = 0;
34302 -                       int header_end = 0;
34303 -                       int cp, eol = EOL_UNSET;
34304 -                       size_t used = 0;
34305 -                       
34306 -                       buffer_append_string_buffer(hctx->response_header, hctx->response);
34307 -                       
34308 -                       /* nph (non-parsed headers) */
34309 -                       if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;
34310 -                       
34311 -                       /* search for the \r\n\r\n or \n\n in the string */
34312 -                       for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) {
34313 -                               if (*c == ':') in_header = 1;
34314 -                               else if (*c == '\n') {
34315 -                                       if (in_header == 0) {
34316 -                                               /* got a response without a response header */
34317 -                                               
34318 -                                               c = NULL;
34319 -                                               header_end = 1;
34320 -                                               break;
34321 -                                       }
34322 -                                       
34323 -                                       if (eol == EOL_UNSET) eol = EOL_N;
34324 -                                       
34325 -                                       if (*(c+1) == '\n') {
34326 -                                               header_end = 1;
34327 -                                               break;
34328 -                                       }
34329 -                                       
34330 -                               } else if (used > 1 && *c == '\r' && *(c+1) == '\n') {
34331 -                                       if (in_header == 0) {
34332 -                                               /* got a response without a response header */
34333 -                                               
34334 -                                               c = NULL;
34335 -                                               header_end = 1;
34336 -                                               break;
34337 -                                       }
34338 -                                       
34339 -                                       if (eol == EOL_UNSET) eol = EOL_RN;
34340 -                                       
34341 -                                       if (used > 3 &&
34342 -                                           *(c+2) == '\r' && 
34343 -                                           *(c+3) == '\n') {
34344 -                                               header_end = 1;
34345 -                                               break;
34346 -                                       }
34347 -                                       
34348 -                                       /* skip the \n */
34349 -                                       c++;
34350 -                                       cp++;
34351 -                                       used--;
34352 +               case PARSE_NEED_MORE:
34353 +                       return 0;
34354 +               case PARSE_SUCCESS:
34355 +                       con->http_status = p->resp->status;
34356 +
34357 +                       chunkqueue_remove_finished_chunks(hctx->rb);
34358 +
34359 +                       /* copy the http-headers */
34360 +                       for (i = 0; i < p->resp->headers->used; i++) {
34361 +                               const char *ign[] = { "Status", "Connection", NULL };
34362 +                               size_t j;
34363 +                               data_string *ds;
34364 +
34365 +                               data_string *header = (data_string *)p->resp->headers->data[i];
34366 +
34367 +                               /* some headers are ignored by default */
34368 +                               for (j = 0; ign[j]; j++) {
34369 +                                       if (0 == strcasecmp(ign[j], header->key->ptr)) break;
34370                                 }
34371 -                       }
34372 -                       
34373 -                       if (header_end) {
34374 -                               if (c == NULL) {
34375 -                                       /* no header, but a body */
34376 -                                       
34377 -                                       if (con->request.http_version == HTTP_VERSION_1_1) {
34378 -                                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
34379 -                                       }
34380 -                                       
34381 -                                       http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
34382 -                                       joblist_append(srv, con);
34383 -                               } else {
34384 -                                       size_t hlen = c - hctx->response_header->ptr + (eol == EOL_RN ? 4 : 2);
34385 -                                       size_t blen = hctx->response_header->used - hlen - 1;
34386 -                               
34387 -                                       /* a small hack: terminate after at the second \r */
34388 -                                       hctx->response_header->used = hlen + 1 - (eol == EOL_RN ? 2 : 1);
34389 -                                       hctx->response_header->ptr[hlen - (eol == EOL_RN ? 2 : 1)] = '\0';
34390 -                               
34391 -                                       /* parse the response header */
34392 -                                       scgi_response_parse(srv, con, p, hctx->response_header, eol);
34393 -                                       
34394 -                                       /* enable chunked-transfer-encoding */
34395 -                                       if (con->request.http_version == HTTP_VERSION_1_1 &&
34396 -                                           !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
34397 -                                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
34398 -                                       }
34399 -                                       
34400 -                                       if ((hctx->response->used != hlen) && blen > 0) {
34401 -                                               http_chunk_append_mem(srv, con, c + (eol == EOL_RN ? 4: 2), blen + 1);
34402 -                                               joblist_append(srv, con);
34403 -                                       }
34404 +                               if (ign[j]) continue;
34405 +
34406 +                               if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
34407 +                                       /* CGI/1.1 rev 03 - 7.2.1.2 */
34408 +                                       if (con->http_status == 0) con->http_status = 302;
34409 +                               } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
34410 +                                       have_content_length = 1;
34411                                 }
34412                                 
34413 -                               con->file_started = 1;
34414 +                               if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
34415 +                                       ds = data_response_init();
34416 +                               }
34417 +                               buffer_copy_string_buffer(ds->key, header->key);
34418 +                               buffer_copy_string_buffer(ds->value, header->value);
34419 +
34420 +                               array_insert_unique(con->response.headers, (data_unset *)ds);
34421                         }
34422 -               } else {
34423 -                       http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
34424 -                       joblist_append(srv, con);
34425 +
34426 +                       con->file_started = 1;
34427 +
34428 +                       if (con->request.http_version == HTTP_VERSION_1_1 &&
34429 +                           !have_content_length) {
34430 +                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
34431 +                       }
34432 +
34433 +                       hctx->state = SCGI_STATE_RESPONSE_CONTENT;
34434 +                       break;
34435                 }
34436 -               
34437 -#if 0          
34438 -               log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr);
34439 -#endif
34440         }
34441 -       
34442 +
34443 +       /* FIXME: pass the response-header to the other plugins to
34444 +       * setup the filter-queue
34445 +       *
34446 +       * - use next-queue instead of con->write_queue
34447 +       */
34448 +
34449 +       assert(hctx->state == SCGI_STATE_RESPONSE_CONTENT);
34450 +
34451 +       /* FIXME: if we have a content-length or chunked-encoding
34452 +       * handle it.
34453 +       *
34454 +       * for now we wait for EOF on the socket */
34455 +
34456 +       /* copy the content to the next cq */
34457 +       for (c = hctx->rb->first; c; c = c->next) {
34458 +               http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
34459 +
34460 +               c->offset = c->mem->used - 1;
34461 +       }
34462 +
34463 +       chunkqueue_remove_finished_chunks(hctx->rb);
34464 +       joblist_append(srv, con);
34465 +
34466         return 0;
34467  }
34468  
34469  
34470  int scgi_proclist_sort_up(server *srv, scgi_extension_host *host, scgi_proc *proc) {
34471         scgi_proc *p;
34472 -       
34473 +
34474         UNUSED(srv);
34475 -       
34476 -       /* we have been the smallest of the current list 
34477 -        * and we want to insert the node sorted as soon 
34478 +
34479 +       /* we have been the smallest of the current list
34480 +        * and we want to insert the node sorted as soon
34481          * possible
34482          *
34483 -        * 1 0 0 0 1 1 1 
34484 -        * |      ^ 
34485 +        * 1 0 0 0 1 1 1
34486 +        * |      ^
34487          * |      |
34488          * +------+
34489 -        * 
34490 +        *
34491          */
34492  
34493         /* nothing to sort, only one element */
34494 @@ -1909,9 +1771,9 @@
34495  
34496         for (p = proc; p->next && p->next->load < proc->load; p = p->next);
34497  
34498 -       /* no need to move something 
34499 +       /* no need to move something
34500          *
34501 -        * 1 2 2 2 3 3 3 
34502 +        * 1 2 2 2 3 3 3
34503          * ^
34504          * |
34505          * +
34506 @@ -1930,16 +1792,16 @@
34507  
34508         if (proc->prev) proc->prev->next = proc->next;
34509         if (proc->next) proc->next->prev = proc->prev;
34510 -       
34511 +
34512         /* proc should be right of p */
34513 -       
34514 +
34515         proc->next = p->next;
34516         proc->prev = p;
34517         if (p->next) p->next->prev = proc;
34518         p->next = proc;
34519  #if 0
34520         for(p = host->first; p; p = p->next) {
34521 -               log_error_write(srv, __FILE__, __LINE__, "dd", 
34522 +               log_error_write(srv, __FILE__, __LINE__, "dd",
34523                                 p->pid, p->load);
34524         }
34525  #else
34526 @@ -1951,21 +1813,21 @@
34527  
34528  int scgi_proclist_sort_down(server *srv, scgi_extension_host *host, scgi_proc *proc) {
34529         scgi_proc *p;
34530 -       
34531 +
34532         UNUSED(srv);
34533 -       
34534 -       /* we have been the smallest of the current list 
34535 -        * and we want to insert the node sorted as soon 
34536 +
34537 +       /* we have been the smallest of the current list
34538 +        * and we want to insert the node sorted as soon
34539          * possible
34540          *
34541 -        *  0 0 0 0 1 0 1 
34542 +        *  0 0 0 0 1 0 1
34543          * ^          |
34544          * |          |
34545          * +----------+
34546          *
34547          *
34548          * the basic is idea is:
34549 -        * - the last active scgi process should be still 
34550 +        * - the last active scgi process should be still
34551          *   in ram and is not swapped out yet
34552          * - processes that are not reused will be killed
34553          *   after some time by the trigger-handler
34554 @@ -1975,7 +1837,7 @@
34555          *   ice-cold processes are propably unused since more
34556          *   than 'unused-timeout', are swaped out and won't be
34557          *   reused in the next seconds anyway.
34558 -        * 
34559 +        *
34560          */
34561  
34562         /* nothing to sort, only one element */
34563 @@ -1984,16 +1846,16 @@
34564         for (p = host->first; p != proc && p->load < proc->load; p = p->next);
34565  
34566  
34567 -       /* no need to move something 
34568 +       /* no need to move something
34569          *
34570 -        * 1 2 2 2 3 3 3 
34571 +        * 1 2 2 2 3 3 3
34572          * ^
34573          * |
34574          * +
34575          *
34576          */
34577         if (p == proc) return 0;
34578 -       
34579 +
34580         /* we have to move left. If we are already the first element
34581          * we are done */
34582         if (host->first == proc) return 0;
34583 @@ -2009,9 +1871,9 @@
34584         p->prev = proc;
34585  
34586         if (proc->prev == NULL) host->first = proc;
34587 -#if 0  
34588 +#if 0
34589         for(p = host->first; p; p = p->next) {
34590 -               log_error_write(srv, __FILE__, __LINE__, "dd", 
34591 +               log_error_write(srv, __FILE__, __LINE__, "dd",
34592                                 p->pid, p->load);
34593         }
34594  #else
34595 @@ -2023,41 +1885,42 @@
34596  
34597  static int scgi_restart_dead_procs(server *srv, plugin_data *p, scgi_extension_host *host) {
34598         scgi_proc *proc;
34599 -       
34600 +
34601         for (proc = host->first; proc; proc = proc->next) {
34602                 if (p->conf.debug) {
34603 -                       log_error_write(srv, __FILE__, __LINE__,  "sbdbdddd", 
34604 -                                       "proc:", 
34605 -                                       host->host, proc->port, 
34606 +                       log_error_write(srv, __FILE__, __LINE__,  "sbdbdddd",
34607 +                                       "proc:",
34608 +                                       host->host, proc->port,
34609                                         proc->socket,
34610                                         proc->state,
34611                                         proc->is_local,
34612                                         proc->load,
34613                                         proc->pid);
34614                 }
34615 -               
34616 +
34617                 if (0 == proc->is_local) {
34618 -                       /* 
34619 -                        * external servers might get disabled 
34620 -                        * 
34621 -                        * enable the server again, perhaps it is back again 
34622 +                       /*
34623 +                        * external servers might get disabled
34624 +                        *
34625 +                        * enable the server again, perhaps it is back again
34626                          */
34627 -                       
34628 +
34629                         if ((proc->state == PROC_STATE_DISABLED) &&
34630                             (srv->cur_ts - proc->disable_ts > host->disable_time)) {
34631                                 proc->state = PROC_STATE_RUNNING;
34632                                 host->active_procs++;
34633 -                               
34634 -                               log_error_write(srv, __FILE__, __LINE__,  "sbdb", 
34635 -                                               "fcgi-server re-enabled:", 
34636 -                                               host->host, host->port, 
34637 +
34638 +                               log_error_write(srv, __FILE__, __LINE__,  "sbdb",
34639 +                                               "fcgi-server re-enabled:",
34640 +                                               host->host, host->port,
34641                                                 host->unixsocket);
34642                         }
34643                 } else {
34644                         /* the child should not terminate at all */
34645                         int status;
34646 -                       
34647 +
34648                         if (proc->state == PROC_STATE_DIED_WAIT_FOR_PID) {
34649 +#ifndef _WIN32
34650                                 switch(waitpid(proc->pid, &status, WNOHANG)) {
34651                                 case 0:
34652                                         /* child is still alive */
34653 @@ -2067,33 +1930,34 @@
34654                                 default:
34655                                         if (WIFEXITED(status)) {
34656  #if 0
34657 -                                               log_error_write(srv, __FILE__, __LINE__, "sdsd", 
34658 +                                               log_error_write(srv, __FILE__, __LINE__, "sdsd",
34659                                                                 "child exited, pid:", proc->pid,
34660                                                                 "status:", WEXITSTATUS(status));
34661  #endif
34662                                         } else if (WIFSIGNALED(status)) {
34663 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
34664 -                                                               "child signaled:", 
34665 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
34666 +                                                               "child signaled:",
34667                                                                 WTERMSIG(status));
34668                                         } else {
34669 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
34670 -                                                               "child died somehow:", 
34671 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
34672 +                                                               "child died somehow:",
34673                                                                 status);
34674                                         }
34675 -                                       
34676 +
34677                                         proc->state = PROC_STATE_DIED;
34678                                         break;
34679                                 }
34680 +#endif
34681                         }
34682 -                       
34683 -                       /* 
34684 +
34685 +                       /*
34686                          * local servers might died, but we restart them
34687 -                        * 
34688 +                        *
34689                          */
34690                         if (proc->state == PROC_STATE_DIED &&
34691                             proc->load == 0) {
34692                                 /* restart the child */
34693 -                               
34694 +
34695                                 if (p->conf.debug) {
34696                                         log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
34697                                                         "--- scgi spawning",
34698 @@ -2101,18 +1965,18 @@
34699                                                         "\n\tsocket", host->unixsocket,
34700                                                         "\n\tcurrent:", 1, "/", host->min_procs);
34701                                 }
34702 -                               
34703 +
34704                                 if (scgi_spawn_connection(srv, p, host, proc)) {
34705                                         log_error_write(srv, __FILE__, __LINE__, "s",
34706                                                         "ERROR: spawning fcgi failed.");
34707                                         return HANDLER_ERROR;
34708                                 }
34709 -                               
34710 +
34711                                 scgi_proclist_sort_down(srv, host, proc);
34712                         }
34713                 }
34714         }
34715 -       
34716 +
34717         return 0;
34718  }
34719  
34720 @@ -2121,13 +1985,13 @@
34721         plugin_data *p    = hctx->plugin_data;
34722         scgi_extension_host *host= hctx->host;
34723         connection *con   = hctx->remote_conn;
34724 -       
34725 +
34726         int ret;
34727  
34728 -       /* sanity check */      
34729 +       /* sanity check */
34730         if (!host ||
34731             ((!host->host->used || !host->port) && !host->unixsocket->used)) {
34732 -               log_error_write(srv, __FILE__, __LINE__, "sxddd", 
34733 +               log_error_write(srv, __FILE__, __LINE__, "sxddd",
34734                                 "write-req: error",
34735                                 host,
34736                                 host->host->used,
34737 @@ -2135,259 +1999,260 @@
34738                                 host->unixsocket->used);
34739                 return HANDLER_ERROR;
34740         }
34741 -       
34742 +
34743  
34744         switch(hctx->state) {
34745 -       case FCGI_STATE_INIT:
34746 +       case SCGI_STATE_INIT:
34747                 ret = host->unixsocket->used ? AF_UNIX : AF_INET;
34748 -               
34749 -               if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
34750 +
34751 +               if (-1 == (hctx->sock->fd = socket(ret, SOCK_STREAM, 0))) {
34752                         if (errno == EMFILE ||
34753                             errno == EINTR) {
34754 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
34755 -                                               "wait for fd at connection:", con->fd);
34756 -                               
34757 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
34758 +                                               "wait for fd at connection:", con->sock->fd);
34759 +
34760                                 return HANDLER_WAIT_FOR_FD;
34761                         }
34762 -                       
34763 -                       log_error_write(srv, __FILE__, __LINE__, "ssdd", 
34764 +
34765 +                       log_error_write(srv, __FILE__, __LINE__, "ssdd",
34766                                         "socket failed:", strerror(errno), srv->cur_fds, srv->max_fds);
34767                         return HANDLER_ERROR;
34768                 }
34769 -               hctx->fde_ndx = -1;
34770 -               
34771 +               hctx->sock->fde_ndx = -1;
34772 +
34773                 srv->cur_fds++;
34774 -               
34775 -               fdevent_register(srv->ev, hctx->fd, scgi_handle_fdevent, hctx);
34776 -               
34777 -               if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
34778 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
34779 +
34780 +               fdevent_register(srv->ev, hctx->sock, scgi_handle_fdevent, hctx);
34781 +
34782 +               if (-1 == fdevent_fcntl_set(srv->ev, hctx->sock)) {
34783 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
34784                                         "fcntl failed: ", strerror(errno));
34785 -                       
34786 +
34787                         return HANDLER_ERROR;
34788                 }
34789 -               
34790 +
34791                 /* fall through */
34792 -       case FCGI_STATE_CONNECT:
34793 -               if (hctx->state == FCGI_STATE_INIT) {
34794 -                       for (hctx->proc = hctx->host->first; 
34795 -                            hctx->proc && hctx->proc->state != PROC_STATE_RUNNING; 
34796 +       case SCGI_STATE_CONNECT:
34797 +               if (hctx->state == SCGI_STATE_INIT) {
34798 +                       for (hctx->proc = hctx->host->first;
34799 +                            hctx->proc && hctx->proc->state != PROC_STATE_RUNNING;
34800                              hctx->proc = hctx->proc->next);
34801 -                       
34802 +
34803                         /* all childs are dead */
34804                         if (hctx->proc == NULL) {
34805 -                               hctx->fde_ndx = -1;
34806 -                               
34807 +                               hctx->sock->fde_ndx = -1;
34808 +
34809                                 return HANDLER_ERROR;
34810                         }
34811 -                       
34812 +
34813                         if (hctx->proc->is_local) {
34814                                 hctx->pid = hctx->proc->pid;
34815                         }
34816 -                       
34817 +
34818                         switch (scgi_establish_connection(srv, hctx)) {
34819                         case 1:
34820 -                               scgi_set_state(srv, hctx, FCGI_STATE_CONNECT);
34821 -                               
34822 +                               scgi_set_state(srv, hctx, SCGI_STATE_CONNECT);
34823 +
34824                                 /* connection is in progress, wait for an event and call getsockopt() below */
34825 -                               
34826 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
34827 -                               
34828 +
34829 +                               fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
34830 +
34831                                 return HANDLER_WAIT_FOR_EVENT;
34832                         case -1:
34833                                 /* if ECONNREFUSED choose another connection -> FIXME */
34834 -                               hctx->fde_ndx = -1;
34835 -                               
34836 +                               hctx->sock->fde_ndx = -1;
34837 +
34838                                 return HANDLER_ERROR;
34839                         default:
34840                                 /* everything is ok, go on */
34841                                 break;
34842                         }
34843  
34844 -                       
34845 +
34846                 } else {
34847                         int socket_error;
34848                         socklen_t socket_error_len = sizeof(socket_error);
34849 -                       
34850 +
34851                         /* try to finish the connect() */
34852 -                       if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
34853 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
34854 +                       if (0 != getsockopt(hctx->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
34855 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
34856                                                 "getsockopt failed:", strerror(errno));
34857 -                               
34858 +
34859                                 return HANDLER_ERROR;
34860                         }
34861                         if (socket_error != 0) {
34862                                 if (!hctx->proc->is_local || p->conf.debug) {
34863                                         /* local procs get restarted */
34864 -                                       
34865 +
34866                                         log_error_write(srv, __FILE__, __LINE__, "ss",
34867 -                                                       "establishing connection failed:", strerror(socket_error), 
34868 +                                                       "establishing connection failed:", strerror(socket_error),
34869                                                         "port:", hctx->proc->port);
34870                                 }
34871 -                               
34872 +
34873                                 return HANDLER_ERROR;
34874                         }
34875                 }
34876 -               
34877 +
34878                 /* ok, we have the connection */
34879 -               
34880 +
34881                 hctx->proc->load++;
34882                 hctx->proc->last_used = srv->cur_ts;
34883                 hctx->got_proc = 1;
34884 -               
34885 +
34886                 if (p->conf.debug) {
34887                         log_error_write(srv, __FILE__, __LINE__, "sddbdd",
34888 -                                       "got proc:", 
34889 -                                       hctx->fd,
34890 -                                       hctx->proc->pid, 
34891 -                                       hctx->proc->socket, 
34892 +                                       "got proc:",
34893 +                                       hctx->sock->fd,
34894 +                                       hctx->proc->pid,
34895 +                                       hctx->proc->socket,
34896                                         hctx->proc->port,
34897                                         hctx->proc->load);
34898                 }
34899  
34900                 /* move the proc-list entry down the list */
34901                 scgi_proclist_sort_up(srv, hctx->host, hctx->proc);
34902 -               
34903 -               scgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
34904 +
34905 +               scgi_set_state(srv, hctx, SCGI_STATE_PREPARE_WRITE);
34906                 /* fall through */
34907 -       case FCGI_STATE_PREPARE_WRITE:
34908 +       case SCGI_STATE_PREPARE_WRITE:
34909                 scgi_create_env(srv, hctx);
34910 -               
34911 -               scgi_set_state(srv, hctx, FCGI_STATE_WRITE);
34912 -               
34913 +
34914 +               scgi_set_state(srv, hctx, SCGI_STATE_WRITE);
34915 +
34916                 /* fall through */
34917 -       case FCGI_STATE_WRITE:
34918 -               ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); 
34919 +       case SCGI_STATE_WRITE:
34920 +               ret = srv->network_backend_write(srv, con, hctx->sock, hctx->wb);
34921  
34922                 chunkqueue_remove_finished_chunks(hctx->wb);
34923 -       
34924 +
34925                 if (-1 == ret) {
34926                         if (errno == ENOTCONN) {
34927 -                               /* the connection got dropped after accept() 
34928 -                                * 
34929 -                                * this is most of the time a PHP which dies 
34930 +                               /* the connection got dropped after accept()
34931 +                                *
34932 +                                * this is most of the time a PHP which dies
34933                                  * after PHP_FCGI_MAX_REQUESTS
34934 -                                * 
34935 -                                */ 
34936 +                                *
34937 +                                */
34938                                 if (hctx->wb->bytes_out == 0 &&
34939                                     hctx->reconnects < 5) {
34940 -                                       usleep(10000); /* take away the load of the webserver 
34941 -                                                       * to let the php a chance to restart 
34942 +#ifndef _WIN32
34943 +                                       usleep(10000); /* take away the load of the webserver
34944 +                                                       * to let the php a chance to restart
34945                                                         */
34946 -                                       
34947 +#endif
34948                                         scgi_reconnect(srv, hctx);
34949 -                               
34950 +
34951                                         return HANDLER_WAIT_FOR_FD;
34952                                 }
34953 -                               
34954 +
34955                                 /* not reconnected ... why
34956 -                                * 
34957 +                                *
34958                                  * far@#lighttpd report this for FreeBSD
34959 -                                * 
34960 +                                *
34961                                  */
34962 -                               
34963 -                               log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
34964 +
34965 +                               log_error_write(srv, __FILE__, __LINE__, "ssosd",
34966                                                 "[REPORT ME] connection was dropped after accept(). reconnect() denied:",
34967                                                 "write-offset:", hctx->wb->bytes_out,
34968                                                 "reconnect attempts:", hctx->reconnects);
34969 -                               
34970 +
34971                                 return HANDLER_ERROR;
34972                         }
34973 -                       
34974 +
34975                         if ((errno != EAGAIN) &&
34976                             (errno != EINTR)) {
34977 -                               
34978 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", 
34979 +
34980 +                               log_error_write(srv, __FILE__, __LINE__, "ssd",
34981                                                 "write failed:", strerror(errno), errno);
34982 -                               
34983 +
34984                                 return HANDLER_ERROR;
34985                         } else {
34986 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
34987 -                               
34988 +                               fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
34989 +
34990                                 return HANDLER_WAIT_FOR_EVENT;
34991                         }
34992                 }
34993 -               
34994 +
34995                 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
34996                         /* we don't need the out event anymore */
34997 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
34998 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
34999 -                       scgi_set_state(srv, hctx, FCGI_STATE_READ);
35000 +                       fdevent_event_del(srv->ev, hctx->sock);
35001 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
35002 +                       scgi_set_state(srv, hctx, SCGI_STATE_RESPONSE_HEADER);
35003                 } else {
35004 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
35005 -                       
35006 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
35007 +
35008                         return HANDLER_WAIT_FOR_EVENT;
35009                 }
35010 -               
35011 +
35012                 break;
35013 -       case FCGI_STATE_READ:
35014 +       case SCGI_STATE_RESPONSE_HEADER:
35015                 /* waiting for a response */
35016                 break;
35017         default:
35018                 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
35019                 return HANDLER_ERROR;
35020         }
35021 -       
35022 +
35023         return HANDLER_WAIT_FOR_EVENT;
35024  }
35025  
35026  SUBREQUEST_FUNC(mod_scgi_handle_subrequest) {
35027         plugin_data *p = p_d;
35028 -       
35029 +
35030         handler_ctx *hctx = con->plugin_ctx[p->id];
35031         scgi_proc *proc;
35032         scgi_extension_host *host;
35033 -       
35034 +
35035         if (NULL == hctx) return HANDLER_GO_ON;
35036 -       
35037 +
35038         /* not my job */
35039         if (con->mode != p->id) return HANDLER_GO_ON;
35040 -       
35041 +
35042         /* ok, create the request */
35043         switch(scgi_write_request(srv, hctx)) {
35044         case HANDLER_ERROR:
35045                 proc = hctx->proc;
35046                 host = hctx->host;
35047 -               
35048 -               if (proc && 
35049 +
35050 +               if (proc &&
35051                     0 == proc->is_local &&
35052                     proc->state != PROC_STATE_DISABLED) {
35053                         /* only disable remote servers as we don't manage them*/
35054 -                       
35055 -                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", "fcgi-server disabled:", 
35056 +
35057 +                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", "fcgi-server disabled:",
35058                                         host->host,
35059                                         proc->port,
35060                                         proc->socket);
35061 -                       
35062 +
35063                         /* disable this server */
35064                         proc->disable_ts = srv->cur_ts;
35065                         proc->state = PROC_STATE_DISABLED;
35066                         host->active_procs--;
35067                 }
35068 -               
35069 -               if (hctx->state == FCGI_STATE_INIT ||
35070 -                   hctx->state == FCGI_STATE_CONNECT) {
35071 -                       /* connect() or getsockopt() failed, 
35072 -                        * restart the request-handling 
35073 +
35074 +               if (hctx->state == SCGI_STATE_INIT ||
35075 +                   hctx->state == SCGI_STATE_CONNECT) {
35076 +                       /* connect() or getsockopt() failed,
35077 +                        * restart the request-handling
35078                          */
35079                         if (proc && proc->is_local) {
35080  
35081                                 if (p->conf.debug) {
35082 -                                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", "connect() to scgi failed, restarting the request-handling:", 
35083 +                                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", "connect() to scgi failed, restarting the request-handling:",
35084                                                         host->host,
35085                                                         proc->port,
35086                                                         proc->socket);
35087                                 }
35088  
35089 -                               /* 
35090 +                               /*
35091                                  * several hctx might reference the same proc
35092 -                                * 
35093 +                                *
35094                                  * Only one of them should mark the proc as dead all the other
35095                                  * ones should just take a new one.
35096 -                                * 
35097 +                                *
35098                                  * If a new proc was started with the old struct this might lead
35099                                  * the mark a perfect proc as dead otherwise
35100 -                                * 
35101 +                                *
35102                                  */
35103                                 if (proc->state == PROC_STATE_RUNNING &&
35104                                     hctx->pid == proc->pid) {
35105 @@ -2395,25 +2260,25 @@
35106                                 }
35107                         }
35108                         scgi_restart_dead_procs(srv, p, host);
35109 -                       
35110 +
35111                         scgi_connection_cleanup(srv, hctx);
35112 -                       
35113 +
35114                         buffer_reset(con->physical.path);
35115                         con->mode = DIRECT;
35116                         joblist_append(srv, con);
35117 -                       
35118 -                       /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop 
35119 -                        * and hope that the childs will be restarted 
35120 -                        * 
35121 +
35122 +                       /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
35123 +                        * and hope that the childs will be restarted
35124 +                        *
35125                          */
35126                         return HANDLER_WAIT_FOR_FD;
35127                 } else {
35128                         scgi_connection_cleanup(srv, hctx);
35129 -                       
35130 +
35131                         buffer_reset(con->physical.path);
35132                         con->mode = DIRECT;
35133                         con->http_status = 503;
35134 -                       
35135 +
35136                         return HANDLER_FINISHED;
35137                 }
35138         case HANDLER_WAIT_FOR_EVENT:
35139 @@ -2433,23 +2298,23 @@
35140  static handler_t scgi_connection_close(server *srv, handler_ctx *hctx) {
35141         plugin_data *p;
35142         connection  *con;
35143 -       
35144 +
35145         if (NULL == hctx) return HANDLER_GO_ON;
35146 -       
35147 +
35148         p    = hctx->plugin_data;
35149         con  = hctx->remote_conn;
35150 -       
35151 +
35152         if (con->mode != p->id) return HANDLER_GO_ON;
35153 -       
35154 -       log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
35155 -                       "emergency exit: scgi:", 
35156 -                       "connection-fd:", con->fd,
35157 -                       "fcgi-fd:", hctx->fd);
35158 -       
35159 -       
35160 -       
35161 +
35162 +       log_error_write(srv, __FILE__, __LINE__, "ssdsd",
35163 +                       "emergency exit: scgi:",
35164 +                       "connection-fd:", con->sock->fd,
35165 +                       "fcgi-fd:", hctx->sock->fd);
35166 +
35167 +
35168 +
35169         scgi_connection_cleanup(srv, hctx);
35170 -       
35171 +
35172         return HANDLER_FINISHED;
35173  }
35174  
35175 @@ -2459,27 +2324,28 @@
35176         handler_ctx *hctx = ctx;
35177         connection  *con  = hctx->remote_conn;
35178         plugin_data *p    = hctx->plugin_data;
35179 -       
35180 +
35181         scgi_proc *proc   = hctx->proc;
35182         scgi_extension_host *host= hctx->host;
35183  
35184         if ((revents & FDEVENT_IN) &&
35185 -           hctx->state == FCGI_STATE_READ) {
35186 +           (hctx->state == SCGI_STATE_RESPONSE_HEADER ||
35187 +            hctx->state == SCGI_STATE_RESPONSE_CONTENT)) {
35188                 switch (scgi_demux_response(srv, hctx)) {
35189                 case 0:
35190                         break;
35191                 case 1:
35192                         /* we are done */
35193                         scgi_connection_cleanup(srv, hctx);
35194 -                       
35195 +
35196                         joblist_append(srv, con);
35197                         return HANDLER_FINISHED;
35198                 case -1:
35199                         if (proc->pid && proc->state != PROC_STATE_DIED) {
35200                                 int status;
35201 -                               
35202 +
35203                                 /* only fetch the zombie if it is not already done */
35204 -                               
35205 +#ifndef _WIN32
35206                                 switch(waitpid(proc->pid, &status, WNOHANG)) {
35207                                 case 0:
35208                                         /* child is still alive */
35209 @@ -2489,19 +2355,19 @@
35210                                 default:
35211                                         /* the child should not terminate at all */
35212                                         if (WIFEXITED(status)) {
35213 -                                               log_error_write(srv, __FILE__, __LINE__, "sdsd", 
35214 +                                               log_error_write(srv, __FILE__, __LINE__, "sdsd",
35215                                                                 "child exited, pid:", proc->pid,
35216                                                                 "status:", WEXITSTATUS(status));
35217                                         } else if (WIFSIGNALED(status)) {
35218 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
35219 -                                                               "child signaled:", 
35220 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
35221 +                                                               "child signaled:",
35222                                                                 WTERMSIG(status));
35223                                         } else {
35224 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
35225 -                                                               "child died somehow:", 
35226 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
35227 +                                                               "child died somehow:",
35228                                                                 status);
35229                                         }
35230 -                                       
35231 +
35232                                         if (p->conf.debug) {
35233                                                 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
35234                                                                 "--- scgi spawning",
35235 @@ -2509,40 +2375,41 @@
35236                                                                 "\n\tsocket", host->unixsocket,
35237                                                                 "\n\tcurrent:", 1, "/", host->min_procs);
35238                                         }
35239 -                                       
35240 +
35241                                         if (scgi_spawn_connection(srv, p, host, proc)) {
35242                                                 /* child died */
35243                                                 proc->state = PROC_STATE_DIED;
35244                                         } else {
35245                                                 scgi_proclist_sort_down(srv, host, proc);
35246                                         }
35247 -                                       
35248 +
35249                                         break;
35250                                 }
35251 +#endif
35252                         }
35253  
35254                         if (con->file_started == 0) {
35255                                 /* nothing has been send out yet, try to use another child */
35256 -                               
35257 +
35258                                 if (hctx->wb->bytes_out == 0 &&
35259                                     hctx->reconnects < 5) {
35260                                         scgi_reconnect(srv, hctx);
35261 -                                       
35262 -                                       log_error_write(srv, __FILE__, __LINE__, "sdsdsd", 
35263 +
35264 +                                       log_error_write(srv, __FILE__, __LINE__, "sdsdsd",
35265                                                 "response not sent, request not sent, reconnection.",
35266 -                                               "connection-fd:", con->fd,
35267 -                                               "fcgi-fd:", hctx->fd);
35268 -                                       
35269 +                                               "connection-fd:", con->sock->fd,
35270 +                                               "fcgi-fd:", hctx->sock->fd);
35271 +
35272                                         return HANDLER_WAIT_FOR_FD;
35273                                 }
35274 -                               
35275 -                               log_error_write(srv, __FILE__, __LINE__, "sdsdsd", 
35276 +
35277 +                               log_error_write(srv, __FILE__, __LINE__, "sosdsd",
35278                                                 "response not sent, request sent:", hctx->wb->bytes_out,
35279 -                                               "connection-fd:", con->fd,
35280 -                                               "fcgi-fd:", hctx->fd);
35281 -                               
35282 +                                               "connection-fd:", con->sock->fd,
35283 +                                               "fcgi-fd:", hctx->sock->fd);
35284 +
35285                                 scgi_connection_cleanup(srv, hctx);
35286 -                               
35287 +
35288                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
35289                                 buffer_reset(con->physical.path);
35290                                 con->http_status = 500;
35291 @@ -2550,76 +2417,77 @@
35292                         } else {
35293                                 /* response might have been already started, kill the connection */
35294                                 scgi_connection_cleanup(srv, hctx);
35295 -                               
35296 -                               log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
35297 +
35298 +                               log_error_write(srv, __FILE__, __LINE__, "ssdsd",
35299                                                 "response already sent out, termination connection",
35300 -                                               "connection-fd:", con->fd,
35301 -                                               "fcgi-fd:", hctx->fd);
35302 -                               
35303 +                                               "connection-fd:", con->sock->fd,
35304 +                                               "fcgi-fd:", hctx->sock->fd);
35305 +
35306                                 connection_set_state(srv, con, CON_STATE_ERROR);
35307                         }
35308  
35309                         /* */
35310 -                       
35311 -                       
35312 +
35313 +
35314                         joblist_append(srv, con);
35315                         return HANDLER_FINISHED;
35316                 }
35317         }
35318 -       
35319 +
35320         if (revents & FDEVENT_OUT) {
35321 -               if (hctx->state == FCGI_STATE_CONNECT ||
35322 -                   hctx->state == FCGI_STATE_WRITE) {
35323 +               if (hctx->state == SCGI_STATE_CONNECT ||
35324 +                   hctx->state == SCGI_STATE_WRITE) {
35325                         /* we are allowed to send something out
35326 -                        * 
35327 +                        *
35328                          * 1. in a unfinished connect() call
35329                          * 2. in a unfinished write() call (long POST request)
35330                          */
35331                         return mod_scgi_handle_subrequest(srv, con, p);
35332                 } else {
35333 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
35334 -                                       "got a FDEVENT_OUT and didn't know why:", 
35335 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
35336 +                                       "got a FDEVENT_OUT and didn't know why:",
35337                                         hctx->state);
35338                 }
35339         }
35340 -       
35341 +
35342         /* perhaps this issue is already handled */
35343         if (revents & FDEVENT_HUP) {
35344 -               if (hctx->state == FCGI_STATE_CONNECT) {
35345 +               if (hctx->state == SCGI_STATE_CONNECT) {
35346                         /* getoptsock will catch this one (right ?)
35347 -                        * 
35348 -                        * if we are in connect we might get a EINPROGRESS 
35349 -                        * in the first call and a FDEVENT_HUP in the 
35350 +                        *
35351 +                        * if we are in connect we might get a EINPROGRESS
35352 +                        * in the first call and a FDEVENT_HUP in the
35353                          * second round
35354 -                        * 
35355 +                        *
35356                          * FIXME: as it is a bit ugly.
35357 -                        * 
35358 +                        *
35359                          */
35360                         return mod_scgi_handle_subrequest(srv, con, p);
35361 -               } else if (hctx->state == FCGI_STATE_READ &&
35362 +               } else if ((hctx->state == SCGI_STATE_RESPONSE_HEADER ||
35363 +                           hctx->state == SCGI_STATE_RESPONSE_CONTENT ) &&
35364                            hctx->proc->port == 0) {
35365                         /* FIXME:
35366 -                        * 
35367 +                        *
35368                          * ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket
35369                          * even if the FCGI_FIN packet is not received yet
35370                          */
35371                 } else {
35372 -                       log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd", 
35373 -                                       "error: unexpected close of scgi connection for", 
35374 +                       log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
35375 +                                       "error: unexpected close of scgi connection for",
35376                                         con->uri.path,
35377 -                                       "(no scgi process on host: ", 
35378 +                                       "(no scgi process on host: ",
35379                                         host->host,
35380 -                                       ", port: ", 
35381 +                                       ", port: ",
35382                                         host->port,
35383                                         " ?)",
35384                                         hctx->state);
35385 -                       
35386 +
35387                         connection_set_state(srv, con, CON_STATE_ERROR);
35388                         scgi_connection_close(srv, hctx);
35389                         joblist_append(srv, con);
35390                 }
35391         } else if (revents & FDEVENT_ERR) {
35392 -               log_error_write(srv, __FILE__, __LINE__, "s", 
35393 +               log_error_write(srv, __FILE__, __LINE__, "s",
35394                                 "fcgi: got a FDEVENT_ERR. Don't know why.");
35395                 /* kill all connections to the scgi process */
35396  
35397 @@ -2628,42 +2496,39 @@
35398                 scgi_connection_close(srv, hctx);
35399                 joblist_append(srv, con);
35400         }
35401 -       
35402 +
35403         return HANDLER_FINISHED;
35404  }
35405 -#define PATCH(x) \
35406 -       p->conf.x = s->x;
35407 +
35408  static int scgi_patch_connection(server *srv, connection *con, plugin_data *p) {
35409         size_t i, j;
35410         plugin_config *s = p->config_storage[0];
35411 -       
35412 -       PATCH(exts);
35413 -       PATCH(debug);
35414 -       
35415 +
35416 +       PATCH_OPTION(exts);
35417 +       PATCH_OPTION(debug);
35418 +
35419         /* skip the first, the global context */
35420         for (i = 1; i < srv->config_context->used; i++) {
35421                 data_config *dc = (data_config *)srv->config_context->data[i];
35422                 s = p->config_storage[i];
35423 -               
35424 +
35425                 /* condition didn't match */
35426                 if (!config_check_cond(srv, con, dc)) continue;
35427 -               
35428 +
35429                 /* merge config */
35430                 for (j = 0; j < dc->value->used; j++) {
35431                         data_unset *du = dc->value->data[j];
35432 -                       
35433 +
35434                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.server"))) {
35435 -                               PATCH(exts);
35436 +                               PATCH_OPTION(exts);
35437                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.debug"))) {
35438 -                               PATCH(debug);
35439 +                               PATCH_OPTION(debug);
35440                         }
35441                 }
35442         }
35443 -       
35444 +
35445         return 0;
35446  }
35447 -#undef PATCH
35448 -
35449  
35450  static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
35451         plugin_data *p = p_d;
35452 @@ -2673,30 +2538,30 @@
35453         size_t k;
35454         buffer *fn;
35455         scgi_extension *extension = NULL;
35456 -       
35457 +
35458         /* Possibly, we processed already this request */
35459         if (con->file_started == 1) return HANDLER_GO_ON;
35460 -       
35461 +
35462         fn = uri_path_handler ? con->uri.path : con->physical.path;
35463  
35464         if (buffer_is_empty(fn)) return HANDLER_GO_ON;
35465  
35466         s_len = fn->used - 1;
35467 -       
35468 +
35469         scgi_patch_connection(srv, con, p);
35470  
35471         /* check if extension matches */
35472         for (k = 0; k < p->conf.exts->used; k++) {
35473                 size_t ct_len;
35474 -               
35475 +
35476                 extension = p->conf.exts->exts[k];
35477 -               
35478 +
35479                 if (extension->key->used == 0) continue;
35480 -               
35481 +
35482                 ct_len = extension->key->used - 1;
35483 -               
35484 +
35485                 if (s_len < ct_len) continue;
35486 -               
35487 +
35488                 /* check extension in the form "/scgi_pattern" */
35489                 if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
35490                         break;
35491 @@ -2710,17 +2575,17 @@
35492         if (k == p->conf.exts->used) {
35493                 return HANDLER_GO_ON;
35494         }
35495 -       
35496 +
35497         /* get best server */
35498         for (k = 0, ndx = -1; k < extension->used; k++) {
35499                 scgi_extension_host *host = extension->hosts[k];
35500 -               
35501 +
35502                 /* we should have at least one proc that can do somthing */
35503                 if (host->active_procs == 0) continue;
35504  
35505                 if (used == -1 || host->load < used) {
35506                         used = host->load;
35507 -                       
35508 +
35509                         ndx = k;
35510                 }
35511         }
35512 @@ -2728,12 +2593,12 @@
35513         /* found a server */
35514         if (ndx != -1) {
35515                 scgi_extension_host *host = extension->hosts[ndx];
35516 -               
35517 -               /* 
35518 -                * if check-local is disabled, use the uri.path handler 
35519 -                * 
35520 +
35521 +               /*
35522 +                * if check-local is disabled, use the uri.path handler
35523 +                *
35524                  */
35525 -               
35526 +
35527                 /* init handler-context */
35528                 if (uri_path_handler) {
35529                         if (host->check_local == 0) {
35530 @@ -2741,7 +2606,7 @@
35531                                 char *pathinfo;
35532  
35533                                 hctx = handler_ctx_init();
35534 -                               
35535 +
35536                                 hctx->remote_conn      = con;
35537                                 hctx->plugin_data      = p;
35538                                 hctx->host             = host;
35539 @@ -2749,45 +2614,45 @@
35540  
35541                                 hctx->conf.exts        = p->conf.exts;
35542                                 hctx->conf.debug       = p->conf.debug;
35543 -                               
35544 +
35545                                 con->plugin_ctx[p->id] = hctx;
35546 -                               
35547 +
35548                                 host->load++;
35549 -                               
35550 +
35551                                 con->mode = p->id;
35552  
35553                                 if (con->conf.log_request_handling) {
35554                                         log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_scgi");
35555                                 }
35556  
35557 -                               /* the prefix is the SCRIPT_NAME, 
35558 +                               /* the prefix is the SCRIPT_NAME,
35559                                  * everthing from start to the next slash
35560                                  * this is important for check-local = "disable"
35561 -                                * 
35562 +                                *
35563                                  * if prefix = /admin.fcgi
35564 -                                * 
35565 +                                *
35566                                  * /admin.fcgi/foo/bar
35567 -                                * 
35568 +                                *
35569                                  * SCRIPT_NAME = /admin.fcgi
35570                                  * PATH_INFO   = /foo/bar
35571 -                                * 
35572 +                                *
35573                                  * if prefix = /fcgi-bin/
35574 -                                * 
35575 +                                *
35576                                  * /fcgi-bin/foo/bar
35577 -                                * 
35578 +                                *
35579                                  * SCRIPT_NAME = /fcgi-bin/foo
35580                                  * PATH_INFO   = /bar
35581 -                                * 
35582 +                                *
35583                                  */
35584 -                               
35585 +
35586                                 /* the rewrite is only done for /prefix/? matches */
35587                                 if (extension->key->ptr[0] == '/' &&
35588                                     con->uri.path->used > extension->key->used &&
35589                                     NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
35590 -                                       /* rewrite uri.path and pathinfo */ 
35591 -                                       
35592 +                                       /* rewrite uri.path and pathinfo */
35593 +
35594                                         buffer_copy_string(con->request.pathinfo, pathinfo);
35595 -                                       
35596 +
35597                                         con->uri.path->used -= con->request.pathinfo->used - 1;
35598                                         con->uri.path->ptr[con->uri.path->used - 1] = '\0';
35599                                 }
35600 @@ -2796,21 +2661,21 @@
35601                 } else {
35602                         handler_ctx *hctx;
35603                         hctx = handler_ctx_init();
35604 -                       
35605 +
35606                         hctx->remote_conn      = con;
35607                         hctx->plugin_data      = p;
35608                         hctx->host             = host;
35609                         hctx->proc             = NULL;
35610 -                       
35611 +
35612                         hctx->conf.exts        = p->conf.exts;
35613                         hctx->conf.debug       = p->conf.debug;
35614 -                       
35615 +
35616                         con->plugin_ctx[p->id] = hctx;
35617 -                       
35618 +
35619                         host->load++;
35620 -                       
35621 +
35622                         con->mode = p->id;
35623 -                       
35624 +
35625                         if (con->conf.log_request_handling) {
35626                                 log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
35627                         }
35628 @@ -2821,11 +2686,11 @@
35629                 /* no handler found */
35630                 buffer_reset(con->physical.path);
35631                 con->http_status = 500;
35632 -               
35633 -               log_error_write(srv, __FILE__, __LINE__,  "sb", 
35634 -                               "no fcgi-handler found for:", 
35635 +
35636 +               log_error_write(srv, __FILE__, __LINE__,  "sb",
35637 +                               "no fcgi-handler found for:",
35638                                 fn);
35639 -               
35640 +
35641                 return HANDLER_FINISHED;
35642         }
35643         return HANDLER_GO_ON;
35644 @@ -2844,21 +2709,22 @@
35645  JOBLIST_FUNC(mod_scgi_handle_joblist) {
35646         plugin_data *p = p_d;
35647         handler_ctx *hctx = con->plugin_ctx[p->id];
35648 -       
35649 +
35650         if (hctx == NULL) return HANDLER_GO_ON;
35651  
35652 -       if (hctx->fd != -1) {
35653 +       if (hctx->sock->fd != -1) {
35654                 switch (hctx->state) {
35655 -               case FCGI_STATE_READ:
35656 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
35657 -                       
35658 +               case SCGI_STATE_RESPONSE_HEADER:
35659 +               case SCGI_STATE_RESPONSE_CONTENT:
35660 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
35661 +
35662                         break;
35663 -               case FCGI_STATE_CONNECT:
35664 -               case FCGI_STATE_WRITE:
35665 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
35666 -                       
35667 +               case SCGI_STATE_CONNECT:
35668 +               case SCGI_STATE_WRITE:
35669 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
35670 +
35671                         break;
35672 -               case FCGI_STATE_INIT:
35673 +               case SCGI_STATE_INIT:
35674                         /* at reconnect */
35675                         break;
35676                 default:
35677 @@ -2873,21 +2739,21 @@
35678  
35679  static handler_t scgi_connection_close_callback(server *srv, connection *con, void *p_d) {
35680         plugin_data *p = p_d;
35681 -       
35682 +
35683         return scgi_connection_close(srv, con->plugin_ctx[p->id]);
35684  }
35685  
35686  TRIGGER_FUNC(mod_scgi_handle_trigger) {
35687         plugin_data *p = p_d;
35688         size_t i, j, n;
35689 -       
35690 -       
35691 +
35692 +
35693         /* perhaps we should kill a connect attempt after 10-15 seconds
35694 -        * 
35695 +        *
35696          * currently we wait for the TCP timeout which is on Linux 180 seconds
35697 -        * 
35698 -        * 
35699 -        * 
35700 +        *
35701 +        *
35702 +        *
35703          */
35704  
35705         /* check all childs if they are still up */
35706 @@ -2904,47 +2770,47 @@
35707                         scgi_extension *ex;
35708  
35709                         ex = exts->exts[j];
35710 -                       
35711 +
35712                         for (n = 0; n < ex->used; n++) {
35713 -                               
35714 +
35715                                 scgi_proc *proc;
35716                                 unsigned long sum_load = 0;
35717                                 scgi_extension_host *host;
35718 -                               
35719 +
35720                                 host = ex->hosts[n];
35721 -                               
35722 +
35723                                 scgi_restart_dead_procs(srv, p, host);
35724 -                               
35725 +
35726                                 for (proc = host->first; proc; proc = proc->next) {
35727                                         sum_load += proc->load;
35728                                 }
35729 -                               
35730 +
35731                                 if (host->num_procs &&
35732                                     host->num_procs < host->max_procs &&
35733                                     (sum_load / host->num_procs) > host->max_load_per_proc) {
35734                                         /* overload, spawn new child */
35735                                         scgi_proc *fp = NULL;
35736 -                                       
35737 +
35738                                         if (p->conf.debug) {
35739 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
35740 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
35741                                                                 "overload detected, spawning a new child");
35742                                         }
35743 -                                       
35744 +
35745                                         for (fp = host->unused_procs; fp && fp->pid != 0; fp = fp->next);
35746 -                                       
35747 +
35748                                         if (fp) {
35749                                                 if (fp == host->unused_procs) host->unused_procs = fp->next;
35750 -                                               
35751 +
35752                                                 if (fp->next) fp->next->prev = NULL;
35753 -                                               
35754 +
35755                                                 host->max_id++;
35756                                         } else {
35757                                                 fp = scgi_process_init();
35758                                                 fp->id = host->max_id++;
35759                                         }
35760 -                                       
35761 +
35762                                         host->num_procs++;
35763 -                                       
35764 +
35765                                         if (buffer_is_empty(host->unixsocket)) {
35766                                                 fp->port = host->port + fp->id;
35767                                         } else {
35768 @@ -2952,13 +2818,13 @@
35769                                                 buffer_append_string(fp->socket, "-");
35770                                                 buffer_append_long(fp->socket, fp->id);
35771                                         }
35772 -                                       
35773 +
35774                                         if (scgi_spawn_connection(srv, p, host, fp)) {
35775                                                 log_error_write(srv, __FILE__, __LINE__, "s",
35776                                                                 "ERROR: spawning fcgi failed.");
35777                                                 return HANDLER_ERROR;
35778                                         }
35779 -                                       
35780 +
35781                                         fp->prev = NULL;
35782                                         fp->next = host->first;
35783                                         if (host->first) {
35784 @@ -2966,56 +2832,57 @@
35785                                         }
35786                                         host->first = fp;
35787                                 }
35788 -                               
35789 +
35790                                 for (proc = host->first; proc; proc = proc->next) {
35791                                         if (proc->load != 0) break;
35792                                         if (host->num_procs <= host->min_procs) break;
35793                                         if (proc->pid == 0) continue;
35794 -                                       
35795 +#ifndef _WIN32
35796                                         if (srv->cur_ts - proc->last_used > host->idle_timeout) {
35797                                                 /* a proc is idling for a long time now,
35798                                                  * terminated it */
35799 -                                               
35800 +
35801                                                 if (p->conf.debug) {
35802 -                                                       log_error_write(srv, __FILE__, __LINE__, "ssbsd", 
35803 -                                                                       "idle-timeout reached, terminating child:", 
35804 -                                                                       "socket:", proc->socket, 
35805 +                                                       log_error_write(srv, __FILE__, __LINE__, "ssbsd",
35806 +                                                                       "idle-timeout reached, terminating child:",
35807 +                                                                       "socket:", proc->socket,
35808                                                                         "pid", proc->pid);
35809                                                 }
35810 -                                               
35811 -                                               
35812 +
35813 +
35814                                                 if (proc->next) proc->next->prev = proc->prev;
35815                                                 if (proc->prev) proc->prev->next = proc->next;
35816 -                                               
35817 +
35818                                                 if (proc->prev == NULL) host->first = proc->next;
35819 -                                               
35820 +
35821                                                 proc->prev = NULL;
35822                                                 proc->next = host->unused_procs;
35823 -                                               
35824 +
35825                                                 if (host->unused_procs) host->unused_procs->prev = proc;
35826                                                 host->unused_procs = proc;
35827 -                                               
35828 +
35829                                                 kill(proc->pid, SIGTERM);
35830 -                                               
35831 +
35832                                                 proc->state = PROC_STATE_KILLED;
35833 -                                               
35834 -                                               log_error_write(srv, __FILE__, __LINE__, "ssbsd", 
35835 -                                                                       "killed:", 
35836 -                                                                       "socket:", proc->socket, 
35837 +
35838 +                                               log_error_write(srv, __FILE__, __LINE__, "ssbsd",
35839 +                                                                       "killed:",
35840 +                                                                       "socket:", proc->socket,
35841                                                                         "pid", proc->pid);
35842 -                                               
35843 +
35844                                                 host->num_procs--;
35845 -                                               
35846 +
35847                                                 /* proc is now in unused, let the next second handle the next process */
35848                                                 break;
35849 -                                       }       
35850 +                                       }
35851 +#endif
35852                                 }
35853 -                               
35854 +
35855                                 for (proc = host->unused_procs; proc; proc = proc->next) {
35856                                         int status;
35857 -                                       
35858 +
35859                                         if (proc->pid == 0) continue;
35860 -                                       
35861 +#ifndef _WIN32
35862                                         switch (waitpid(proc->pid, &status, WNOHANG)) {
35863                                         case 0:
35864                                                 /* child still running after timeout, good */
35865 @@ -3023,10 +2890,10 @@
35866                                         case -1:
35867                                                 if (errno != EINTR) {
35868                                                         /* no PID found ? should never happen */
35869 -                                                       log_error_write(srv, __FILE__, __LINE__, "sddss", 
35870 +                                                       log_error_write(srv, __FILE__, __LINE__, "sddss",
35871                                                                         "pid ", proc->pid, proc->state,
35872                                                                         "not found:", strerror(errno));
35873 -                                                       
35874 +
35875  #if 0
35876                                                         if (errno == ECHILD) {
35877                                                                 /* someone else has cleaned up for us */
35878 @@ -3040,25 +2907,26 @@
35879                                                 /* the child should not terminate at all */
35880                                                 if (WIFEXITED(status)) {
35881                                                         if (proc->state != PROC_STATE_KILLED) {
35882 -                                                               log_error_write(srv, __FILE__, __LINE__, "sdb", 
35883 -                                                                               "child exited:", 
35884 +                                                               log_error_write(srv, __FILE__, __LINE__, "sdb",
35885 +                                                                               "child exited:",
35886                                                                                 WEXITSTATUS(status), proc->socket);
35887                                                         }
35888                                                 } else if (WIFSIGNALED(status)) {
35889                                                         if (WTERMSIG(status) != SIGTERM) {
35890 -                                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
35891 -                                                                               "child signaled:", 
35892 +                                                               log_error_write(srv, __FILE__, __LINE__, "sd",
35893 +                                                                               "child signaled:",
35894                                                                                 WTERMSIG(status));
35895                                                         }
35896                                                 } else {
35897 -                                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
35898 -                                                                       "child died somehow:", 
35899 +                                                       log_error_write(srv, __FILE__, __LINE__, "sd",
35900 +                                                                       "child died somehow:",
35901                                                                         status);
35902                                                 }
35903                                                 proc->pid = 0;
35904                                                 proc->state = PROC_STATE_UNSET;
35905                                                 host->max_id--;
35906                                         }
35907 +#endif
35908                                 }
35909                         }
35910                 }
35911 @@ -3082,8 +2950,8 @@
35912         p->handle_subrequest       = mod_scgi_handle_subrequest;
35913         p->handle_joblist          = mod_scgi_handle_joblist;
35914         p->handle_trigger          = mod_scgi_handle_trigger;
35915 -       
35916 +
35917         p->data         = NULL;
35918 -       
35919 +
35920         return 0;
35921  }
35922 --- ../lighttpd-1.4.11/src/mod_secure_download.c        2005-12-14 14:37:29.000000000 +0200
35923 +++ lighttpd-1.4.12/src/mod_secure_download.c   2006-07-16 00:26:03.000000000 +0300
35924 @@ -25,7 +25,7 @@
35925  #ifdef USE_OPENSSL
35926  #define IN const
35927  #else
35928 -#define IN 
35929 +#define IN
35930  #endif
35931  #define OUT
35932  
35933 @@ -36,28 +36,28 @@
35934         buffer *doc_root;
35935         buffer *secret;
35936         buffer *uri_prefix;
35937 -       
35938 +
35939         unsigned short timeout;
35940  } plugin_config;
35941  
35942  typedef struct {
35943         PLUGIN_DATA;
35944 -       
35945 +
35946         buffer *md5;
35947 -       
35948 +
35949         plugin_config **config_storage;
35950 -       
35951 -       plugin_config conf; 
35952 +
35953 +       plugin_config conf;
35954  } plugin_data;
35955  
35956  /* init the plugin data */
35957  INIT_FUNC(mod_secdownload_init) {
35958         plugin_data *p;
35959 -       
35960 +
35961         p = calloc(1, sizeof(*p));
35962 -       
35963 +
35964         p->md5 = buffer_init();
35965 -       
35966 +
35967         return p;
35968  }
35969  
35970 @@ -65,27 +65,27 @@
35971  FREE_FUNC(mod_secdownload_free) {
35972         plugin_data *p = p_d;
35973         UNUSED(srv);
35974 -       
35975 +
35976         if (!p) return HANDLER_GO_ON;
35977 -       
35978 +
35979         if (p->config_storage) {
35980                 size_t i;
35981                 for (i = 0; i < srv->config_context->used; i++) {
35982                         plugin_config *s = p->config_storage[i];
35983 -                       
35984 +
35985                         buffer_free(s->secret);
35986                         buffer_free(s->doc_root);
35987                         buffer_free(s->uri_prefix);
35988 -                       
35989 +
35990                         free(s);
35991                 }
35992                 free(p->config_storage);
35993         }
35994 -       
35995 +
35996         buffer_free(p->md5);
35997 -       
35998 +
35999         free(p);
36000 -       
36001 +
36002         return HANDLER_GO_ON;
36003  }
36004  
36005 @@ -94,107 +94,103 @@
36006  SETDEFAULTS_FUNC(mod_secdownload_set_defaults) {
36007         plugin_data *p = p_d;
36008         size_t i = 0;
36009 -       
36010 -       config_values_t cv[] = { 
36011 +
36012 +       config_values_t cv[] = {
36013                 { "secdownload.secret",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
36014                 { "secdownload.document-root",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
36015                 { "secdownload.uri-prefix",        NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
36016                 { "secdownload.timeout",           NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 3 */
36017                 { NULL,                            NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
36018         };
36019 -       
36020 +
36021         if (!p) return HANDLER_ERROR;
36022 -       
36023 +
36024         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
36025 -       
36026 +
36027         for (i = 0; i < srv->config_context->used; i++) {
36028                 plugin_config *s;
36029 -               
36030 +
36031                 s = calloc(1, sizeof(plugin_config));
36032                 s->secret        = buffer_init();
36033                 s->doc_root      = buffer_init();
36034                 s->uri_prefix    = buffer_init();
36035                 s->timeout       = 60;
36036 -               
36037 +
36038                 cv[0].destination = s->secret;
36039                 cv[1].destination = s->doc_root;
36040                 cv[2].destination = s->uri_prefix;
36041                 cv[3].destination = &(s->timeout);
36042 -               
36043 +
36044                 p->config_storage[i] = s;
36045 -       
36046 +
36047                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
36048                         return HANDLER_ERROR;
36049                 }
36050         }
36051 -       
36052 +
36053         return HANDLER_GO_ON;
36054  }
36055  
36056  /**
36057   * checks if the supplied string is a MD5 string
36058 - * 
36059 + *
36060   * @param str a possible MD5 string
36061   * @return if the supplied string is a valid MD5 string 1 is returned otherwise 0
36062   */
36063  
36064  int is_hex_len(const char *str, size_t len) {
36065         size_t i;
36066 -       
36067 +
36068         if (NULL == str) return 0;
36069 -       
36070 +
36071         for (i = 0; i < len && *str; i++, str++) {
36072                 /* illegal characters */
36073                 if (!((*str >= '0' && *str <= '9') ||
36074                       (*str >= 'a' && *str <= 'f') ||
36075 -                     (*str >= 'A' && *str <= 'F')) 
36076 +                     (*str >= 'A' && *str <= 'F'))
36077                     ) {
36078                         return 0;
36079                 }
36080         }
36081 -       
36082 +
36083         return i == len;
36084  }
36085  
36086 -#define PATCH(x) \
36087 -       p->conf.x = s->x;
36088  static int mod_secdownload_patch_connection(server *srv, connection *con, plugin_data *p) {
36089         size_t i, j;
36090         plugin_config *s = p->config_storage[0];
36091 -       
36092 -       PATCH(secret);
36093 -       PATCH(doc_root);
36094 -       PATCH(uri_prefix);
36095 -       PATCH(timeout);
36096 -       
36097 +
36098 +       PATCH_OPTION(secret);
36099 +       PATCH_OPTION(doc_root);
36100 +       PATCH_OPTION(uri_prefix);
36101 +       PATCH_OPTION(timeout);
36102 +
36103         /* skip the first, the global context */
36104         for (i = 1; i < srv->config_context->used; i++) {
36105                 data_config *dc = (data_config *)srv->config_context->data[i];
36106                 s = p->config_storage[i];
36107 -               
36108 +
36109                 /* condition didn't match */
36110                 if (!config_check_cond(srv, con, dc)) continue;
36111 -               
36112 +
36113                 /* merge config */
36114                 for (j = 0; j < dc->value->used; j++) {
36115                         data_unset *du = dc->value->data[j];
36116 -                       
36117 +
36118                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.secret"))) {
36119 -                               PATCH(secret);
36120 +                               PATCH_OPTION(secret);
36121                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.document-root"))) {
36122 -                               PATCH(doc_root);
36123 +                               PATCH_OPTION(doc_root);
36124                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.uri-prefix"))) {
36125 -                               PATCH(uri_prefix);
36126 +                               PATCH_OPTION(uri_prefix);
36127                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.timeout"))) {
36128 -                               PATCH(timeout);
36129 +                               PATCH_OPTION(timeout);
36130                         }
36131                 }
36132         }
36133 -       
36134 +
36135         return 0;
36136  }
36137 -#undef PATCH
36138 -
36139  
36140  URIHANDLER_FUNC(mod_secdownload_uri_handler) {
36141         plugin_data *p = p_d;
36142 @@ -203,88 +199,88 @@
36143         const char *rel_uri, *ts_str, *md5_str;
36144         time_t ts = 0;
36145         size_t i;
36146 -       
36147 +
36148         if (con->uri.path->used == 0) return HANDLER_GO_ON;
36149 -       
36150 +
36151         mod_secdownload_patch_connection(srv, con, p);
36152  
36153         if (buffer_is_empty(p->conf.uri_prefix)) return HANDLER_GO_ON;
36154 -       
36155 +
36156         if (buffer_is_empty(p->conf.secret)) {
36157                 log_error_write(srv, __FILE__, __LINE__, "s",
36158                                 "secdownload.secret has to be set");
36159                 return HANDLER_ERROR;
36160         }
36161 -       
36162 +
36163         if (buffer_is_empty(p->conf.doc_root)) {
36164                 log_error_write(srv, __FILE__, __LINE__, "s",
36165                                 "secdownload.document-root has to be set");
36166                 return HANDLER_ERROR;
36167         }
36168 -       
36169 -       /* 
36170 +
36171 +       /*
36172          *  /<uri-prefix>[a-f0-9]{32}/[a-f0-9]{8}/<rel-path>
36173          */
36174 -       
36175 +
36176         if (0 != strncmp(con->uri.path->ptr, p->conf.uri_prefix->ptr, p->conf.uri_prefix->used - 1)) return HANDLER_GO_ON;
36177 -       
36178 +
36179         md5_str = con->uri.path->ptr + p->conf.uri_prefix->used - 1;
36180 -       
36181 +
36182         if (!is_hex_len(md5_str, 32)) return HANDLER_GO_ON;
36183         if (*(md5_str + 32) != '/') return HANDLER_GO_ON;
36184 -       
36185 +
36186         ts_str = md5_str + 32 + 1;
36187 -       
36188 +
36189         if (!is_hex_len(ts_str, 8)) return HANDLER_GO_ON;
36190         if (*(ts_str + 8) != '/') return HANDLER_GO_ON;
36191 -       
36192 +
36193         for (i = 0; i < 8; i++) {
36194                 ts = (ts << 4) + hex2int(*(ts_str + i));
36195         }
36196 -       
36197 +
36198         /* timed-out */
36199 -       if (srv->cur_ts - ts > p->conf.timeout || 
36200 +       if (srv->cur_ts - ts > p->conf.timeout ||
36201             srv->cur_ts - ts < -p->conf.timeout) {
36202                 con->http_status = 408;
36203 -               
36204 +
36205                 return HANDLER_FINISHED;
36206         }
36207 -       
36208 +
36209         rel_uri = ts_str + 8;
36210 -       
36211 -       /* checking MD5 
36212 -        * 
36213 +
36214 +       /* checking MD5
36215 +        *
36216          * <secret><rel-path><timestamp-hex>
36217          */
36218 -       
36219 +
36220         buffer_copy_string_buffer(p->md5, p->conf.secret);
36221         buffer_append_string(p->md5, rel_uri);
36222         buffer_append_string_len(p->md5, ts_str, 8);
36223 -       
36224 +
36225         MD5_Init(&Md5Ctx);
36226         MD5_Update(&Md5Ctx, (unsigned char *)p->md5->ptr, p->md5->used - 1);
36227         MD5_Final(HA1, &Md5Ctx);
36228 -       
36229 +
36230         buffer_copy_string_hex(p->md5, (char *)HA1, 16);
36231 -       
36232 +
36233         if (0 != strncmp(md5_str, p->md5->ptr, 32)) {
36234                 con->http_status = 403;
36235 -               
36236 -               log_error_write(srv, __FILE__, __LINE__, "sss", 
36237 +
36238 +               log_error_write(srv, __FILE__, __LINE__, "sss",
36239                                 "md5 invalid:",
36240                                 md5_str, p->md5->ptr);
36241 -               
36242 +
36243                 return HANDLER_FINISHED;
36244         }
36245 -       
36246 +
36247         /* starting with the last / we should have relative-path to the docroot
36248          */
36249 -       
36250 +
36251         buffer_copy_string_buffer(con->physical.doc_root, p->conf.doc_root);
36252         buffer_copy_string(con->physical.rel_path, rel_uri);
36253         buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
36254         buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
36255 -       
36256 +
36257         return HANDLER_GO_ON;
36258  }
36259  
36260 @@ -293,13 +289,13 @@
36261  int mod_secdownload_plugin_init(plugin *p) {
36262         p->version     = LIGHTTPD_VERSION_ID;
36263         p->name        = buffer_init_string("secdownload");
36264 -       
36265 +
36266         p->init        = mod_secdownload_init;
36267         p->handle_physical  = mod_secdownload_uri_handler;
36268         p->set_defaults  = mod_secdownload_set_defaults;
36269         p->cleanup     = mod_secdownload_free;
36270 -       
36271 +
36272         p->data        = NULL;
36273 -       
36274 +
36275         return 0;
36276  }
36277 --- ../lighttpd-1.4.11/src/mod_setenv.c 2006-01-14 20:33:12.000000000 +0200
36278 +++ lighttpd-1.4.12/src/mod_setenv.c    2006-07-16 00:26:04.000000000 +0300
36279 @@ -18,25 +18,25 @@
36280  typedef struct {
36281         array *request_header;
36282         array *response_header;
36283 -       
36284 +
36285         array *environment;
36286  } plugin_config;
36287  
36288  typedef struct {
36289         PLUGIN_DATA;
36290 -       
36291 +
36292         plugin_config **config_storage;
36293 -       
36294 -       plugin_config conf; 
36295 +
36296 +       plugin_config conf;
36297  } plugin_data;
36298  
36299  static handler_ctx * handler_ctx_init() {
36300         handler_ctx * hctx;
36301 -       
36302 +
36303         hctx = calloc(1, sizeof(*hctx));
36304 -       
36305 +
36306         hctx->handled = 0;
36307 -       
36308 +
36309         return hctx;
36310  }
36311  
36312 @@ -48,36 +48,36 @@
36313  /* init the plugin data */
36314  INIT_FUNC(mod_setenv_init) {
36315         plugin_data *p;
36316 -       
36317 +
36318         p = calloc(1, sizeof(*p));
36319 -       
36320 +
36321         return p;
36322  }
36323  
36324  /* detroy the plugin data */
36325  FREE_FUNC(mod_setenv_free) {
36326         plugin_data *p = p_d;
36327 -       
36328 +
36329         UNUSED(srv);
36330  
36331         if (!p) return HANDLER_GO_ON;
36332 -       
36333 +
36334         if (p->config_storage) {
36335                 size_t i;
36336                 for (i = 0; i < srv->config_context->used; i++) {
36337                         plugin_config *s = p->config_storage[i];
36338 -                       
36339 +
36340                         array_free(s->request_header);
36341                         array_free(s->response_header);
36342                         array_free(s->environment);
36343 -                       
36344 +
36345                         free(s);
36346                 }
36347                 free(p->config_storage);
36348         }
36349 -       
36350 +
36351         free(p);
36352 -       
36353 +
36354         return HANDLER_GO_ON;
36355  }
36356  
36357 @@ -86,86 +86,83 @@
36358  SETDEFAULTS_FUNC(mod_setenv_set_defaults) {
36359         plugin_data *p = p_d;
36360         size_t i = 0;
36361 -       
36362 -       config_values_t cv[] = { 
36363 +
36364 +       config_values_t cv[] = {
36365                 { "setenv.add-request-header",  NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
36366                 { "setenv.add-response-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
36367                 { "setenv.add-environment",     NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
36368                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
36369         };
36370 -       
36371 +
36372         if (!p) return HANDLER_ERROR;
36373 -       
36374 +
36375         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
36376 -       
36377 +
36378         for (i = 0; i < srv->config_context->used; i++) {
36379                 plugin_config *s;
36380 -               
36381 +
36382                 s = calloc(1, sizeof(plugin_config));
36383                 s->request_header   = array_init();
36384                 s->response_header  = array_init();
36385                 s->environment      = array_init();
36386 -               
36387 +
36388                 cv[0].destination = s->request_header;
36389                 cv[1].destination = s->response_header;
36390                 cv[2].destination = s->environment;
36391 -               
36392 +
36393                 p->config_storage[i] = s;
36394 -       
36395 +
36396                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
36397                         return HANDLER_ERROR;
36398                 }
36399         }
36400 -       
36401 +
36402         return HANDLER_GO_ON;
36403  }
36404  
36405 -#define PATCH(x) \
36406 -       p->conf.x = s->x;
36407  static int mod_setenv_patch_connection(server *srv, connection *con, plugin_data *p) {
36408         size_t i, j;
36409         plugin_config *s = p->config_storage[0];
36410 -       
36411 -       PATCH(request_header);
36412 -       PATCH(response_header);
36413 -       PATCH(environment);
36414 -       
36415 +
36416 +       PATCH_OPTION(request_header);
36417 +       PATCH_OPTION(response_header);
36418 +       PATCH_OPTION(environment);
36419 +
36420         /* skip the first, the global context */
36421         for (i = 1; i < srv->config_context->used; i++) {
36422                 data_config *dc = (data_config *)srv->config_context->data[i];
36423                 s = p->config_storage[i];
36424 -               
36425 +
36426                 /* condition didn't match */
36427                 if (!config_check_cond(srv, con, dc)) continue;
36428 -               
36429 +
36430                 /* merge config */
36431                 for (j = 0; j < dc->value->used; j++) {
36432                         data_unset *du = dc->value->data[j];
36433 -                       
36434 +
36435                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-request-header"))) {
36436 -                               PATCH(request_header);
36437 +                               PATCH_OPTION(request_header);
36438                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-response-header"))) {
36439 -                               PATCH(response_header);
36440 +                               PATCH_OPTION(response_header);
36441                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-environment"))) {
36442 -                               PATCH(environment);
36443 +                               PATCH_OPTION(environment);
36444                         }
36445                 }
36446         }
36447 -       
36448 +
36449         return 0;
36450  }
36451 -#undef PATCH
36452  
36453  URIHANDLER_FUNC(mod_setenv_uri_handler) {
36454         plugin_data *p = p_d;
36455         size_t k;
36456         handler_ctx *hctx;
36457 -       
36458 +
36459         if (con->plugin_ctx[p->id]) {
36460                 hctx = con->plugin_ctx[p->id];
36461         } else {
36462                 hctx = handler_ctx_init();
36463 -                               
36464 +
36465                 con->plugin_ctx[p->id] = hctx;
36466         }
36467  
36468 @@ -180,52 +177,52 @@
36469         for (k = 0; k < p->conf.request_header->used; k++) {
36470                 data_string *ds = (data_string *)p->conf.request_header->data[k];
36471                 data_string *ds_dst;
36472 -               
36473 +
36474                 if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
36475                         ds_dst = data_string_init();
36476                 }
36477 -               
36478 +
36479                 buffer_copy_string_buffer(ds_dst->key, ds->key);
36480                 buffer_copy_string_buffer(ds_dst->value, ds->value);
36481 -               
36482 +
36483                 array_insert_unique(con->request.headers, (data_unset *)ds_dst);
36484         }
36485 -       
36486 +
36487         for (k = 0; k < p->conf.environment->used; k++) {
36488                 data_string *ds = (data_string *)p->conf.environment->data[k];
36489                 data_string *ds_dst;
36490 -               
36491 +
36492                 if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
36493                         ds_dst = data_string_init();
36494                 }
36495 -               
36496 +
36497                 buffer_copy_string_buffer(ds_dst->key, ds->key);
36498                 buffer_copy_string_buffer(ds_dst->value, ds->value);
36499 -               
36500 +
36501                 array_insert_unique(con->environment, (data_unset *)ds_dst);
36502         }
36503 -       
36504 +
36505         for (k = 0; k < p->conf.response_header->used; k++) {
36506                 data_string *ds = (data_string *)p->conf.response_header->data[k];
36507 -               
36508 +
36509                 response_header_insert(srv, con, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
36510         }
36511 -       
36512 +
36513         /* not found */
36514         return HANDLER_GO_ON;
36515  }
36516  
36517  REQUESTDONE_FUNC(mod_setenv_reset) {
36518         plugin_data *p = p_d;
36519 -       
36520 +
36521         UNUSED(srv);
36522 -       
36523 +
36524         if (con->plugin_ctx[p->id]) {
36525                 handler_ctx_free(con->plugin_ctx[p->id]);
36526                 con->plugin_ctx[p->id] = NULL;
36527         }
36528  
36529 -       return HANDLER_GO_ON;   
36530 +       return HANDLER_GO_ON;
36531  }
36532  
36533  /* this function is called at dlopen() time and inits the callbacks */
36534 @@ -233,15 +230,15 @@
36535  int mod_setenv_plugin_init(plugin *p) {
36536         p->version     = LIGHTTPD_VERSION_ID;
36537         p->name        = buffer_init_string("setenv");
36538 -       
36539 +
36540         p->init        = mod_setenv_init;
36541         p->handle_uri_clean  = mod_setenv_uri_handler;
36542         p->set_defaults  = mod_setenv_set_defaults;
36543         p->cleanup     = mod_setenv_free;
36544 -       
36545 +
36546         p->handle_request_done  = mod_setenv_reset;
36547  
36548         p->data        = NULL;
36549 -       
36550 +
36551         return 0;
36552  }
36553 --- ../lighttpd-1.4.11/src/mod_simple_vhost.c   2005-11-18 15:16:13.000000000 +0200
36554 +++ lighttpd-1.4.12/src/mod_simple_vhost.c      2006-07-16 00:26:04.000000000 +0300
36555 @@ -10,6 +10,8 @@
36556  
36557  #include "plugin.h"
36558  
36559 +#include "sys-files.h"
36560 +
36561  #ifdef HAVE_CONFIG_H
36562  #include "config.h"
36563  #endif
36564 @@ -18,7 +20,7 @@
36565         buffer *server_root;
36566         buffer *default_host;
36567         buffer *document_root;
36568 -       
36569 +
36570         buffer *docroot_cache_key;
36571         buffer *docroot_cache_value;
36572         buffer *docroot_cache_servername;
36573 @@ -28,138 +30,138 @@
36574  
36575  typedef struct {
36576         PLUGIN_DATA;
36577 -       
36578 +
36579         buffer *doc_root;
36580 -       
36581 +
36582         plugin_config **config_storage;
36583 -       plugin_config conf; 
36584 +       plugin_config conf;
36585  } plugin_data;
36586  
36587  INIT_FUNC(mod_simple_vhost_init) {
36588         plugin_data *p;
36589 -       
36590 +
36591         p = calloc(1, sizeof(*p));
36592 -       
36593 +
36594         p->doc_root = buffer_init();
36595 -       
36596 +
36597         return p;
36598  }
36599  
36600  FREE_FUNC(mod_simple_vhost_free) {
36601         plugin_data *p = p_d;
36602 -       
36603 +
36604         UNUSED(srv);
36605  
36606         if (!p) return HANDLER_GO_ON;
36607 -       
36608 +
36609         if (p->config_storage) {
36610                 size_t i;
36611                 for (i = 0; i < srv->config_context->used; i++) {
36612                         plugin_config *s = p->config_storage[i];
36613 -                       
36614 +
36615                         buffer_free(s->document_root);
36616                         buffer_free(s->default_host);
36617                         buffer_free(s->server_root);
36618 -                       
36619 +
36620                         buffer_free(s->docroot_cache_key);
36621                         buffer_free(s->docroot_cache_value);
36622                         buffer_free(s->docroot_cache_servername);
36623 -                       
36624 +
36625                         free(s);
36626                 }
36627 -       
36628 +
36629                 free(p->config_storage);
36630         }
36631 -       
36632 +
36633         buffer_free(p->doc_root);
36634 -       
36635 +
36636         free(p);
36637 -       
36638 +
36639         return HANDLER_GO_ON;
36640  }
36641  
36642  SETDEFAULTS_FUNC(mod_simple_vhost_set_defaults) {
36643         plugin_data *p = p_d;
36644         size_t i;
36645 -       
36646 -       config_values_t cv[] = { 
36647 +
36648 +       config_values_t cv[] = {
36649                 { "simple-vhost.server-root",       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
36650                 { "simple-vhost.default-host",      NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
36651                 { "simple-vhost.document-root",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
36652                 { "simple-vhost.debug",             NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
36653                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
36654         };
36655 -       
36656 +
36657         if (!p) return HANDLER_ERROR;
36658 -       
36659 +
36660         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
36661 -       
36662 +
36663         for (i = 0; i < srv->config_context->used; i++) {
36664                 plugin_config *s;
36665 -               
36666 +
36667                 s = calloc(1, sizeof(plugin_config));
36668 -               
36669 +
36670                 s->server_root = buffer_init();
36671                 s->default_host = buffer_init();
36672                 s->document_root = buffer_init();
36673 -               
36674 +
36675                 s->docroot_cache_key = buffer_init();
36676                 s->docroot_cache_value = buffer_init();
36677                 s->docroot_cache_servername = buffer_init();
36678  
36679                 s->debug = 0;
36680 -               
36681 +
36682                 cv[0].destination = s->server_root;
36683                 cv[1].destination = s->default_host;
36684                 cv[2].destination = s->document_root;
36685                 cv[3].destination = &(s->debug);
36686 -               
36687 -               
36688 +
36689 +
36690                 p->config_storage[i] = s;
36691 -               
36692 +
36693                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
36694                         return HANDLER_ERROR;
36695                 }
36696         }
36697 -       
36698 +
36699         return HANDLER_GO_ON;
36700  }
36701  
36702  static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *out, buffer *host) {
36703         stat_cache_entry *sce = NULL;
36704 -       
36705 +
36706         buffer_prepare_copy(out, 128);
36707  
36708         if (p->conf.server_root->used) {
36709                 buffer_copy_string_buffer(out, p->conf.server_root);
36710 -               
36711 +
36712                 if (host->used) {
36713                         /* a hostname has to start with a alpha-numerical character
36714                          * and must not contain a slash "/"
36715                          */
36716                         char *dp;
36717 -                       
36718 -                       BUFFER_APPEND_SLASH(out);
36719 -                       
36720 +
36721 +                       PATHNAME_APPEND_SLASH(out);
36722 +
36723                         if (NULL == (dp = strchr(host->ptr, ':'))) {
36724                                 buffer_append_string_buffer(out, host);
36725                         } else {
36726                                 buffer_append_string_len(out, host->ptr, dp - host->ptr);
36727                         }
36728                 }
36729 -               BUFFER_APPEND_SLASH(out);
36730 -               
36731 +               PATHNAME_APPEND_SLASH(out);
36732 +
36733                 if (p->conf.document_root->used > 2 && p->conf.document_root->ptr[0] == '/') {
36734                         buffer_append_string_len(out, p->conf.document_root->ptr + 1, p->conf.document_root->used - 2);
36735                 } else {
36736                         buffer_append_string_buffer(out, p->conf.document_root);
36737 -                       BUFFER_APPEND_SLASH(out);
36738 +                       PATHNAME_APPEND_SLASH(out);
36739                 }
36740         } else {
36741                 buffer_copy_string_buffer(out, con->conf.document_root);
36742 -               BUFFER_APPEND_SLASH(out);
36743 +               PATHNAME_APPEND_SLASH(out);
36744         }
36745 -       
36746 +
36747         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, out, &sce)) {
36748                 if (p->conf.debug) {
36749                         log_error_write(srv, __FILE__, __LINE__, "sb",
36750 @@ -169,57 +171,53 @@
36751         } else if (!S_ISDIR(sce->st.st_mode)) {
36752                 return -1;
36753         }
36754 -       
36755 +
36756         return 0;
36757  }
36758  
36759 -
36760 -#define PATCH(x) \
36761 -       p->conf.x = s->x;
36762  static int mod_simple_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
36763         size_t i, j;
36764         plugin_config *s = p->config_storage[0];
36765 -       
36766 -       PATCH(server_root);
36767 -       PATCH(default_host);
36768 -       PATCH(document_root);
36769 -       
36770 -       PATCH(docroot_cache_key);
36771 -       PATCH(docroot_cache_value);
36772 -       PATCH(docroot_cache_servername);
36773  
36774 -       PATCH(debug);
36775 -       
36776 +       PATCH_OPTION(server_root);
36777 +       PATCH_OPTION(default_host);
36778 +       PATCH_OPTION(document_root);
36779 +
36780 +       PATCH_OPTION(docroot_cache_key);
36781 +       PATCH_OPTION(docroot_cache_value);
36782 +       PATCH_OPTION(docroot_cache_servername);
36783 +
36784 +       PATCH_OPTION(debug);
36785 +
36786         /* skip the first, the global context */
36787         for (i = 1; i < srv->config_context->used; i++) {
36788                 data_config *dc = (data_config *)srv->config_context->data[i];
36789                 s = p->config_storage[i];
36790 -               
36791 +
36792                 /* condition didn't match */
36793                 if (!config_check_cond(srv, con, dc)) continue;
36794 -               
36795 +
36796                 /* merge config */
36797                 for (j = 0; j < dc->value->used; j++) {
36798                         data_unset *du = dc->value->data[j];
36799 -                       
36800 +
36801                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.server-root"))) {
36802 -                               PATCH(server_root);
36803 -                               PATCH(docroot_cache_key);
36804 -                               PATCH(docroot_cache_value);
36805 -                               PATCH(docroot_cache_servername);
36806 +                               PATCH_OPTION(server_root);
36807 +                               PATCH_OPTION(docroot_cache_key);
36808 +                               PATCH_OPTION(docroot_cache_value);
36809 +                               PATCH_OPTION(docroot_cache_servername);
36810                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.default-host"))) {
36811 -                               PATCH(default_host);
36812 +                               PATCH_OPTION(default_host);
36813                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.document-root"))) {
36814 -                               PATCH(document_root);
36815 +                               PATCH_OPTION(document_root);
36816                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.debug"))) {
36817 -                               PATCH(debug);
36818 +                               PATCH_OPTION(debug);
36819                         }
36820                 }
36821         }
36822 -       
36823 +
36824         return 0;
36825  }
36826 -#undef PATCH
36827  
36828  static handler_t mod_simple_vhost_docroot(server *srv, connection *con, void *p_data) {
36829         plugin_data *p = p_data;
36830 @@ -227,12 +225,12 @@
36831         /*
36832          * cache the last successfull translation from hostname (authority) to docroot
36833          * - this saves us a stat() call
36834 -        * 
36835 +        *
36836          */
36837 -       
36838 +
36839         mod_simple_vhost_patch_connection(srv, con, p);
36840 -       
36841 -       if (p->conf.docroot_cache_key->used && 
36842 +
36843 +       if (p->conf.docroot_cache_key->used &&
36844             con->uri.authority->used &&
36845             buffer_is_equal(p->conf.docroot_cache_key, con->uri.authority)) {
36846                 /* cache hit */
36847 @@ -243,8 +241,8 @@
36848                 if ((con->uri.authority->used == 0) ||
36849                     build_doc_root(srv, con, p, p->doc_root, con->uri.authority)) {
36850                         /* not found, fallback the default-host */
36851 -                       if (build_doc_root(srv, con, p, 
36852 -                                          p->doc_root, 
36853 +                       if (build_doc_root(srv, con, p,
36854 +                                          p->doc_root,
36855                                            p->conf.default_host)) {
36856                                 return HANDLER_GO_ON;
36857                         } else {
36858 @@ -253,15 +251,15 @@
36859                 } else {
36860                         buffer_copy_string_buffer(con->server_name, con->uri.authority);
36861                 }
36862 -               
36863 +
36864                 /* copy to cache */
36865                 buffer_copy_string_buffer(p->conf.docroot_cache_key,        con->uri.authority);
36866                 buffer_copy_string_buffer(p->conf.docroot_cache_value,      p->doc_root);
36867                 buffer_copy_string_buffer(p->conf.docroot_cache_servername, con->server_name);
36868 -               
36869 +
36870                 buffer_copy_string_buffer(con->physical.doc_root, p->doc_root);
36871         }
36872 -       
36873 +
36874         return HANDLER_GO_ON;
36875  }
36876  
36877 @@ -269,13 +267,13 @@
36878  int mod_simple_vhost_plugin_init(plugin *p) {
36879         p->version     = LIGHTTPD_VERSION_ID;
36880         p->name        = buffer_init_string("simple_vhost");
36881 -       
36882 +
36883         p->init        = mod_simple_vhost_init;
36884         p->set_defaults = mod_simple_vhost_set_defaults;
36885         p->handle_docroot  = mod_simple_vhost_docroot;
36886         p->cleanup     = mod_simple_vhost_free;
36887 -       
36888 +
36889         p->data        = NULL;
36890 -       
36891 +
36892         return 0;
36893  }
36894 --- ../lighttpd-1.4.11/src/mod_skeleton.c       2005-10-02 18:30:51.000000000 +0300
36895 +++ lighttpd-1.4.12/src/mod_skeleton.c  2006-07-16 00:26:03.000000000 +0300
36896 @@ -14,13 +14,13 @@
36897  
36898  /**
36899   * this is a skeleton for a lighttpd plugin
36900 - * 
36901 + *
36902   * just replaces every occurance of 'skeleton' by your plugin name
36903 - * 
36904 + *
36905   * e.g. in vim:
36906 - * 
36907 + *
36908   *   :%s/skeleton/myhandler/
36909 - * 
36910 + *
36911   */
36912  
36913  
36914 @@ -33,12 +33,12 @@
36915  
36916  typedef struct {
36917         PLUGIN_DATA;
36918 -       
36919 +
36920         buffer *match_buf;
36921 -       
36922 +
36923         plugin_config **config_storage;
36924 -       
36925 -       plugin_config conf; 
36926 +
36927 +       plugin_config conf;
36928  } plugin_data;
36929  
36930  typedef struct {
36931 @@ -47,36 +47,36 @@
36932  
36933  static handler_ctx * handler_ctx_init() {
36934         handler_ctx * hctx;
36935 -       
36936 +
36937         hctx = calloc(1, sizeof(*hctx));
36938 -       
36939 +
36940         return hctx;
36941  }
36942  
36943  static void handler_ctx_free(handler_ctx *hctx) {
36944 -       
36945 +
36946         free(hctx);
36947  }
36948  
36949  /* init the plugin data */
36950  INIT_FUNC(mod_skeleton_init) {
36951         plugin_data *p;
36952 -       
36953 +
36954         p = calloc(1, sizeof(*p));
36955 -       
36956 +
36957         p->match_buf = buffer_init();
36958 -       
36959 +
36960         return p;
36961  }
36962  
36963  /* detroy the plugin data */
36964  FREE_FUNC(mod_skeleton_free) {
36965         plugin_data *p = p_d;
36966 -       
36967 +
36968         UNUSED(srv);
36969  
36970         if (!p) return HANDLER_GO_ON;
36971 -       
36972 +
36973         if (p->config_storage) {
36974                 size_t i;
36975  
36976 @@ -84,18 +84,18 @@
36977                         plugin_config *s = p->config_storage[i];
36978  
36979                         if (!s) continue;
36980 -                       
36981 +
36982                         array_free(s->match);
36983 -                       
36984 +
36985                         free(s);
36986                 }
36987                 free(p->config_storage);
36988         }
36989 -       
36990 +
36991         buffer_free(p->match_buf);
36992 -       
36993 +
36994         free(p);
36995 -       
36996 +
36997         return HANDLER_GO_ON;
36998  }
36999  
37000 @@ -104,91 +104,88 @@
37001  SETDEFAULTS_FUNC(mod_skeleton_set_defaults) {
37002         plugin_data *p = p_d;
37003         size_t i = 0;
37004 -       
37005 -       config_values_t cv[] = { 
37006 +
37007 +       config_values_t cv[] = {
37008                 { "skeleton.array",             NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
37009                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
37010         };
37011 -       
37012 +
37013         if (!p) return HANDLER_ERROR;
37014 -       
37015 +
37016         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37017 -       
37018 +
37019         for (i = 0; i < srv->config_context->used; i++) {
37020                 plugin_config *s;
37021 -               
37022 +
37023                 s = calloc(1, sizeof(plugin_config));
37024                 s->match    = array_init();
37025 -               
37026 +
37027                 cv[0].destination = s->match;
37028 -               
37029 +
37030                 p->config_storage[i] = s;
37031 -       
37032 +
37033                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
37034                         return HANDLER_ERROR;
37035                 }
37036         }
37037 -       
37038 +
37039         return HANDLER_GO_ON;
37040  }
37041  
37042 -#define PATCH(x) \
37043 -       p->conf.x = s->x;
37044  static int mod_skeleton_patch_connection(server *srv, connection *con, plugin_data *p) {
37045         size_t i, j;
37046         plugin_config *s = p->config_storage[0];
37047 -       
37048 -       PATCH(match);
37049 -       
37050 +
37051 +       PATCH_OPTION(match);
37052 +
37053         /* skip the first, the global context */
37054         for (i = 1; i < srv->config_context->used; i++) {
37055                 data_config *dc = (data_config *)srv->config_context->data[i];
37056                 s = p->config_storage[i];
37057 -               
37058 +
37059                 /* condition didn't match */
37060                 if (!config_check_cond(srv, con, dc)) continue;
37061 -               
37062 +
37063                 /* merge config */
37064                 for (j = 0; j < dc->value->used; j++) {
37065                         data_unset *du = dc->value->data[j];
37066 -                       
37067 +
37068                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("skeleton.array"))) {
37069 -                               PATCH(match);
37070 +                               PATCH_OPTION(match);
37071                         }
37072                 }
37073         }
37074 -       
37075 +
37076         return 0;
37077  }
37078 -#undef PATCH
37079  
37080  URIHANDLER_FUNC(mod_skeleton_uri_handler) {
37081         plugin_data *p = p_d;
37082         int s_len;
37083         size_t k, i;
37084 -       
37085 +
37086         UNUSED(srv);
37087  
37088         if (con->uri.path->used == 0) return HANDLER_GO_ON;
37089 -       
37090 +
37091         mod_skeleton_patch_connection(srv, con, p);
37092  
37093         s_len = con->uri.path->used - 1;
37094 -       
37095 +
37096         for (k = 0; k < p->conf.match->used; k++) {
37097                 data_string *ds = (data_string *)p->conf.match->data[k];
37098                 int ct_len = ds->value->used - 1;
37099 -               
37100 +
37101                 if (ct_len > s_len) continue;
37102                 if (ds->value->used == 0) continue;
37103 -               
37104 +
37105                 if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
37106                         con->http_status = 403;
37107 -       
37108 +
37109                         return HANDLER_FINISHED;
37110                 }
37111         }
37112 -       
37113 +
37114         /* not found */
37115         return HANDLER_GO_ON;
37116  }
37117 @@ -198,13 +195,13 @@
37118  int mod_skeleton_plugin_init(plugin *p) {
37119         p->version     = LIGHTTPD_VERSION_ID;
37120         p->name        = buffer_init_string("skeleton");
37121 -       
37122 +
37123         p->init        = mod_skeleton_init;
37124         p->handle_uri_clean  = mod_skeleton_uri_handler;
37125         p->set_defaults  = mod_skeleton_set_defaults;
37126         p->cleanup     = mod_skeleton_free;
37127 -       
37128 +
37129         p->data        = NULL;
37130 -       
37131 +
37132         return 0;
37133  }
37134 --- ../lighttpd-1.4.11/src/mod_sql_vhost_core.c 1970-01-01 03:00:00.000000000 +0300
37135 +++ lighttpd-1.4.12/src/mod_sql_vhost_core.c    2006-07-16 00:26:04.000000000 +0300
37136 @@ -0,0 +1,209 @@
37137 +#include <stdio.h>
37138 +#include <errno.h>
37139 +#include <fcntl.h>
37140 +#include <string.h>
37141 +
37142 +#ifdef HAVE_CONFIG_H
37143 +#include "config.h"
37144 +#endif
37145 +
37146 +#include "plugin.h"
37147 +#include "log.h"
37148 +
37149 +#include "stat_cache.h"
37150 +
37151 +#include "mod_sql_vhost_core.h"
37152 +
37153 +#define plugin_data mod_sql_vhost_core_plugin_data
37154 +#define plugin_config mod_sql_vhost_core_plugin_config
37155 +
37156 +/* init the plugin data */
37157 +INIT_FUNC(mod_sql_vhost_core_init) {
37158 +       plugin_data *p;
37159 +
37160 +       p = calloc(1, sizeof(*p));
37161 +
37162 +       p->docroot = buffer_init();
37163 +       p->host = buffer_init();
37164 +
37165 +       return p;
37166 +}
37167 +
37168 +/* cleanup the plugin data */
37169 +SERVER_FUNC(mod_sql_vhost_core_cleanup) {
37170 +       plugin_data *p = p_d;
37171 +
37172 +       UNUSED(srv);
37173 +
37174 +       if (!p) return HANDLER_GO_ON;
37175 +
37176 +       if (p->config_storage) {
37177 +               size_t i;
37178 +               for (i = 0; i < srv->config_context->used; i++) {
37179 +                       plugin_config *s = p->config_storage[i];
37180 +
37181 +                       if (!s) continue;
37182 +
37183 +                       buffer_free(s->db);
37184 +                       buffer_free(s->user);
37185 +                       buffer_free(s->pass);
37186 +                       buffer_free(s->sock);
37187 +                       buffer_free(s->backend);
37188 +
37189 +                       free(s);
37190 +               }
37191 +               free(p->config_storage);
37192 +       }
37193 +       buffer_free(p->docroot);
37194 +       buffer_free(p->host);
37195 +
37196 +       free(p);
37197 +
37198 +       return HANDLER_GO_ON;
37199 +}
37200 +
37201 +/* set configuration values */
37202 +SERVER_FUNC(mod_sql_vhost_core_set_defaults) {
37203 +       plugin_data *p = p_d;
37204 +
37205 +       size_t i = 0;
37206 +
37207 +       config_values_t cv[] = {
37208 +               { "sql-vhost.db",       NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 0 * e.g. vhost */
37209 +               { "sql-vhost.user",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 1 * lighty */
37210 +               { "sql-vhost.pass",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 2 * secrect */
37211 +               { "sql-vhost.sock",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 3 * /tmp/mysql.sock */
37212 +               { "sql-vhost.select-vhost", NULL, T_CONFIG_STRING,      T_CONFIG_SCOPE_SERVER }, /* 4 * SELECT ... FROM hosts WHERE hostname = ? */
37213 +               { "sql-vhost.hostname", NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 5 * 127.0.0.1 */
37214 +               { "sql-vhost.port",     NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_SERVER }, /* 6 * 3306 */
37215 +               { "sql-vhost.backend",  NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 7 * mysql */
37216 +
37217 +               /* backward compat */
37218 +               { "mysql-vhost.db",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 8 == 0 */
37219 +               { "mysql-vhost.user",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 9 == 1 */
37220 +               { "mysql-vhost.pass",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 10 == 2 */
37221 +               { "mysql-vhost.sock",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 11 == 3 */
37222 +               { "mysql-vhost.sql",    NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 12 == 4 */
37223 +               { "mysql-vhost.hostname", NULL, T_CONFIG_STRING,T_CONFIG_SCOPE_SERVER }, /* 13 == 5 */
37224 +               { "mysql-vhost.port",   NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_SERVER }, /* 14 == 6 */
37225 +
37226 +                { NULL,                        NULL, T_CONFIG_UNSET,   T_CONFIG_SCOPE_UNSET }
37227 +        };
37228 +
37229 +       p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37230 +
37231 +       for (i = 0; i < srv->config_context->used; i++) {
37232 +               plugin_config *s;
37233 +
37234 +               s = calloc(1, sizeof(plugin_config));
37235 +               s->db = buffer_init();
37236 +               s->user = buffer_init();
37237 +               s->pass = buffer_init();
37238 +               s->sock = buffer_init();
37239 +               s->hostname = buffer_init();
37240 +               s->backend = buffer_init();
37241 +               s->port   = 0;               /* default port for mysql */
37242 +               s->select_vhost = buffer_init();
37243 +               s->backend_data = NULL;
37244 +
37245 +               cv[0].destination = s->db;
37246 +               cv[1].destination = s->user;
37247 +               cv[2].destination = s->pass;
37248 +               cv[3].destination = s->sock;
37249 +               cv[4].destination = s->select_vhost;
37250 +               cv[5].destination = s->hostname;
37251 +               cv[6].destination = &(s->port);
37252 +               cv[7].destination = s->backend;
37253 +
37254 +               /* backend compat */
37255 +               cv[8].destination = cv[0].destination;
37256 +               cv[9].destination = cv[1].destination;
37257 +               cv[10].destination = cv[2].destination;
37258 +               cv[11].destination = cv[3].destination;
37259 +               cv[12].destination = cv[4].destination;
37260 +               cv[13].destination = cv[5].destination;
37261 +               cv[14].destination = cv[6].destination;
37262 +
37263 +               p->config_storage[i] = s;
37264 +
37265 +               if (config_insert_values_global(srv,
37266 +                       ((data_config *)srv->config_context->data[i])->value,
37267 +                       cv)) return HANDLER_ERROR;
37268 +
37269 +               /* we only parse the config, the backend plugin will patch itself into the plugin-struct */
37270 +       }
37271 +
37272 +        return HANDLER_GO_ON;
37273 +}
37274 +
37275 +static int mod_sql_vhost_core_patch_connection(server *srv, connection *con, plugin_data *p) {
37276 +       size_t i;
37277 +       plugin_config *s = p->config_storage[0];
37278 +
37279 +       PATCH_OPTION(backend_data);
37280 +       PATCH_OPTION(get_vhost);
37281 +
37282 +       /* skip the first, the global context */
37283 +       for (i = 1; i < srv->config_context->used; i++) {
37284 +               data_config *dc = (data_config *)srv->config_context->data[i];
37285 +               s = p->config_storage[i];
37286 +
37287 +               /* condition didn't match */
37288 +               if (!config_check_cond(srv, con, dc)) continue;
37289 +
37290 +               if (s->backend_data) {
37291 +                       PATCH_OPTION(backend_data);
37292 +                       PATCH_OPTION(get_vhost);
37293 +               }
37294 +       }
37295 +
37296 +       return 0;
37297 +}
37298 +
37299 +/* handle document root request */
37300 +CONNECTION_FUNC(mod_sql_vhost_core_handle_docroot) {
37301 +       plugin_data *p = p_d;
37302 +       stat_cache_entry *sce;
37303 +
37304 +       /* no host specified? */
37305 +       if (!con->uri.authority->used) return HANDLER_GO_ON;
37306 +
37307 +       mod_sql_vhost_core_patch_connection(srv, con, p);
37308 +
37309 +       /* do we have backend ? */
37310 +       if (!p->conf.get_vhost) return HANDLER_GO_ON;
37311 +
37312 +       /* ask the backend for the data */
37313 +       if (0 != p->conf.get_vhost(srv, con, p->conf.backend_data, p->docroot, p->host)) {
37314 +               return HANDLER_GO_ON;
37315 +       }
37316 +
37317 +       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->docroot, &sce)) {
37318 +               log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->docroot);
37319 +               return HANDLER_GO_ON;
37320 +       }
37321 +        if (!S_ISDIR(sce->st.st_mode)) {
37322 +               log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", p->docroot);
37323 +               return HANDLER_GO_ON;
37324 +       }
37325 +
37326 +       buffer_copy_string_buffer(con->server_name, p->host);
37327 +       buffer_copy_string_buffer(con->physical.doc_root, p->docroot);
37328 +
37329 +       return HANDLER_GO_ON;
37330 +}
37331 +
37332 +/* this function is called at dlopen() time and inits the callbacks */
37333 +int mod_sql_vhost_core_plugin_init(plugin *p) {
37334 +       p->version     = LIGHTTPD_VERSION_ID;
37335 +       p->name                         = buffer_init_string("mod_sql_vhost_core");
37336 +
37337 +       p->init                         = mod_sql_vhost_core_init;
37338 +       p->cleanup                      = mod_sql_vhost_core_cleanup;
37339 +
37340 +       p->set_defaults                 = mod_sql_vhost_core_set_defaults;
37341 +       p->handle_docroot               = mod_sql_vhost_core_handle_docroot;
37342 +
37343 +       return 0;
37344 +}
37345 +
37346 --- ../lighttpd-1.4.11/src/mod_sql_vhost_core.h 1970-01-01 03:00:00.000000000 +0300
37347 +++ lighttpd-1.4.12/src/mod_sql_vhost_core.h    2006-07-16 00:26:04.000000000 +0300
37348 @@ -0,0 +1,49 @@
37349 +#ifndef _MOD_SQL_VHOST_CORE_H_
37350 +#define _MOD_SQL_VHOST_CORE_H_
37351 +
37352 +#include "buffer.h"
37353 +#include "plugin.h"
37354 +
37355 +#define SQLVHOST_BACKEND_GETVHOST_PARAMS \
37356 +       (server *srv, connection *con, void *p_d, buffer *docroot, buffer *host)
37357 +
37358 +#define SQLVHOST_BACKEND_GETVHOST_RETVAL handler_t
37359 +
37360 +#define SQLVHOST_BACKEND_GETVHOST(name) \
37361 +       SQLVHOST_BACKEND_GETVHOST_RETVAL name SQLVHOST_BACKEND_GETVHOST_PARAMS
37362 +
37363 +#define SQLVHOST_BACKEND_GETVHOST_PTR(name) \
37364 +       SQLVHOST_BACKEND_GETVHOST_RETVAL (* name)SQLVHOST_BACKEND_GETVHOST_PARAMS
37365 +
37366 +typedef struct {
37367 +       buffer  *db;
37368 +       buffer  *user;
37369 +       buffer  *pass;
37370 +       buffer  *sock;
37371 +
37372 +       buffer  *hostname;
37373 +       unsigned short port;
37374 +
37375 +       buffer  *backend;
37376 +       void *backend_data;
37377 +
37378 +       buffer *select_vhost;
37379 +
37380 +       SQLVHOST_BACKEND_GETVHOST_PTR(get_vhost);
37381 +} mod_sql_vhost_core_plugin_config;
37382 +
37383 +/* global plugin data */
37384 +typedef struct {
37385 +       PLUGIN_DATA;
37386 +
37387 +       buffer  *docroot;
37388 +       buffer  *host;
37389 +
37390 +       mod_sql_vhost_core_plugin_config **config_storage;
37391 +
37392 +       mod_sql_vhost_core_plugin_config conf;
37393 +} mod_sql_vhost_core_plugin_data;
37394 +
37395 +
37396 +
37397 +#endif
37398 --- ../lighttpd-1.4.11/src/mod_ssi.c    2006-03-04 17:09:48.000000000 +0200
37399 +++ lighttpd-1.4.12/src/mod_ssi.c       2006-07-16 00:26:04.000000000 +0300
37400 @@ -6,7 +6,6 @@
37401  #include <string.h>
37402  #include <errno.h>
37403  #include <time.h>
37404 -#include <unistd.h>
37405  
37406  #include "base.h"
37407  #include "log.h"
37408 @@ -23,6 +22,8 @@
37409  #include "inet_ntop_cache.h"
37410  
37411  #include "sys-socket.h"
37412 +#include "sys-strings.h"
37413 +#include "sys-files.h"
37414  
37415  #ifdef HAVE_PWD_H
37416  #include <pwd.h>
37417 @@ -39,15 +40,15 @@
37418  /* init the plugin data */
37419  INIT_FUNC(mod_ssi_init) {
37420         plugin_data *p;
37421 -       
37422 +
37423         p = calloc(1, sizeof(*p));
37424 -       
37425 +
37426         p->timefmt = buffer_init();
37427         p->stat_fn = buffer_init();
37428 -       
37429 +
37430         p->ssi_vars = array_init();
37431         p->ssi_cgi_env = array_init();
37432 -       
37433 +
37434         return p;
37435  }
37436  
37437 @@ -55,21 +56,21 @@
37438  FREE_FUNC(mod_ssi_free) {
37439         plugin_data *p = p_d;
37440         UNUSED(srv);
37441 -       
37442 +
37443         if (!p) return HANDLER_GO_ON;
37444 -       
37445 +
37446         if (p->config_storage) {
37447                 size_t i;
37448                 for (i = 0; i < srv->config_context->used; i++) {
37449                         plugin_config *s = p->config_storage[i];
37450 -                       
37451 +
37452                         array_free(s->ssi_extension);
37453 -                       
37454 +
37455                         free(s);
37456                 }
37457                 free(p->config_storage);
37458         }
37459 -       
37460 +
37461         array_free(p->ssi_vars);
37462         array_free(p->ssi_cgi_env);
37463  #ifdef HAVE_PCRE_H
37464 @@ -77,9 +78,9 @@
37465  #endif
37466         buffer_free(p->timefmt);
37467         buffer_free(p->stat_fn);
37468 -       
37469 +
37470         free(p);
37471 -       
37472 +
37473         return HANDLER_GO_ON;
37474  }
37475  
37476 @@ -92,36 +93,36 @@
37477         const char *errptr;
37478         int erroff;
37479  #endif
37480 -       
37481 -       config_values_t cv[] = { 
37482 +
37483 +       config_values_t cv[] = {
37484                 { "ssi.extension",              NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
37485                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
37486         };
37487 -       
37488 +
37489         if (!p) return HANDLER_ERROR;
37490 -       
37491 +
37492         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37493 -       
37494 +
37495         for (i = 0; i < srv->config_context->used; i++) {
37496                 plugin_config *s;
37497 -               
37498 +
37499                 s = calloc(1, sizeof(plugin_config));
37500                 s->ssi_extension  = array_init();
37501 -               
37502 +
37503                 cv[0].destination = s->ssi_extension;
37504 -               
37505 +
37506                 p->config_storage[i] = s;
37507 -       
37508 +
37509                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
37510                         return HANDLER_ERROR;
37511                 }
37512         }
37513 -       
37514 +
37515  #ifdef HAVE_PCRE_H
37516         /* allow 2 params */
37517         if (NULL == (p->ssi_regex = pcre_compile("<!--#([a-z]+)\\s+(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?-->", 0, &errptr, &erroff, NULL))) {
37518                 log_error_write(srv, __FILE__, __LINE__, "sds",
37519 -                               "ssi: pcre ", 
37520 +                               "ssi: pcre ",
37521                                 erroff, errptr);
37522                 return HANDLER_ERROR;
37523         }
37524 @@ -130,52 +131,52 @@
37525                         "mod_ssi: pcre support is missing, please recompile with pcre support or remove mod_ssi from the list of modules");
37526         return HANDLER_ERROR;
37527  #endif
37528 -       
37529 +
37530         return HANDLER_GO_ON;
37531  }
37532  
37533  int ssi_env_add(array *env, const char *key, const char *val) {
37534         data_string *ds;
37535 -                       
37536 +
37537         if (NULL == (ds = (data_string *)array_get_unused_element(env, TYPE_STRING))) {
37538                 ds = data_string_init();
37539         }
37540         buffer_copy_string(ds->key,   key);
37541         buffer_copy_string(ds->value, val);
37542 -       
37543 +
37544         array_insert_unique(env, (data_unset *)ds);
37545 -       
37546 +
37547         return 0;
37548  }
37549  
37550  /**
37551   *
37552   *  the next two functions are take from fcgi.c
37553 - * 
37554 + *
37555   */
37556  
37557  static int ssi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
37558         size_t i;
37559 -       
37560 +
37561         for (i = 0; i < con->request.headers->used; i++) {
37562                 data_string *ds;
37563 -               
37564 +
37565                 ds = (data_string *)con->request.headers->data[i];
37566 -               
37567 +
37568                 if (ds->value->used && ds->key->used) {
37569                         size_t j;
37570                         buffer_reset(srv->tmp_buf);
37571 -                       
37572 +
37573                         /* don't forward the Authorization: Header */
37574                         if (0 == strcasecmp(ds->key->ptr, "AUTHORIZATION")) {
37575                                 continue;
37576                         }
37577 -                       
37578 +
37579                         if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
37580                                 buffer_copy_string(srv->tmp_buf, "HTTP_");
37581                                 srv->tmp_buf->used--;
37582                         }
37583 -                       
37584 +
37585                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
37586                         for (j = 0; j < ds->key->used - 1; j++) {
37587                                 char c = '_';
37588 @@ -189,33 +190,33 @@
37589                                 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
37590                         }
37591                         srv->tmp_buf->ptr[srv->tmp_buf->used] = '\0';
37592 -                       
37593 +
37594                         ssi_env_add(p->ssi_cgi_env, srv->tmp_buf->ptr, ds->value->ptr);
37595                 }
37596         }
37597 -       
37598 +
37599         return 0;
37600  }
37601  
37602  static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) {
37603         char buf[32];
37604 -       
37605 +
37606         server_socket *srv_sock = con->srv_socket;
37607 -       
37608 +
37609  #ifdef HAVE_IPV6
37610         char b2[INET6_ADDRSTRLEN + 1];
37611  #endif
37612  
37613  #define CONST_STRING(x) \
37614                 x
37615 -       
37616 +
37617         array_reset(p->ssi_cgi_env);
37618 -       
37619 +
37620         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_SOFTWARE"), PACKAGE_NAME"/"PACKAGE_VERSION);
37621         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_NAME"),
37622  #ifdef HAVE_IPV6
37623 -                    inet_ntop(srv_sock->addr.plain.sa_family, 
37624 -                              srv_sock->addr.plain.sa_family == AF_INET6 ? 
37625 +                    inet_ntop(srv_sock->addr.plain.sa_family,
37626 +                              srv_sock->addr.plain.sa_family == AF_INET6 ?
37627                                (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
37628                                (const void *) &(srv_sock->addr.ipv4.sin_addr),
37629                                b2, sizeof(b2)-1)
37630 @@ -224,28 +225,28 @@
37631  #endif
37632                      );
37633         ssi_env_add(p->ssi_cgi_env, CONST_STRING("GATEWAY_INTERFACE"), "CGI/1.1");
37634 -               
37635 -       ltostr(buf, 
37636 +
37637 +       ltostr(buf,
37638  #ifdef HAVE_IPV6
37639                ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
37640  #else
37641                ntohs(srv_sock->addr.ipv4.sin_port)
37642  #endif
37643                );
37644 -       
37645 +
37646         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PORT"), buf);
37647 -       
37648 +
37649         ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_ADDR"),
37650                     inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
37651 -       
37652 +
37653         if (con->authed_user->used) {
37654                 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_USER"),
37655                              con->authed_user->ptr);
37656         }
37657 -       
37658 +
37659         if (con->request.content_length > 0) {
37660                 /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
37661 -               
37662 +
37663                 /* request.content_length < SSIZE_MAX, see request.c */
37664                 ltostr(buf, con->request.content_length);
37665                 ssi_env_add(p->ssi_cgi_env, CONST_STRING("CONTENT_LENGTH"), buf);
37666 @@ -271,30 +272,30 @@
37667         if (con->request.pathinfo->used) {
37668                 ssi_env_add(p->ssi_cgi_env, CONST_STRING("PATH_INFO"), con->request.pathinfo->ptr);
37669         }
37670 -               
37671 +
37672         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SCRIPT_FILENAME"), con->physical.path->ptr);
37673         ssi_env_add(p->ssi_cgi_env, CONST_STRING("DOCUMENT_ROOT"), con->physical.doc_root->ptr);
37674 -       
37675 +
37676         ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_URI"), con->request.uri->ptr);
37677         ssi_env_add(p->ssi_cgi_env, CONST_STRING("QUERY_STRING"), con->uri.query->used ? con->uri.query->ptr : "");
37678         ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_METHOD"), get_http_method_name(con->request.http_method));
37679         ssi_env_add(p->ssi_cgi_env, CONST_STRING("REDIRECT_STATUS"), "200");
37680         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PROTOCOL"), get_http_version_name(con->request.http_version));
37681 -       
37682 +
37683         ssi_env_add_request_headers(srv, con, p);
37684 -       
37685 +
37686         return 0;
37687  }
37688  
37689 -static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, 
37690 +static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
37691                             const char **l, size_t n) {
37692         size_t i, ssicmd = 0;
37693         char buf[255];
37694         buffer *b = NULL;
37695 -       
37696 -       struct { 
37697 +
37698 +       struct {
37699                 const char *var;
37700 -               enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD, 
37701 +               enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD,
37702                                 SSI_CONFIG, SSI_PRINTENV, SSI_SET, SSI_IF, SSI_ELIF,
37703                                 SSI_ELSE, SSI_ENDIF, SSI_EXEC } type;
37704         } ssicmds[] = {
37705 @@ -310,27 +311,27 @@
37706                 { "endif",    SSI_ENDIF },
37707                 { "else",     SSI_ELSE },
37708                 { "exec",     SSI_EXEC },
37709 -               
37710 +
37711                 { NULL, SSI_UNSET }
37712         };
37713 -       
37714 +
37715         for (i = 0; ssicmds[i].var; i++) {
37716                 if (0 == strcmp(l[1], ssicmds[i].var)) {
37717                         ssicmd = ssicmds[i].type;
37718                         break;
37719                 }
37720         }
37721 -       
37722 +
37723         switch(ssicmd) {
37724         case SSI_ECHO: {
37725                 /* echo */
37726                 int var = 0, enc = 0;
37727                 const char *var_val = NULL;
37728                 stat_cache_entry *sce = NULL;
37729 -               
37730 -               struct { 
37731 +
37732 +               struct {
37733                         const char *var;
37734 -                       enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI, 
37735 +                       enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI,
37736                                         SSI_ECHO_LAST_MODIFIED, SSI_ECHO_USER_NAME } type;
37737                 } echovars[] = {
37738                         { "DATE_GMT",      SSI_ECHO_DATE_GMT },
37739 @@ -339,27 +340,27 @@
37740                         { "DOCUMENT_URI",  SSI_ECHO_DOCUMENT_URI },
37741                         { "LAST_MODIFIED", SSI_ECHO_LAST_MODIFIED },
37742                         { "USER_NAME",     SSI_ECHO_USER_NAME },
37743 -                       
37744 +
37745                         { NULL, SSI_ECHO_UNSET }
37746                 };
37747 -               
37748 -               struct { 
37749 +
37750 +               struct {
37751                         const char *var;
37752                         enum { SSI_ENC_UNSET, SSI_ENC_URL, SSI_ENC_NONE, SSI_ENC_ENTITY } type;
37753                 } encvars[] = {
37754                         { "url",          SSI_ENC_URL },
37755                         { "none",         SSI_ENC_NONE },
37756                         { "entity",       SSI_ENC_ENTITY },
37757 -                       
37758 +
37759                         { NULL, SSI_ENC_UNSET }
37760                 };
37761 -               
37762 +
37763                 for (i = 2; i < n; i += 2) {
37764                         if (0 == strcmp(l[i], "var")) {
37765                                 int j;
37766 -                               
37767 +
37768                                 var_val = l[i+1];
37769 -                               
37770 +
37771                                 for (j = 0; echovars[j].var; j++) {
37772                                         if (0 == strcmp(l[i+1], echovars[j].var)) {
37773                                                 var = echovars[j].type;
37774 @@ -368,7 +369,7 @@
37775                                 }
37776                         } else if (0 == strcmp(l[i], "encoding")) {
37777                                 int j;
37778 -                               
37779 +
37780                                 for (j = 0; encvars[j].var; j++) {
37781                                         if (0 == strcmp(l[i+1], encvars[j].var)) {
37782                                                 enc = encvars[j].type;
37783 @@ -377,26 +378,26 @@
37784                                 }
37785                         } else {
37786                                 log_error_write(srv, __FILE__, __LINE__, "sss",
37787 -                                               "ssi: unknow attribute for ", 
37788 +                                               "ssi: unknow attribute for ",
37789                                                 l[1], l[i]);
37790                         }
37791                 }
37792 -               
37793 +
37794                 if (p->if_is_false) break;
37795 -               
37796 +
37797                 if (!var_val) {
37798                         log_error_write(srv, __FILE__, __LINE__, "sss",
37799 -                                       "ssi: ", 
37800 +                                       "ssi: ",
37801                                         l[1], "var is missing");
37802                         break;
37803                 }
37804  
37805                 stat_cache_get_entry(srv, con, con->physical.path, &sce);
37806 -               
37807 +
37808                 switch(var) {
37809                 case SSI_ECHO_USER_NAME: {
37810                         struct passwd *pw;
37811 -                       
37812 +
37813                         b = chunkqueue_get_append_buffer(con->write_queue);
37814  #ifdef HAVE_PWD_H
37815                         if (NULL == (pw = getpwuid(sce->st.st_uid))) {
37816 @@ -411,7 +412,7 @@
37817                 }
37818                 case SSI_ECHO_LAST_MODIFIED:    {
37819                         time_t t = sce->st.st_mtime;
37820 -                       
37821 +
37822                         b = chunkqueue_get_append_buffer(con->write_queue);
37823                         if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
37824                                 buffer_copy_string(b, "(none)");
37825 @@ -422,7 +423,7 @@
37826                 }
37827                 case SSI_ECHO_DATE_LOCAL: {
37828                         time_t t = time(NULL);
37829 -                       
37830 +
37831                         b = chunkqueue_get_append_buffer(con->write_queue);
37832                         if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
37833                                 buffer_copy_string(b, "(none)");
37834 @@ -433,7 +434,7 @@
37835                 }
37836                 case SSI_ECHO_DATE_GMT: {
37837                         time_t t = time(NULL);
37838 -                       
37839 +
37840                         b = chunkqueue_get_append_buffer(con->write_queue);
37841                         if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, gmtime(&t))) {
37842                                 buffer_copy_string(b, "(none)");
37843 @@ -444,7 +445,7 @@
37844                 }
37845                 case SSI_ECHO_DOCUMENT_NAME: {
37846                         char *sl;
37847 -                       
37848 +
37849                         b = chunkqueue_get_append_buffer(con->write_queue);
37850                         if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
37851                                 buffer_copy_string_buffer(b, con->physical.path);
37852 @@ -461,15 +462,15 @@
37853                 default: {
37854                         data_string *ds;
37855                         /* check if it is a cgi-var */
37856 -                       
37857 +
37858                         b = chunkqueue_get_append_buffer(con->write_queue);
37859 -                       
37860 +
37861                         if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, var_val))) {
37862                                 buffer_copy_string_buffer(b, ds->value);
37863                         } else {
37864                                 buffer_copy_string(b, "(none)");
37865                         }
37866 -                       
37867 +
37868                         break;
37869                 }
37870                 }
37871 @@ -481,7 +482,7 @@
37872                 const char * file_path = NULL, *virt_path = NULL;
37873                 struct stat st;
37874                 char *sl;
37875 -               
37876 +
37877                 for (i = 2; i < n; i += 2) {
37878                         if (0 == strcmp(l[i], "file")) {
37879                                 file_path = l[i+1];
37880 @@ -489,28 +490,28 @@
37881                                 virt_path = l[i+1];
37882                         } else {
37883                                 log_error_write(srv, __FILE__, __LINE__, "sss",
37884 -                                               "ssi: unknow attribute for ", 
37885 +                                               "ssi: unknow attribute for ",
37886                                                 l[1], l[i]);
37887                         }
37888                 }
37889 -               
37890 +
37891                 if (!file_path && !virt_path) {
37892                         log_error_write(srv, __FILE__, __LINE__, "sss",
37893 -                                       "ssi: ", 
37894 +                                       "ssi: ",
37895                                         l[1], "file or virtual are missing");
37896                         break;
37897                 }
37898 -               
37899 +
37900                 if (file_path && virt_path) {
37901                         log_error_write(srv, __FILE__, __LINE__, "sss",
37902 -                                       "ssi: ", 
37903 +                                       "ssi: ",
37904                                         l[1], "only one of file and virtual is allowed here");
37905                         break;
37906                 }
37907 -               
37908 -               
37909 +
37910 +
37911                 if (p->if_is_false) break;
37912 -               
37913 +
37914                 if (file_path) {
37915                         /* current doc-root */
37916                         if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
37917 @@ -519,46 +520,46 @@
37918                                 buffer_copy_string_len(p->stat_fn, con->physical.path->ptr, sl - con->physical.path->ptr + 1);
37919                         }
37920  
37921 -                       buffer_copy_string(srv->tmp_buf, file_path); 
37922 +                       buffer_copy_string(srv->tmp_buf, file_path);
37923                         buffer_urldecode_path(srv->tmp_buf);
37924 -                       buffer_path_simplify(srv->tmp_buf, srv->tmp_buf); 
37925 -                       buffer_append_string_buffer(p->stat_fn, srv->tmp_buf); 
37926 +                       buffer_path_simplify(srv->tmp_buf, srv->tmp_buf);
37927 +                       buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
37928                 } else {
37929                         /* virtual */
37930 -                       
37931 +
37932                         if (virt_path[0] == '/') {
37933                                 buffer_copy_string(p->stat_fn, virt_path);
37934                         } else {
37935                                 /* there is always a / */
37936                                 sl = strrchr(con->uri.path->ptr, '/');
37937 -                               
37938 +
37939                                 buffer_copy_string_len(p->stat_fn, con->uri.path->ptr, sl - con->uri.path->ptr + 1);
37940                                 buffer_append_string(p->stat_fn, virt_path);
37941                         }
37942 -                       
37943 +
37944                         buffer_urldecode_path(p->stat_fn);
37945                         buffer_path_simplify(srv->tmp_buf, p->stat_fn);
37946 -                       
37947 +
37948                         /* we have an uri */
37949 -                       
37950 +
37951                         buffer_copy_string_buffer(p->stat_fn, con->physical.doc_root);
37952                         buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
37953                 }
37954 -               
37955 +
37956                 if (0 == stat(p->stat_fn->ptr, &st)) {
37957                         time_t t = st.st_mtime;
37958 -                       
37959 +
37960                         switch (ssicmd) {
37961                         case SSI_FSIZE:
37962                                 b = chunkqueue_get_append_buffer(con->write_queue);
37963                                 if (p->sizefmt) {
37964                                         int j = 0;
37965                                         const char *abr[] = { " B", " kB", " MB", " GB", " TB", NULL };
37966 -                                       
37967 +
37968                                         off_t s = st.st_size;
37969 -                                       
37970 +
37971                                         for (j = 0; s > 1024 && abr[j+1]; s /= 1024, j++);
37972 -                                       
37973 +
37974                                         buffer_copy_off_t(b, s);
37975                                         buffer_append_string(b, abr[j]);
37976                                 } else {
37977 @@ -579,7 +580,7 @@
37978                         }
37979                 } else {
37980                         log_error_write(srv, __FILE__, __LINE__, "sbs",
37981 -                                       "ssi: stating failed ", 
37982 +                                       "ssi: stating failed ",
37983                                         p->stat_fn, strerror(errno));
37984                 }
37985                 break;
37986 @@ -593,33 +594,33 @@
37987                                 val = l[i+1];
37988                         } else {
37989                                 log_error_write(srv, __FILE__, __LINE__, "sss",
37990 -                                               "ssi: unknow attribute for ", 
37991 +                                               "ssi: unknow attribute for ",
37992                                                 l[1], l[i]);
37993                         }
37994                 }
37995 -               
37996 +
37997                 if (p->if_is_false) break;
37998 -               
37999 +
38000                 if (key && val) {
38001                         data_string *ds;
38002 -                       
38003 +
38004                         if (NULL == (ds = (data_string *)array_get_unused_element(p->ssi_vars, TYPE_STRING))) {
38005                                 ds = data_string_init();
38006                         }
38007                         buffer_copy_string(ds->key,   key);
38008                         buffer_copy_string(ds->value, val);
38009 -                       
38010 +
38011                         array_insert_unique(p->ssi_vars, (data_unset *)ds);
38012                 } else {
38013                         log_error_write(srv, __FILE__, __LINE__, "sss",
38014 -                                       "ssi: var and value have to be set in", 
38015 +                                       "ssi: var and value have to be set in",
38016                                         l[0], l[1]);
38017                 }
38018                 break;
38019         }
38020 -       case SSI_CONFIG: 
38021 +       case SSI_CONFIG:
38022                 if (p->if_is_false) break;
38023 -               
38024 +
38025                 for (i = 2; i < n; i += 2) {
38026                         if (0 == strcmp(l[i], "timefmt")) {
38027                                 buffer_copy_string(p->timefmt, l[i+1]);
38028 @@ -632,63 +633,65 @@
38029                                         log_error_write(srv, __FILE__, __LINE__, "sssss",
38030                                                         "ssi: unknow value for attribute '",
38031                                                         l[i],
38032 -                                                       "' for ", 
38033 +                                                       "' for ",
38034                                                         l[1], l[i+1]);
38035                                 }
38036                         } else {
38037                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38038 -                                               "ssi: unknow attribute for ", 
38039 +                                               "ssi: unknow attribute for ",
38040                                                 l[1], l[i]);
38041                         }
38042                 }
38043                 break;
38044         case SSI_PRINTENV:
38045                 if (p->if_is_false) break;
38046 -               
38047 +
38048                 b = chunkqueue_get_append_buffer(con->write_queue);
38049                 buffer_copy_string(b, "<pre>");
38050                 for (i = 0; i < p->ssi_vars->used; i++) {
38051                         data_string *ds = (data_string *)p->ssi_vars->data[p->ssi_vars->sorted[i]];
38052 -                       
38053 +
38054                         buffer_append_string_buffer(b, ds->key);
38055                         buffer_append_string(b, ": ");
38056                         buffer_append_string_buffer(b, ds->value);
38057                         buffer_append_string(b, "<br />");
38058 -                                       
38059 +
38060                 }
38061                 buffer_append_string(b, "</pre>");
38062 -               
38063 +
38064                 break;
38065         case SSI_EXEC: {
38066 +#ifndef _WIN32
38067 +
38068                 const char *cmd = NULL;
38069                 pid_t pid;
38070                 int from_exec_fds[2];
38071 -               
38072 +
38073                 for (i = 2; i < n; i += 2) {
38074                         if (0 == strcmp(l[i], "cmd")) {
38075                                 cmd = l[i+1];
38076                         } else {
38077                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38078 -                                               "ssi: unknow attribute for ", 
38079 +                                               "ssi: unknow attribute for ",
38080                                                 l[1], l[i]);
38081                         }
38082                 }
38083 -               
38084 +
38085                 if (p->if_is_false) break;
38086 -               
38087 +
38088                 /* create a return pipe and send output to the html-page
38089 -                * 
38090 -                * as exec is assumed evil it is implemented synchronously 
38091 +                *
38092 +                * as exec is assumed evil it is implemented synchronously
38093                  */
38094 -               
38095 +
38096                 if (!cmd) break;
38097 -#ifdef HAVE_FORK       
38098 +
38099                 if (pipe(from_exec_fds)) {
38100 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
38101 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
38102                                         "pipe failed: ", strerror(errno));
38103                         return -1;
38104                 }
38105 -       
38106 +
38107                 /* fork, execve */
38108                 switch (pid = fork()) {
38109                 case 0: {
38110 @@ -698,14 +701,14 @@
38111                         close(from_exec_fds[1]);
38112                         /* not needed */
38113                         close(from_exec_fds[0]);
38114 -                       
38115 +
38116                         /* close stdin */
38117                         close(STDIN_FILENO);
38118 -               
38119 +
38120                         execl("/bin/sh", "sh", "-c", cmd, NULL);
38121 -                       
38122 +
38123                         log_error_write(srv, __FILE__, __LINE__, "sss", "spawing exec failed:", strerror(errno), cmd);
38124 -               
38125 +
38126                         /* */
38127                         SEGFAULT();
38128                         break;
38129 @@ -718,9 +721,9 @@
38130                         /* father */
38131                         int status;
38132                         ssize_t r;
38133 -                       
38134 +
38135                         close(from_exec_fds[1]);
38136 -                       
38137 +
38138                         /* wait for the client to end */
38139                         if (-1 == waitpid(pid, &status, 0)) {
38140                                 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed:", strerror(errno));
38141 @@ -730,7 +733,7 @@
38142  
38143                                 while(1) {
38144                                         if (ioctl(from_exec_fds[0], FIONREAD, &toread)) {
38145 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
38146 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
38147                                                         "unexpected end-of-file (perhaps the ssi-exec process died)");
38148                                                 return -1;
38149                                         }
38150 @@ -738,10 +741,10 @@
38151                                         if (toread > 0) {
38152                                                 b = chunkqueue_get_append_buffer(con->write_queue);
38153  
38154 -                                               buffer_prepare_copy(b, toread + 1); 
38155 +                                               buffer_prepare_copy(b, toread + 1);
38156  
38157                                                 if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) {
38158 -                                                       /* read failed */ 
38159 +                                                       /* read failed */
38160                                                         break;
38161                                                 } else {
38162                                                         b->used = r;
38163 @@ -755,59 +758,58 @@
38164                                 log_error_write(srv, __FILE__, __LINE__, "s", "process exited abnormally");
38165                         }
38166                         close(from_exec_fds[0]);
38167 -                       
38168 +
38169                         break;
38170                 }
38171                 }
38172  #else
38173 -
38174                 return -1;
38175  #endif
38176 -               
38177 +
38178                 break;
38179         }
38180         case SSI_IF: {
38181                 const char *expr = NULL;
38182 -               
38183 +
38184                 for (i = 2; i < n; i += 2) {
38185                         if (0 == strcmp(l[i], "expr")) {
38186                                 expr = l[i+1];
38187                         } else {
38188                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38189 -                                               "ssi: unknow attribute for ", 
38190 +                                               "ssi: unknow attribute for ",
38191                                                 l[1], l[i]);
38192                         }
38193                 }
38194 -               
38195 +
38196                 if (!expr) {
38197                         log_error_write(srv, __FILE__, __LINE__, "sss",
38198 -                                       "ssi: ", 
38199 +                                       "ssi: ",
38200                                         l[1], "expr missing");
38201                         break;
38202                 }
38203 -               
38204 +
38205                 if ((!p->if_is_false) &&
38206 -                   ((p->if_is_false_level == 0) || 
38207 +                   ((p->if_is_false_level == 0) ||
38208                      (p->if_level < p->if_is_false_level))) {
38209                         switch (ssi_eval_expr(srv, con, p, expr)) {
38210                         case -1:
38211 -                       case 0: 
38212 -                               p->if_is_false = 1; 
38213 +                       case 0:
38214 +                               p->if_is_false = 1;
38215                                 p->if_is_false_level = p->if_level;
38216                                 break;
38217 -                       case 1: 
38218 -                               p->if_is_false = 0; 
38219 +                       case 1:
38220 +                               p->if_is_false = 0;
38221                                 break;
38222                         }
38223                 }
38224 -               
38225 +
38226                 p->if_level++;
38227 -               
38228 +
38229                 break;
38230         }
38231         case SSI_ELSE:
38232                 p->if_level--;
38233 -               
38234 +
38235                 if (p->if_is_false) {
38236                         if ((p->if_level == p->if_is_false_level) &&
38237                             (p->if_is_false_endif == 0)) {
38238 @@ -815,11 +817,11 @@
38239                         }
38240                 } else {
38241                         p->if_is_false = 1;
38242 -                       
38243 +
38244                         p->if_is_false_level = p->if_level;
38245                 }
38246                 p->if_level++;
38247 -               
38248 +
38249                 break;
38250         case SSI_ELIF: {
38251                 const char *expr = NULL;
38252 @@ -828,52 +830,52 @@
38253                                 expr = l[i+1];
38254                         } else {
38255                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38256 -                                               "ssi: unknow attribute for ", 
38257 +                                               "ssi: unknow attribute for ",
38258                                                 l[1], l[i]);
38259                         }
38260                 }
38261 -               
38262 +
38263                 if (!expr) {
38264                         log_error_write(srv, __FILE__, __LINE__, "sss",
38265 -                                       "ssi: ", 
38266 +                                       "ssi: ",
38267                                         l[1], "expr missing");
38268                         break;
38269                 }
38270 -               
38271 +
38272                 p->if_level--;
38273 -               
38274 +
38275                 if (p->if_level == p->if_is_false_level) {
38276                         if ((p->if_is_false) &&
38277                             (p->if_is_false_endif == 0)) {
38278                                 switch (ssi_eval_expr(srv, con, p, expr)) {
38279                                 case -1:
38280 -                               case 0: 
38281 -                                       p->if_is_false = 1; 
38282 +                               case 0:
38283 +                                       p->if_is_false = 1;
38284                                         p->if_is_false_level = p->if_level;
38285                                         break;
38286 -                               case 1: 
38287 -                                       p->if_is_false = 0; 
38288 +                               case 1:
38289 +                                       p->if_is_false = 0;
38290                                         break;
38291                                 }
38292                         } else {
38293 -                               p->if_is_false = 1; 
38294 +                               p->if_is_false = 1;
38295                                 p->if_is_false_level = p->if_level;
38296                                 p->if_is_false_endif = 1;
38297                         }
38298                 }
38299 -               
38300 +
38301                 p->if_level++;
38302 -               
38303 +
38304                 break;
38305         }
38306         case SSI_ENDIF:
38307                 p->if_level--;
38308 -               
38309 +
38310                 if (p->if_level == p->if_is_false_level) {
38311                         p->if_is_false = 0;
38312                         p->if_is_false_endif = 0;
38313                 }
38314 -                       
38315 +
38316                 break;
38317         default:
38318                 log_error_write(srv, __FILE__, __LINE__, "ss",
38319 @@ -881,41 +883,41 @@
38320                                 l[1]);
38321                 break;
38322         }
38323 -       
38324 +
38325         return 0;
38326 -       
38327 +
38328  }
38329  
38330  static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) {
38331         stream s;
38332  #ifdef  HAVE_PCRE_H
38333         int i, n;
38334 -       
38335 +
38336  #define N 10
38337         int ovec[N * 3];
38338  #endif
38339 -       
38340 +
38341         /* get a stream to the file */
38342 -       
38343 +
38344         array_reset(p->ssi_vars);
38345         array_reset(p->ssi_cgi_env);
38346         buffer_copy_string(p->timefmt, "%a, %d %b %Y %H:%M:%S %Z");
38347         p->sizefmt = 0;
38348         build_ssi_cgi_vars(srv, con, p);
38349         p->if_is_false = 0;
38350 -       
38351 +
38352         if (-1 == stream_open(&s, con->physical.path)) {
38353                 log_error_write(srv, __FILE__, __LINE__, "sb",
38354                                 "stream-open: ", con->physical.path);
38355                 return -1;
38356         }
38357 -       
38358 -       
38359 +
38360 +
38361         /**
38362 -        * <!--#element attribute=value attribute=value ... --> 
38363 -        * 
38364 +        * <!--#element attribute=value attribute=value ... -->
38365 +        *
38366          * config       DONE
38367 -        *   errmsg     -- missing 
38368 +        *   errmsg     -- missing
38369          *   sizefmt    DONE
38370          *   timefmt    DONE
38371          * echo         DONE
38372 @@ -937,13 +939,13 @@
38373          * set          DONE
38374          *   var        DONE
38375          *   value      DONE
38376 -        * 
38377 +        *
38378          * if           DONE
38379          * elif         DONE
38380          * else         DONE
38381          * endif        DONE
38382 -        * 
38383 -        * 
38384 +        *
38385 +        *
38386          * expressions
38387          * AND, OR      DONE
38388          * comp         DONE
38389 @@ -951,118 +953,115 @@
38390          * $...         DONE
38391          * '...'        DONE
38392          * ( ... )      DONE
38393 -        * 
38394 -        * 
38395 -        * 
38396 +        *
38397 +        *
38398 +        *
38399          * ** all DONE **
38400 -        * DATE_GMT 
38401 -        *   The current date in Greenwich Mean Time. 
38402 -        * DATE_LOCAL 
38403 -        *   The current date in the local time zone. 
38404 -        * DOCUMENT_NAME 
38405 -        *   The filename (excluding directories) of the document requested by the user. 
38406 -        * DOCUMENT_URI 
38407 -        *   The (%-decoded) URL path of the document requested by the user. Note that in the case of nested include files, this is not then URL for the current document. 
38408 -        * LAST_MODIFIED 
38409 -        *   The last modification date of the document requested by the user. 
38410 -        * USER_NAME 
38411 +        * DATE_GMT
38412 +        *   The current date in Greenwich Mean Time.
38413 +        * DATE_LOCAL
38414 +        *   The current date in the local time zone.
38415 +        * DOCUMENT_NAME
38416 +        *   The filename (excluding directories) of the document requested by the user.
38417 +        * DOCUMENT_URI
38418 +        *   The (%-decoded) URL path of the document requested by the user. Note that in the case of nested include files, this is not then URL for the current document.
38419 +        * LAST_MODIFIED
38420 +        *   The last modification date of the document requested by the user.
38421 +        * USER_NAME
38422          *   Contains the owner of the file which included it.
38423 -        * 
38424 +        *
38425          */
38426 -#ifdef HAVE_PCRE_H     
38427 +#ifdef HAVE_PCRE_H
38428         for (i = 0; (n = pcre_exec(p->ssi_regex, NULL, s.start, s.size, i, 0, ovec, N * 3)) > 0; i = ovec[1]) {
38429                 const char **l;
38430                 /* take everything from last offset to current match pos */
38431 -               
38432 +
38433                 if (!p->if_is_false) chunkqueue_append_file(con->write_queue, con->physical.path, i, ovec[0] - i);
38434 -               
38435 +
38436                 pcre_get_substring_list(s.start, ovec, n, &l);
38437                 process_ssi_stmt(srv, con, p, l, n);
38438                 pcre_free_substring_list(l);
38439         }
38440 -       
38441 +
38442         switch(n) {
38443         case PCRE_ERROR_NOMATCH:
38444                 /* copy everything/the rest */
38445                 chunkqueue_append_file(con->write_queue, con->physical.path, i, s.size - i);
38446 -               
38447 +
38448                 break;
38449         default:
38450                 log_error_write(srv, __FILE__, __LINE__, "sd",
38451                                 "execution error while matching: ", n);
38452                 break;
38453         }
38454 -#endif 
38455 -       
38456 -       
38457 +#endif
38458 +
38459 +
38460         stream_close(&s);
38461 -       
38462 +
38463         con->file_started  = 1;
38464         con->file_finished = 1;
38465 -       
38466 +
38467         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
38468 -       
38469 +
38470         /* reset physical.path */
38471         buffer_reset(con->physical.path);
38472 -       
38473 +
38474         return 0;
38475  }
38476  
38477 -#define PATCH(x) \
38478 -       p->conf.x = s->x;
38479  static int mod_ssi_patch_connection(server *srv, connection *con, plugin_data *p) {
38480         size_t i, j;
38481         plugin_config *s = p->config_storage[0];
38482 -       
38483 -       PATCH(ssi_extension);
38484 -       
38485 +
38486 +       PATCH_OPTION(ssi_extension);
38487 +
38488         /* skip the first, the global context */
38489         for (i = 1; i < srv->config_context->used; i++) {
38490                 data_config *dc = (data_config *)srv->config_context->data[i];
38491                 s = p->config_storage[i];
38492 -               
38493 +
38494                 /* condition didn't match */
38495                 if (!config_check_cond(srv, con, dc)) continue;
38496 -               
38497 +
38498                 /* merge config */
38499                 for (j = 0; j < dc->value->used; j++) {
38500                         data_unset *du = dc->value->data[j];
38501 -                       
38502 +
38503                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssi.extension"))) {
38504 -                               PATCH(ssi_extension);
38505 +                               PATCH_OPTION(ssi_extension);
38506                         }
38507                 }
38508         }
38509 -       
38510 +
38511         return 0;
38512  }
38513 -#undef PATCH
38514  
38515  URIHANDLER_FUNC(mod_ssi_physical_path) {
38516         plugin_data *p = p_d;
38517         size_t k;
38518 -       
38519 +
38520         if (con->physical.path->used == 0) return HANDLER_GO_ON;
38521 -       
38522 +
38523         mod_ssi_patch_connection(srv, con, p);
38524 -       
38525 +
38526         for (k = 0; k < p->conf.ssi_extension->used; k++) {
38527                 data_string *ds = (data_string *)p->conf.ssi_extension->data[k];
38528 -               
38529 +
38530                 if (ds->value->used == 0) continue;
38531 -               
38532 +
38533                 if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
38534                         /* handle ssi-request */
38535 -                       
38536 +
38537                         if (mod_ssi_handle_request(srv, con, p)) {
38538                                 /* on error */
38539                                 con->http_status = 500;
38540                         }
38541 -                       
38542 +
38543                         return HANDLER_FINISHED;
38544                 }
38545         }
38546 -       
38547 +
38548         /* not found */
38549         return HANDLER_GO_ON;
38550  }
38551 @@ -1072,13 +1071,13 @@
38552  int mod_ssi_plugin_init(plugin *p) {
38553         p->version     = LIGHTTPD_VERSION_ID;
38554         p->name        = buffer_init_string("ssi");
38555 -       
38556 +
38557         p->init        = mod_ssi_init;
38558         p->handle_subrequest_start = mod_ssi_physical_path;
38559         p->set_defaults  = mod_ssi_set_defaults;
38560         p->cleanup     = mod_ssi_free;
38561 -       
38562 +
38563         p->data        = NULL;
38564 -       
38565 +
38566         return 0;
38567  }
38568 --- ../lighttpd-1.4.11/src/mod_ssi.h    2005-08-11 01:26:39.000000000 +0300
38569 +++ lighttpd-1.4.12/src/mod_ssi.h       2006-07-16 00:26:04.000000000 +0300
38570 @@ -19,23 +19,23 @@
38571  
38572  typedef struct {
38573         PLUGIN_DATA;
38574 -       
38575 -#ifdef HAVE_PCRE_H     
38576 +
38577 +#ifdef HAVE_PCRE_H
38578         pcre *ssi_regex;
38579 -#endif 
38580 +#endif
38581         buffer *timefmt;
38582         int sizefmt;
38583 -       
38584 +
38585         buffer *stat_fn;
38586 -       
38587 +
38588         array *ssi_vars;
38589         array *ssi_cgi_env;
38590 -       
38591 +
38592         int if_level, if_is_false_level, if_is_false, if_is_false_endif;
38593 -       
38594 +
38595         plugin_config **config_storage;
38596 -       
38597 -       plugin_config conf; 
38598 +
38599 +       plugin_config conf;
38600  } plugin_data;
38601  
38602  int ssi_eval_expr(server *srv, connection *con, plugin_data *p, const char *expr);
38603 --- ../lighttpd-1.4.11/src/mod_ssi_expr.c       2005-08-11 01:26:48.000000000 +0300
38604 +++ lighttpd-1.4.12/src/mod_ssi_expr.c  2006-07-16 00:26:04.000000000 +0300
38605 @@ -11,9 +11,9 @@
38606         const char *input;
38607         size_t offset;
38608         size_t size;
38609 -       
38610 +
38611         int line_pos;
38612 -       
38613 +
38614         int in_key;
38615         int in_brace;
38616         int in_cond;
38617 @@ -21,15 +21,15 @@
38618  
38619  ssi_val_t *ssi_val_init() {
38620         ssi_val_t *s;
38621 -       
38622 +
38623         s = calloc(1, sizeof(*s));
38624 -       
38625 +
38626         return s;
38627  }
38628  
38629  void ssi_val_free(ssi_val_t *s) {
38630         if (s->str) buffer_free(s->str);
38631 -       
38632 +
38633         free(s);
38634  }
38635  
38636 @@ -45,175 +45,175 @@
38637                               ssi_tokenizer_t *t, int *token_id, buffer *token) {
38638         int tid = 0;
38639         size_t i;
38640 -       
38641 +
38642         UNUSED(con);
38643  
38644         for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
38645                 char c = t->input[t->offset];
38646                 data_string *ds;
38647 -               
38648 +
38649                 switch (c) {
38650 -               case '=': 
38651 +               case '=':
38652                         tid = TK_EQ;
38653 -                       
38654 +
38655                         t->offset++;
38656                         t->line_pos++;
38657 -                       
38658 +
38659                         buffer_copy_string(token, "(=)");
38660 -                       
38661 +
38662                         break;
38663                 case '>':
38664                         if (t->input[t->offset + 1] == '=') {
38665                                 t->offset += 2;
38666                                 t->line_pos += 2;
38667 -                               
38668 +
38669                                 tid = TK_GE;
38670 -                               
38671 +
38672                                 buffer_copy_string(token, "(>=)");
38673                         } else {
38674                                 t->offset += 1;
38675                                 t->line_pos += 1;
38676 -                               
38677 +
38678                                 tid = TK_GT;
38679 -                               
38680 +
38681                                 buffer_copy_string(token, "(>)");
38682                         }
38683 -                       
38684 +
38685                         break;
38686                 case '<':
38687                         if (t->input[t->offset + 1] == '=') {
38688                                 t->offset += 2;
38689                                 t->line_pos += 2;
38690 -                               
38691 +
38692                                 tid = TK_LE;
38693 -                               
38694 +
38695                                 buffer_copy_string(token, "(<=)");
38696                         } else {
38697                                 t->offset += 1;
38698                                 t->line_pos += 1;
38699 -                               
38700 +
38701                                 tid = TK_LT;
38702 -                               
38703 +
38704                                 buffer_copy_string(token, "(<)");
38705                         }
38706 -                       
38707 +
38708                         break;
38709 -                       
38710 +
38711                 case '!':
38712                         if (t->input[t->offset + 1] == '=') {
38713                                 t->offset += 2;
38714                                 t->line_pos += 2;
38715 -                               
38716 +
38717                                 tid = TK_NE;
38718 -                               
38719 +
38720                                 buffer_copy_string(token, "(!=)");
38721                         } else {
38722                                 t->offset += 1;
38723                                 t->line_pos += 1;
38724 -                               
38725 +
38726                                 tid = TK_NOT;
38727 -                               
38728 +
38729                                 buffer_copy_string(token, "(!)");
38730                         }
38731 -                       
38732 +
38733                         break;
38734                 case '&':
38735                         if (t->input[t->offset + 1] == '&') {
38736                                 t->offset += 2;
38737                                 t->line_pos += 2;
38738 -                               
38739 +
38740                                 tid = TK_AND;
38741 -                               
38742 +
38743                                 buffer_copy_string(token, "(&&)");
38744                         } else {
38745 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
38746 -                                               "pos:", t->line_pos, 
38747 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
38748 +                                               "pos:", t->line_pos,
38749                                                 "missing second &");
38750                                 return -1;
38751                         }
38752 -                       
38753 +
38754                         break;
38755                 case '|':
38756                         if (t->input[t->offset + 1] == '|') {
38757                                 t->offset += 2;
38758                                 t->line_pos += 2;
38759 -                               
38760 +
38761                                 tid = TK_OR;
38762 -                               
38763 +
38764                                 buffer_copy_string(token, "(||)");
38765                         } else {
38766 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
38767 -                                               "pos:", t->line_pos, 
38768 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
38769 +                                               "pos:", t->line_pos,
38770                                                 "missing second |");
38771                                 return -1;
38772                         }
38773 -                       
38774 +
38775                         break;
38776                 case '\t':
38777                 case ' ':
38778                         t->offset++;
38779                         t->line_pos++;
38780                         break;
38781 -                       
38782 +
38783                 case '\'':
38784                         /* search for the terminating " */
38785                         for (i = 1; t->input[t->offset + i] && t->input[t->offset + i] != '\'';  i++);
38786 -                       
38787 +
38788                         if (t->input[t->offset + i]) {
38789                                 tid = TK_VALUE;
38790 -                               
38791 +
38792                                 buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
38793 -                               
38794 +
38795                                 t->offset += i + 1;
38796                                 t->line_pos += i + 1;
38797                         } else {
38798                                 /* ERROR */
38799 -                               
38800 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
38801 -                                               "pos:", t->line_pos, 
38802 +
38803 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
38804 +                                               "pos:", t->line_pos,
38805                                                 "missing closing quote");
38806 -                               
38807 +
38808                                 return -1;
38809                         }
38810 -                       
38811 +
38812                         break;
38813                 case '(':
38814                         t->offset++;
38815                         t->in_brace++;
38816 -                               
38817 +
38818                         tid = TK_LPARAN;
38819 -                               
38820 +
38821                         buffer_copy_string(token, "(");
38822                         break;
38823                 case ')':
38824                         t->offset++;
38825                         t->in_brace--;
38826 -                               
38827 +
38828                         tid = TK_RPARAN;
38829 -                               
38830 +
38831                         buffer_copy_string(token, ")");
38832                         break;
38833                 case '$':
38834                         if (t->input[t->offset + 1] == '{') {
38835                                 for (i = 2; t->input[t->offset + i] && t->input[t->offset + i] != '}';  i++);
38836 -                               
38837 +
38838                                 if (t->input[t->offset + i] != '}') {
38839 -                                       log_error_write(srv, __FILE__, __LINE__, "sds", 
38840 -                                                       "pos:", t->line_pos, 
38841 +                                       log_error_write(srv, __FILE__, __LINE__, "sds",
38842 +                                                       "pos:", t->line_pos,
38843                                                         "missing closing quote");
38844 -                                       
38845 +
38846                                         return -1;
38847                                 }
38848 -                               
38849 +
38850                                 buffer_copy_string_len(token, t->input + t->offset + 2, i-3);
38851                         } else {
38852                                 for (i = 1; isalpha(t->input[t->offset + i]) || t->input[t->offset + i] == '_';  i++);
38853 -                               
38854 +
38855                                 buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
38856                         }
38857 -                       
38858 +
38859                         tid = TK_VALUE;
38860 -                       
38861 +
38862                         if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, token->ptr))) {
38863                                 buffer_copy_string_buffer(token, ds->value);
38864                         } else if (NULL != (ds = (data_string *)array_get_element(p->ssi_vars, token->ptr))) {
38865 @@ -221,16 +221,16 @@
38866                         } else {
38867                                 buffer_copy_string(token, "");
38868                         }
38869 -                               
38870 +
38871                         t->offset += i;
38872                         t->line_pos += i;
38873 -                       
38874 +
38875                         break;
38876                 default:
38877                         for (i = 0; isgraph(t->input[t->offset + i]);  i++) {
38878                                 char d = t->input[t->offset + i];
38879                                 switch(d) {
38880 -                               case ' ': 
38881 +                               case ' ':
38882                                 case '\t':
38883                                 case ')':
38884                                 case '(':
38885 @@ -244,25 +244,25 @@
38886                                         break;
38887                                 }
38888                         }
38889 -                       
38890 +
38891                         tid = TK_VALUE;
38892 -                               
38893 +
38894                         buffer_copy_string_len(token, t->input + t->offset, i);
38895 -                               
38896 +
38897                         t->offset += i;
38898                         t->line_pos += i;
38899 -                       
38900 +
38901                         break;
38902                 }
38903         }
38904 -                       
38905 +
38906         if (tid) {
38907                 *token_id = tid;
38908 -               
38909 +
38910                 return 1;
38911         } else if (t->offset < t->size) {
38912 -               log_error_write(srv, __FILE__, __LINE__, "sds", 
38913 -                               "pos:", t->line_pos, 
38914 +               log_error_write(srv, __FILE__, __LINE__, "sds",
38915 +                               "pos:", t->line_pos,
38916                                 "foobar");
38917         }
38918         return 0;
38919 @@ -275,50 +275,50 @@
38920         buffer *token;
38921         ssi_ctx_t context;
38922         int ret;
38923 -       
38924 +
38925         t.input = expr;
38926         t.offset = 0;
38927         t.size = strlen(expr);
38928         t.line_pos = 1;
38929 -       
38930 +
38931         t.in_key = 1;
38932         t.in_brace = 0;
38933         t.in_cond = 0;
38934 -       
38935 +
38936         context.ok = 1;
38937         context.srv = srv;
38938 -       
38939 +
38940         /* default context */
38941 -       
38942 +
38943         pParser = ssiexprparserAlloc( malloc );
38944         token = buffer_init();
38945         while((1 == (ret = ssi_expr_tokenizer(srv, con, p, &t, &token_id, token))) && context.ok) {
38946                 ssiexprparser(pParser, token_id, token, &context);
38947 -               
38948 +
38949                 token = buffer_init();
38950         }
38951         ssiexprparser(pParser, 0, token, &context);
38952         ssiexprparserFree(pParser, free );
38953 -       
38954 +
38955         buffer_free(token);
38956 -       
38957 +
38958         if (ret == -1) {
38959 -               log_error_write(srv, __FILE__, __LINE__, "s", 
38960 +               log_error_write(srv, __FILE__, __LINE__, "s",
38961                                 "expr parser failed");
38962                 return -1;
38963         }
38964 -       
38965 +
38966         if (context.ok == 0) {
38967 -               log_error_write(srv, __FILE__, __LINE__, "sds", 
38968 -                               "pos:", t.line_pos, 
38969 +               log_error_write(srv, __FILE__, __LINE__, "sds",
38970 +                               "pos:", t.line_pos,
38971                                 "parser failed somehow near here");
38972                 return -1;
38973         }
38974  #if 0
38975 -       log_error_write(srv, __FILE__, __LINE__, "ssd", 
38976 +       log_error_write(srv, __FILE__, __LINE__, "ssd",
38977                         "expr: ",
38978                         expr,
38979                         context.val.bo);
38980 -#endif 
38981 +#endif
38982         return context.val.bo;
38983  }
38984 --- ../lighttpd-1.4.11/src/mod_ssi_expr.h       2005-08-11 01:26:48.000000000 +0300
38985 +++ lighttpd-1.4.12/src/mod_ssi_expr.h  2006-07-16 00:26:04.000000000 +0300
38986 @@ -5,16 +5,16 @@
38987  
38988  typedef struct {
38989         enum { SSI_TYPE_UNSET, SSI_TYPE_BOOL, SSI_TYPE_STRING } type;
38990 -       
38991 +
38992         buffer *str;
38993         int     bo;
38994  } ssi_val_t;
38995  
38996  typedef struct {
38997         int     ok;
38998 -       
38999 +
39000         ssi_val_t val;
39001 -       
39002 +
39003         void   *srv;
39004  } ssi_ctx_t;
39005  
39006 --- ../lighttpd-1.4.11/src/mod_ssi_exprparser.c 2005-10-03 00:40:25.000000000 +0300
39007 +++ lighttpd-1.4.12/src/mod_ssi_exprparser.c    2006-07-17 22:02:23.000000000 +0300
39008 @@ -18,10 +18,10 @@
39009  /* Next is all token values, in a form suitable for use by makeheaders.
39010  ** This section will be null unless lemon is run with the -m switch.
39011  */
39012 -/* 
39013 +/*
39014  ** These constants (all generated automatically by the parser generator)
39015  ** specify the various kinds of tokens (terminals) that the parser
39016 -** understands. 
39017 +** understands.
39018  **
39019  ** Each symbol here is a terminal symbol in the grammar.
39020  */
39021 @@ -38,7 +38,7 @@
39022  **                       and nonterminals.  "int" is used otherwise.
39023  **    YYNOCODE           is a number of type YYCODETYPE which corresponds
39024  **                       to no legal terminal or nonterminal number.  This
39025 -**                       number is used to fill in empty slots of the hash 
39026 +**                       number is used to fill in empty slots of the hash
39027  **                       table.
39028  **    YYFALLBACK         If defined, this indicates that one or more tokens
39029  **                       have fall-back values which should be used if the
39030 @@ -47,7 +47,7 @@
39031  **                       and nonterminal numbers.  "unsigned char" is
39032  **                       used if there are fewer than 250 rules and
39033  **                       states combined.  "int" is used otherwise.
39034 -**    ssiexprparserTOKENTYPE     is the data type used for minor tokens given 
39035 +**    ssiexprparserTOKENTYPE     is the data type used for minor tokens given
39036  **                       directly to the parser from the tokenizer.
39037  **    YYMINORTYPE        is the data type used for all minor tokens.
39038  **                       This is typically a union of many types, one of
39039 @@ -91,7 +91,7 @@
39040  /* Next are that tables used to determine what action to take based on the
39041  ** current state and lookahead token.  These tables are used to implement
39042  ** functions that take a state number and lookahead value and return an
39043 -** action integer.  
39044 +** action integer.
39045  **
39046  ** Suppose the action integer is N.  Then the action is determined as
39047  ** follows
39048 @@ -116,7 +116,7 @@
39049  ** If the index value yy_shift_ofst[S]+X is out of range or if the value
39050  ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
39051  ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
39052 -** and that yy_default[S] should be used instead.  
39053 +** and that yy_default[S] should be used instead.
39054  **
39055  ** The formula above is for computing the action when the lookahead is
39056  ** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
39057 @@ -168,7 +168,7 @@
39058  
39059  /* The next table maps tokens into fallback tokens.  If a construct
39060  ** like the following:
39061 -** 
39062 +**
39063  **      %fallback ID X Y Z.
39064  **
39065  ** appears in the grammer, then ID becomes a fallback token for X, Y,
39066 @@ -219,10 +219,10 @@
39067  #endif /* NDEBUG */
39068  
39069  #ifndef NDEBUG
39070 -/* 
39071 +/*
39072  ** Turn parser tracing on by giving a stream to which to write the trace
39073  ** and a prompt to preface each trace message.  Tracing is turned off
39074 -** by making either argument NULL 
39075 +** by making either argument NULL
39076  **
39077  ** Inputs:
39078  ** <ul>
39079 @@ -247,7 +247,7 @@
39080  #ifndef NDEBUG
39081  /* For tracing shifts, the names of all terminals and nonterminals
39082  ** are required.  The following table supplies these names */
39083 -static const char *yyTokenName[] = { 
39084 +static const char *yyTokenName[] = {
39085    "$",             "AND",           "OR",            "EQ",          
39086    "NE",            "GT",            "GE",            "LT",          
39087    "LE",            "NOT",           "LPARAN",        "RPARAN",      
39088 @@ -295,7 +295,7 @@
39089  #endif
39090  }
39091  
39092 -/* 
39093 +/*
39094  ** This function allocates a new parser.
39095  ** The only argument is a pointer to a function which works like
39096  ** malloc.
39097 @@ -326,7 +326,7 @@
39098      /* Here is inserted the actions which take place when a
39099      ** terminal or non-terminal is destroyed.  This can happen
39100      ** when the symbol is popped from the stack during a
39101 -    ** reduce or during error processing or when a parser is 
39102 +    ** reduce or during error processing or when a parser is
39103      ** being destroyed before it is finished parsing.
39104      **
39105      ** Note: during a reduce, the only symbols destroyed are those
39106 @@ -379,7 +379,7 @@
39107    return yymajor;
39108  }
39109  
39110 -/* 
39111 +/*
39112  ** Deallocate and destroy a parser.  Destructors are all called for
39113  ** all stack elements before shutting the parser down.
39114  **
39115 @@ -415,7 +415,7 @@
39116  ){
39117    int i;
39118    int stateno = pParser->yystack[pParser->yyidx].stateno;
39119
39120 +
39121    /* if( pParser->yyidx<0 ) return YY_NO_ACTION;  */
39122    i = yy_shift_ofst[stateno];
39123    if( i==YY_SHIFT_USE_DFLT ){
39124 @@ -459,7 +459,7 @@
39125  ){
39126    int i;
39127    int stateno = pParser->yystack[pParser->yyidx].stateno;
39128
39129 +
39130    i = yy_reduce_ofst[stateno];
39131    if( i==YY_REDUCE_USE_DFLT ){
39132      return yy_default[stateno];
39133 @@ -559,7 +559,7 @@
39134    ssiexprparserARG_FETCH;
39135    yymsp = &yypParser->yystack[yypParser->yyidx];
39136  #ifndef NDEBUG
39137 -  if( yyTraceFILE && yyruleno>=0 
39138 +  if( yyTraceFILE && yyruleno>=0
39139          && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
39140      fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
39141        yyRuleName[yyruleno]);
39142 @@ -872,7 +872,7 @@
39143  #ifdef YYERRORSYMBOL
39144        /* A syntax error has occurred.
39145        ** The response to an error depends upon whether or not the
39146 -      ** grammar defines an error token "ERROR".  
39147 +      ** grammar defines an error token "ERROR".
39148        **
39149        ** This is what we do if the grammar does define ERROR:
39150        **
39151 --- ../lighttpd-1.4.11/src/mod_staticfile.c     2006-02-15 14:31:14.000000000 +0200
39152 +++ lighttpd-1.4.12/src/mod_staticfile.c        2006-07-16 00:26:03.000000000 +0300
39153 @@ -14,9 +14,11 @@
39154  #include "http_chunk.h"
39155  #include "response.h"
39156  
39157 +#include "sys-files.h"
39158 +#include "sys-strings.h"
39159  /**
39160   * this is a staticfile for a lighttpd plugin
39161 - * 
39162 + *
39163   */
39164  
39165  
39166 @@ -29,48 +31,48 @@
39167  
39168  typedef struct {
39169         PLUGIN_DATA;
39170 -       
39171 +
39172         buffer *range_buf;
39173 -       
39174 +
39175         plugin_config **config_storage;
39176 -       
39177 -       plugin_config conf; 
39178 +
39179 +       plugin_config conf;
39180  } plugin_data;
39181  
39182  /* init the plugin data */
39183  INIT_FUNC(mod_staticfile_init) {
39184         plugin_data *p;
39185 -       
39186 +
39187         p = calloc(1, sizeof(*p));
39188 -       
39189 +
39190         p->range_buf = buffer_init();
39191 -       
39192 +
39193         return p;
39194  }
39195  
39196 -/* detroy the plugin data */
39197 +/* destroy the plugin data */
39198  FREE_FUNC(mod_staticfile_free) {
39199         plugin_data *p = p_d;
39200 -       
39201 +
39202         UNUSED(srv);
39203  
39204         if (!p) return HANDLER_GO_ON;
39205 -       
39206 +
39207         if (p->config_storage) {
39208                 size_t i;
39209                 for (i = 0; i < srv->config_context->used; i++) {
39210                         plugin_config *s = p->config_storage[i];
39211 -                       
39212 +
39213                         array_free(s->exclude_ext);
39214 -                       
39215 +
39216                         free(s);
39217                 }
39218                 free(p->config_storage);
39219         }
39220         buffer_free(p->range_buf);
39221 -       
39222 +
39223         free(p);
39224 -       
39225 +
39226         return HANDLER_GO_ON;
39227  }
39228  
39229 @@ -79,63 +81,60 @@
39230  SETDEFAULTS_FUNC(mod_staticfile_set_defaults) {
39231         plugin_data *p = p_d;
39232         size_t i = 0;
39233 -       
39234 -       config_values_t cv[] = { 
39235 +
39236 +       config_values_t cv[] = {
39237                 { "static-file.exclude-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
39238                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
39239         };
39240 -       
39241 +
39242         if (!p) return HANDLER_ERROR;
39243 -       
39244 +
39245         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
39246 -       
39247 +
39248         for (i = 0; i < srv->config_context->used; i++) {
39249                 plugin_config *s;
39250 -               
39251 +
39252                 s = calloc(1, sizeof(plugin_config));
39253                 s->exclude_ext    = array_init();
39254 -               
39255 +
39256                 cv[0].destination = s->exclude_ext;
39257 -               
39258 +
39259                 p->config_storage[i] = s;
39260 -       
39261 +
39262                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
39263                         return HANDLER_ERROR;
39264                 }
39265         }
39266 -       
39267 +
39268         return HANDLER_GO_ON;
39269  }
39270  
39271 -#define PATCH(x) \
39272 -       p->conf.x = s->x;
39273  static int mod_staticfile_patch_connection(server *srv, connection *con, plugin_data *p) {
39274         size_t i, j;
39275         plugin_config *s = p->config_storage[0];
39276 -       
39277 -       PATCH(exclude_ext);
39278 -       
39279 +
39280 +       PATCH_OPTION(exclude_ext);
39281 +
39282         /* skip the first, the global context */
39283         for (i = 1; i < srv->config_context->used; i++) {
39284                 data_config *dc = (data_config *)srv->config_context->data[i];
39285                 s = p->config_storage[i];
39286 -               
39287 +
39288                 /* condition didn't match */
39289                 if (!config_check_cond(srv, con, dc)) continue;
39290 -               
39291 +
39292                 /* merge config */
39293                 for (j = 0; j < dc->value->used; j++) {
39294                         data_unset *du = dc->value->data[j];
39295 -                       
39296 +
39297                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("static-file.exclude-extensions"))) {
39298 -                               PATCH(exclude_ext);
39299 +                               PATCH_OPTION(exclude_ext);
39300                         }
39301                 }
39302         }
39303 -       
39304 +
39305         return 0;
39306  }
39307 -#undef PATCH
39308  
39309  static int http_response_parse_range(server *srv, connection *con, plugin_data *p) {
39310         int multipart = 0;
39311 @@ -146,69 +145,69 @@
39312         data_string *ds;
39313         stat_cache_entry *sce = NULL;
39314         buffer *content_type = NULL;
39315 -       
39316 +
39317         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
39318                 SEGFAULT();
39319         }
39320 -       
39321 +
39322         start = 0;
39323         end = sce->st.st_size - 1;
39324 -       
39325 +
39326         con->response.content_length = 0;
39327 -       
39328 +
39329         if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Content-Type"))) {
39330                 content_type = ds->value;
39331         }
39332 -       
39333 +
39334         for (s = con->request.http_range, error = 0;
39335              !error && *s && NULL != (minus = strchr(s, '-')); ) {
39336                 char *err;
39337                 off_t la, le;
39338 -               
39339 +
39340                 if (s == minus) {
39341                         /* -<stop> */
39342 -                       
39343 +
39344                         le = strtoll(s, &err, 10);
39345 -                       
39346 +
39347                         if (le == 0) {
39348                                 /* RFC 2616 - 14.35.1 */
39349 -                               
39350 +
39351                                 con->http_status = 416;
39352                                 error = 1;
39353                         } else if (*err == '\0') {
39354                                 /* end */
39355                                 s = err;
39356 -                               
39357 +
39358                                 end = sce->st.st_size - 1;
39359                                 start = sce->st.st_size + le;
39360                         } else if (*err == ',') {
39361                                 multipart = 1;
39362                                 s = err + 1;
39363 -                               
39364 +
39365                                 end = sce->st.st_size - 1;
39366                                 start = sce->st.st_size + le;
39367                         } else {
39368                                 error = 1;
39369                         }
39370 -                       
39371 +
39372                 } else if (*(minus+1) == '\0' || *(minus+1) == ',') {
39373                         /* <start>- */
39374 -                       
39375 +
39376                         la = strtoll(s, &err, 10);
39377 -                       
39378 +
39379                         if (err == minus) {
39380                                 /* ok */
39381 -                               
39382 +
39383                                 if (*(err + 1) == '\0') {
39384                                         s = err + 1;
39385 -                                       
39386 +
39387                                         end = sce->st.st_size - 1;
39388                                         start = la;
39389 -                                       
39390 +
39391                                 } else if (*(err + 1) == ',') {
39392                                         multipart = 1;
39393                                         s = err + 2;
39394 -                                       
39395 +
39396                                         end = sce->st.st_size - 1;
39397                                         start = la;
39398                                 } else {
39399 @@ -220,64 +219,64 @@
39400                         }
39401                 } else {
39402                         /* <start>-<stop> */
39403 -                       
39404 +
39405                         la = strtoll(s, &err, 10);
39406 -                       
39407 +
39408                         if (err == minus) {
39409                                 le = strtoll(minus+1, &err, 10);
39410 -                               
39411 +
39412                                 /* RFC 2616 - 14.35.1 */
39413                                 if (la > le) {
39414                                         error = 1;
39415                                 }
39416 -                                       
39417 +
39418                                 if (*err == '\0') {
39419                                         /* ok, end*/
39420                                         s = err;
39421 -                                       
39422 +
39423                                         end = le;
39424                                         start = la;
39425                                 } else if (*err == ',') {
39426                                         multipart = 1;
39427                                         s = err + 1;
39428 -                                       
39429 +
39430                                         end = le;
39431                                         start = la;
39432                                 } else {
39433                                         /* error */
39434 -                                       
39435 +
39436                                         error = 1;
39437                                 }
39438                         } else {
39439                                 /* error */
39440 -                               
39441 +
39442                                 error = 1;
39443                         }
39444                 }
39445 -               
39446 +
39447                 if (!error) {
39448                         if (start < 0) start = 0;
39449 -                       
39450 +
39451                         /* RFC 2616 - 14.35.1 */
39452                         if (end > sce->st.st_size - 1) end = sce->st.st_size - 1;
39453 -                       
39454 +
39455                         if (start > sce->st.st_size - 1) {
39456                                 error = 1;
39457 -                               
39458 +
39459                                 con->http_status = 416;
39460                         }
39461                 }
39462 -               
39463 +
39464                 if (!error) {
39465                         if (multipart) {
39466                                 /* write boundary-header */
39467                                 buffer *b;
39468 -                               
39469 +
39470                                 b = chunkqueue_get_append_buffer(con->write_queue);
39471 -                               
39472 +
39473                                 buffer_copy_string(b, "\r\n--");
39474                                 buffer_append_string(b, boundary);
39475 -                               
39476 +
39477                                 /* write Content-Range */
39478                                 buffer_append_string(b, "\r\nContent-Range: bytes ");
39479                                 buffer_append_off_t(b, start);
39480 @@ -285,54 +284,54 @@
39481                                 buffer_append_off_t(b, end);
39482                                 buffer_append_string(b, "/");
39483                                 buffer_append_off_t(b, sce->st.st_size);
39484 -                               
39485 +
39486                                 buffer_append_string(b, "\r\nContent-Type: ");
39487                                 buffer_append_string_buffer(b, content_type);
39488 -                               
39489 +
39490                                 /* write END-OF-HEADER */
39491                                 buffer_append_string(b, "\r\n\r\n");
39492 -                               
39493 +
39494                                 con->response.content_length += b->used - 1;
39495 -                               
39496 +
39497                         }
39498 -                       
39499 +
39500                         chunkqueue_append_file(con->write_queue, con->physical.path, start, end - start + 1);
39501                         con->response.content_length += end - start + 1;
39502                 }
39503         }
39504 -       
39505 +
39506         /* something went wrong */
39507         if (error) return -1;
39508 -       
39509 +
39510         if (multipart) {
39511                 /* add boundary end */
39512                 buffer *b;
39513 -               
39514 +
39515                 b = chunkqueue_get_append_buffer(con->write_queue);
39516 -               
39517 +
39518                 buffer_copy_string_len(b, "\r\n--", 4);
39519                 buffer_append_string(b, boundary);
39520                 buffer_append_string_len(b, "--\r\n", 4);
39521 -               
39522 +
39523                 con->response.content_length += b->used - 1;
39524 -               
39525 +
39526                 /* set header-fields */
39527 -               
39528 +
39529                 buffer_copy_string(p->range_buf, "multipart/byteranges; boundary=");
39530                 buffer_append_string(p->range_buf, boundary);
39531 -               
39532 +
39533                 /* overwrite content-type */
39534                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->range_buf));
39535         } else {
39536                 /* add Content-Range-header */
39537 -               
39538 +
39539                 buffer_copy_string(p->range_buf, "bytes ");
39540                 buffer_append_off_t(p->range_buf, start);
39541                 buffer_append_string(p->range_buf, "-");
39542                 buffer_append_off_t(p->range_buf, end);
39543                 buffer_append_string(p->range_buf, "/");
39544                 buffer_append_off_t(p->range_buf, sce->st.st_size);
39545 -               
39546 +
39547                 response_header_insert(srv, con, CONST_STR_LEN("Content-Range"), CONST_BUF_LEN(p->range_buf));
39548         }
39549  
39550 @@ -347,12 +346,12 @@
39551         stat_cache_entry *sce = NULL;
39552         buffer *mtime;
39553         data_string *ds;
39554 -       
39555 +
39556         /* someone else has done a decision for us */
39557         if (con->http_status != 0) return HANDLER_GO_ON;
39558         if (con->uri.path->used == 0) return HANDLER_GO_ON;
39559         if (con->physical.path->used == 0) return HANDLER_GO_ON;
39560 -       
39561 +
39562         /* someone else has handled this request */
39563         if (con->mode != DIRECT) return HANDLER_GO_ON;
39564  
39565 @@ -365,52 +364,52 @@
39566         default:
39567                 return HANDLER_GO_ON;
39568         }
39569 -       
39570 +
39571         mod_staticfile_patch_connection(srv, con, p);
39572 -       
39573 +
39574         s_len = con->uri.path->used - 1;
39575 -       
39576 +
39577         /* ignore certain extensions */
39578         for (k = 0; k < p->conf.exclude_ext->used; k++) {
39579 -               ds = (data_string *)p->conf.exclude_ext->data[k]; 
39580 -               
39581 +               ds = (data_string *)p->conf.exclude_ext->data[k];
39582 +
39583                 if (ds->value->used == 0) continue;
39584  
39585                 if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
39586                         return HANDLER_GO_ON;
39587                 }
39588         }
39589 -       
39590 +
39591  
39592         if (con->conf.log_request_handling) {
39593                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling file as static file");
39594         }
39595 -       
39596 +
39597         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
39598                 con->http_status = 403;
39599 -               
39600 +
39601                 log_error_write(srv, __FILE__, __LINE__, "sbsb",
39602                                 "not a regular file:", con->uri.path,
39603                                 "->", con->physical.path);
39604 -               
39605 +
39606                 return HANDLER_FINISHED;
39607         }
39608 -       
39609 -       /* we only handline regular files */
39610 +
39611 +       /* we only handle regular files */
39612         if (!S_ISREG(sce->st.st_mode)) {
39613                 con->http_status = 404;
39614 -               
39615 +
39616                 if (con->conf.log_file_not_found) {
39617                         log_error_write(srv, __FILE__, __LINE__, "sbsb",
39618                                         "not a regular file:", con->uri.path,
39619                                         "->", sce->name);
39620                 }
39621 -               
39622 +
39623                 return HANDLER_FINISHED;
39624         }
39625  
39626 -       /* mod_compress might set several data directly, don't overwrite them */
39627 -       
39628 +       /* mod_compress might set several parameters directly; don't overwrite them */
39629 +
39630         /* set response content-type, if not set already */
39631  
39632         if (NULL == array_get_element(con->response.headers, "Content-Type")) {
39633 @@ -420,15 +419,15 @@
39634                         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
39635                 }
39636         }
39637 -       
39638 +
39639         if (NULL == array_get_element(con->response.headers, "ETag")) {
39640                 /* generate e-tag */
39641                 etag_mutate(con->physical.etag, sce->etag);
39642 -       
39643 +
39644                 response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
39645         }
39646         response_header_overwrite(srv, con, CONST_STR_LEN("Accept-Ranges"), CONST_STR_LEN("bytes"));
39647 -       
39648 +
39649         /* prepare header */
39650         if (NULL == (ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"))) {
39651                 mtime = strftime_cache_get(srv, sce->st.st_mtime);
39652 @@ -444,34 +443,34 @@
39653                 /* check if we have a conditional GET */
39654  
39655                 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If-Range"))) {
39656 -                       /* if the value is the same as our ETag, we do a Range-request, 
39657 +                       /* if the value is the same as our ETag, we do a Range-request,
39658                          * otherwise a full 200 */
39659  
39660                         if (!buffer_is_equal(ds->value, con->physical.etag)) {
39661                                 do_range_request = 0;
39662                         }
39663                 }
39664 -       
39665 +
39666                 if (do_range_request) {
39667                         /* content prepared, I'm done */
39668                         con->file_finished = 1;
39669 -               
39670 +
39671                         if (0 == http_response_parse_range(srv, con, p)) {
39672                                 con->http_status = 206;
39673                         }
39674                         return HANDLER_FINISHED;
39675                 }
39676         }
39677 -       
39678 +
39679         /* if we are still here, prepare body */
39680 -       
39681 -       /* we add it here for all requests 
39682 -        * the HEAD request will drop it afterwards again 
39683 +
39684 +       /* we add it here for all requests
39685 +        * the HEAD request will drop it afterwards again
39686          */
39687         http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
39688 -       
39689 +
39690         con->file_finished = 1;
39691 -       
39692 +
39693         return HANDLER_FINISHED;
39694  }
39695  
39696 @@ -480,13 +479,13 @@
39697  int mod_staticfile_plugin_init(plugin *p) {
39698         p->version     = LIGHTTPD_VERSION_ID;
39699         p->name        = buffer_init_string("staticfile");
39700 -       
39701 +
39702         p->init        = mod_staticfile_init;
39703         p->handle_subrequest_start = mod_staticfile_subrequest;
39704         p->set_defaults  = mod_staticfile_set_defaults;
39705         p->cleanup     = mod_staticfile_free;
39706 -       
39707 +
39708         p->data        = NULL;
39709 -       
39710 +
39711         return 0;
39712  }
39713 --- ../lighttpd-1.4.11/src/mod_status.c 2006-01-10 21:45:32.000000000 +0200
39714 +++ lighttpd-1.4.12/src/mod_status.c    2006-07-16 00:26:04.000000000 +0300
39715 @@ -4,7 +4,6 @@
39716  #include <fcntl.h>
39717  #include <stdlib.h>
39718  #include <string.h>
39719 -#include <unistd.h>
39720  #include <errno.h>
39721  #include <time.h>
39722  #include <stdio.h>
39723 @@ -29,114 +28,114 @@
39724  
39725  typedef struct {
39726         PLUGIN_DATA;
39727 -       
39728 +
39729         double traffic_out;
39730         double requests;
39731 -       
39732 +
39733         double mod_5s_traffic_out[5];
39734         double mod_5s_requests[5];
39735         size_t mod_5s_ndx;
39736 -       
39737 +
39738         double rel_traffic_out;
39739         double rel_requests;
39740 -       
39741 +
39742         double abs_traffic_out;
39743         double abs_requests;
39744 -       
39745 +
39746         double bytes_written;
39747 -       
39748 +
39749         buffer *module_list;
39750 -       
39751 +
39752         plugin_config **config_storage;
39753 -       
39754 -       plugin_config conf; 
39755 +
39756 +       plugin_config conf;
39757  } plugin_data;
39758  
39759  INIT_FUNC(mod_status_init) {
39760         plugin_data *p;
39761         size_t i;
39762 -       
39763 +
39764         p = calloc(1, sizeof(*p));
39765 -       
39766 +
39767         p->traffic_out = p->requests = 0;
39768         p->rel_traffic_out = p->rel_requests = 0;
39769         p->abs_traffic_out = p->abs_requests = 0;
39770         p->bytes_written = 0;
39771         p->module_list = buffer_init();
39772 -       
39773 +
39774         for (i = 0; i < 5; i++) {
39775                 p->mod_5s_traffic_out[i] = p->mod_5s_requests[i] = 0;
39776         }
39777 -       
39778 +
39779         return p;
39780  }
39781  
39782  FREE_FUNC(mod_status_free) {
39783         plugin_data *p = p_d;
39784 -       
39785 +
39786         UNUSED(srv);
39787  
39788         if (!p) return HANDLER_GO_ON;
39789 -       
39790 +
39791         buffer_free(p->module_list);
39792 -       
39793 +
39794         if (p->config_storage) {
39795                 size_t i;
39796                 for (i = 0; i < srv->config_context->used; i++) {
39797                         plugin_config *s = p->config_storage[i];
39798 -                       
39799 +
39800                         buffer_free(s->status_url);
39801                         buffer_free(s->statistics_url);
39802                         buffer_free(s->config_url);
39803 -                       
39804 +
39805                         free(s);
39806                 }
39807                 free(p->config_storage);
39808         }
39809 -       
39810 -       
39811 +
39812 +
39813         free(p);
39814 -       
39815 +
39816         return HANDLER_GO_ON;
39817  }
39818  
39819  SETDEFAULTS_FUNC(mod_status_set_defaults) {
39820         plugin_data *p = p_d;
39821         size_t i;
39822 -       
39823 -       config_values_t cv[] = { 
39824 +
39825 +       config_values_t cv[] = {
39826                 { "status.status-url",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
39827                 { "status.config-url",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
39828                 { "status.enable-sort",          NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
39829                 { "status.statistics-url",       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
39830                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
39831         };
39832 -       
39833 +
39834         if (!p) return HANDLER_ERROR;
39835 -       
39836 +
39837         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
39838 -       
39839 +
39840         for (i = 0; i < srv->config_context->used; i++) {
39841                 plugin_config *s;
39842 -               
39843 +
39844                 s = calloc(1, sizeof(plugin_config));
39845                 s->config_url    = buffer_init();
39846                 s->status_url    = buffer_init();
39847                 s->sort          = 1;
39848                 s->statistics_url    = buffer_init();
39849 -               
39850 +
39851                 cv[0].destination = s->status_url;
39852                 cv[1].destination = s->config_url;
39853                 cv[2].destination = &(s->sort);
39854                 cv[3].destination = s->statistics_url;
39855 -               
39856 +
39857                 p->config_storage[i] = s;
39858 -       
39859 +
39860                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
39861                         return HANDLER_ERROR;
39862                 }
39863         }
39864 -       
39865 +
39866         return HANDLER_GO_ON;
39867  }
39868  
39869 @@ -151,7 +150,7 @@
39870         buffer_append_string(b, value);
39871         BUFFER_APPEND_STRING_CONST(b, "</td>\n");
39872         BUFFER_APPEND_STRING_CONST(b, "   </tr>\n");
39873 -       
39874 +
39875         return 0;
39876  }
39877  
39878 @@ -161,13 +160,13 @@
39879         buffer_append_string(b, key);
39880         BUFFER_APPEND_STRING_CONST(b, "</th>\n");
39881         BUFFER_APPEND_STRING_CONST(b, "   </tr>\n");
39882 -       
39883 +
39884         return 0;
39885  }
39886  
39887  static int mod_status_header_append_sort(buffer *b, void *p_d, const char* key) {
39888         plugin_data *p = p_d;
39889 -       
39890 +
39891         if (p->conf.sort) {
39892                 BUFFER_APPEND_STRING_CONST(b, "<th class=\"status\"><a href=\"#\" class=\"sortheader\" onclick=\"resort(this);return false;\">");
39893                 buffer_append_string(b, key);
39894 @@ -177,13 +176,13 @@
39895                 buffer_append_string(b, key);
39896                 BUFFER_APPEND_STRING_CONST(b, "</th>\n");
39897         }
39898 -       
39899 +
39900         return 0;
39901  }
39902  
39903  static int mod_status_get_multiplier(double *avg, char *multiplier, int size) {
39904         *multiplier = ' ';
39905 -       
39906 +
39907         if (*avg > size) { *avg /= size; *multiplier = 'k'; }
39908         if (*avg > size) { *avg /= size; *multiplier = 'M'; }
39909         if (*avg > size) { *avg /= size; *multiplier = 'G'; }
39910 @@ -202,21 +201,21 @@
39911         size_t j;
39912         double avg;
39913         char multiplier = '\0';
39914 -       char buf[32];
39915 +       char buf[128];
39916         time_t ts;
39917 -       
39918 +
39919         int days, hours, mins, seconds;
39920 -       
39921 +
39922         b = chunkqueue_get_append_buffer(con->write_queue);
39923  
39924 -       BUFFER_COPY_STRING_CONST(b, 
39925 +       BUFFER_COPY_STRING_CONST(b,
39926                                  "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
39927                                  "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
39928                                  "         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
39929                                  "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
39930                                  " <head>\n"
39931                                  "  <title>Status</title>\n");
39932 -       
39933 +
39934         BUFFER_APPEND_STRING_CONST(b,
39935                                    "  <style type=\"text/css\">\n"
39936                                    "    table.status { border: black solid thin; }\n"
39937 @@ -226,14 +225,14 @@
39938                                    "    a.sortheader { background-color: black; color: white; font-weight: bold; text-decoration: none; display: block; }\n"
39939                                    "    span.sortarrow { color: white; text-decoration: none; }\n"
39940                                    "  </style>\n");
39941 -       
39942 +
39943         if (p->conf.sort) {
39944                 BUFFER_APPEND_STRING_CONST(b,
39945                                            "<script type=\"text/javascript\">\n"
39946                                            "// <!--\n"
39947                                            "var sort_column;\n"
39948                                            "var prev_span = null;\n");
39949 -               
39950 +
39951                 BUFFER_APPEND_STRING_CONST(b,
39952                                            "function get_inner_text(el) {\n"
39953                                            " if((typeof el == 'string')||(typeof el == 'undefined'))\n"
39954 @@ -251,7 +250,7 @@
39955                                            " }\n"
39956                                            " return str;\n"
39957                                            "}\n");
39958 -               
39959 +
39960                 BUFFER_APPEND_STRING_CONST(b,
39961                                            "function sortfn(a,b) {\n"
39962                                            " var at = get_inner_text(a.cells[sort_column]);\n"
39963 @@ -266,7 +265,7 @@
39964                                            "  else return 1;\n"
39965                                            " }\n"
39966                                            "}\n");
39967 -               
39968 +
39969                 BUFFER_APPEND_STRING_CONST(b,
39970                                            "function resort(lnk) {\n"
39971                                            " var span = lnk.childNodes[1];\n"
39972 @@ -276,7 +275,7 @@
39973                                            "  rows[j-1] = table.rows[j];\n"
39974                                            " sort_column = lnk.parentNode.cellIndex;\n"
39975                                            " rows.sort(sortfn);\n");
39976 -               
39977 +
39978                 BUFFER_APPEND_STRING_CONST(b,
39979                                            " if (prev_span != null) prev_span.innerHTML = '';\n"
39980                                            " if (span.getAttribute('sortdir')=='down') {\n"
39981 @@ -294,175 +293,175 @@
39982                                            "// -->\n"
39983                                            "</script>\n");
39984         }
39985 -       
39986 -       BUFFER_APPEND_STRING_CONST(b, 
39987 +
39988 +       BUFFER_APPEND_STRING_CONST(b,
39989                                  " </head>\n"
39990                                  " <body>\n");
39991 -       
39992 -       
39993 -       
39994 +
39995 +
39996 +
39997         /* connection listing */
39998         BUFFER_APPEND_STRING_CONST(b, "<h1>Server-Status</h1>");
39999 -       
40000 -       BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\">");
40001 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Hostname</td><td class=\"string\">");
40002 +
40003 +       BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\" id=\"status\" summary=\"Server Status\">");
40004 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Hostname</td><td class=\"string\"><span id=\"host_addr\">");
40005         buffer_append_string_buffer(b, con->uri.authority);
40006 -       BUFFER_APPEND_STRING_CONST(b, " (");
40007 +       BUFFER_APPEND_STRING_CONST(b, "</span> (<span id=\"host_name\">");
40008         buffer_append_string_buffer(b, con->server_name);
40009 -       BUFFER_APPEND_STRING_CONST(b, ")</td></tr>\n");
40010 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Uptime</td><td class=\"string\">");
40011 -       
40012 +       BUFFER_APPEND_STRING_CONST(b, "</span>)</td></tr>\n");
40013 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Uptime</td><td class=\"string\" id=\"uptime\">");
40014 +
40015         ts = srv->cur_ts - srv->startup_ts;
40016 -       
40017 +
40018         days = ts / (60 * 60 * 24);
40019         ts %= (60 * 60 * 24);
40020 -       
40021 +
40022         hours = ts / (60 * 60);
40023         ts %= (60 * 60);
40024 -       
40025 +
40026         mins = ts / (60);
40027         ts %= (60);
40028 -       
40029 +
40030         seconds = ts;
40031 -       
40032 +
40033         if (days) {
40034                 buffer_append_long(b, days);
40035                 BUFFER_APPEND_STRING_CONST(b, " days ");
40036         }
40037 -       
40038 +
40039         if (hours) {
40040                 buffer_append_long(b, hours);
40041                 BUFFER_APPEND_STRING_CONST(b, " hours ");
40042         }
40043 -       
40044 +
40045         if (mins) {
40046                 buffer_append_long(b, mins);
40047                 BUFFER_APPEND_STRING_CONST(b, " min ");
40048         }
40049 -       
40050 +
40051         buffer_append_long(b, seconds);
40052         BUFFER_APPEND_STRING_CONST(b, " s");
40053 -       
40054 +
40055         BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
40056         BUFFER_APPEND_STRING_CONST(b, "<tr><td>Started at</td><td class=\"string\">");
40057 -       
40058 +
40059         ts = srv->startup_ts;
40060 -       
40061 -       strftime(buf, sizeof(buf) - 1, "%Y-%m-%d %H:%M:%S", localtime(&ts));
40062 +
40063 +       strftime(buf, sizeof(buf) - 1, "<span id=\"start_date\">%Y-%m-%d</span> <span id=\"start_time\">%H:%M:%S</span>", localtime(&ts));
40064         buffer_append_string(b, buf);
40065         BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
40066 -       
40067 -       
40068 +
40069 +
40070         BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">absolute (since start)</th></tr>\n");
40071 -       
40072 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
40073 +
40074 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\" ><span id=\"requests\">");
40075         avg = p->abs_requests;
40076  
40077         mod_status_get_multiplier(&avg, &multiplier, 1000);
40078 -       
40079 +
40080         buffer_append_long(b, avg);
40081 -       BUFFER_APPEND_STRING_CONST(b, " ");
40082 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_mult\">");
40083         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40084 -       BUFFER_APPEND_STRING_CONST(b, "req</td></tr>\n");
40085 -       
40086 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
40087 +       BUFFER_APPEND_STRING_CONST(b, "</span>req</td></tr>\n");
40088 +
40089 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"traffic\">");
40090         avg = p->abs_traffic_out;
40091  
40092         mod_status_get_multiplier(&avg, &multiplier, 1024);
40093  
40094         sprintf(buf, "%.2f", avg);
40095         buffer_append_string(b, buf);
40096 -       BUFFER_APPEND_STRING_CONST(b, " ");
40097 +       BUFFER_APPEND_STRING_CONST(b, "</span>  <span id=\"traffic_mult\">");
40098         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40099 -       BUFFER_APPEND_STRING_CONST(b, "byte</td></tr>\n");
40100 +       BUFFER_APPEND_STRING_CONST(b, "</span>byte</td></tr>\n");
40101  
40102  
40103  
40104         BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (since start)</th></tr>\n");
40105 -       
40106 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
40107 +
40108 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\"><span id=\"requests_avg\">");
40109         avg = p->abs_requests / (srv->cur_ts - srv->startup_ts);
40110  
40111         mod_status_get_multiplier(&avg, &multiplier, 1000);
40112  
40113         buffer_append_long(b, avg);
40114 -       BUFFER_APPEND_STRING_CONST(b, " ");
40115 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_avg_mult\">");
40116         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40117 -       BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n");
40118 -       
40119 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
40120 +       BUFFER_APPEND_STRING_CONST(b, "</span>req/s</td></tr>\n");
40121 +
40122 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"traffic_avg\">");
40123         avg = p->abs_traffic_out / (srv->cur_ts - srv->startup_ts);
40124  
40125         mod_status_get_multiplier(&avg, &multiplier, 1024);
40126  
40127         sprintf(buf, "%.2f", avg);
40128         buffer_append_string(b, buf);
40129 -       BUFFER_APPEND_STRING_CONST(b, " ");
40130 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"traffic_avg_mult\">");
40131         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40132 -       BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n");
40133 +       BUFFER_APPEND_STRING_CONST(b, "</span>byte/s</td></tr>\n");
40134 +
40135 +
40136  
40137 -       
40138 -       
40139         BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (5s sliding average)</th></tr>\n");
40140         for (j = 0, avg = 0; j < 5; j++) {
40141                 avg += p->mod_5s_requests[j];
40142         }
40143 -       
40144 +
40145         avg /= 5;
40146 -       
40147 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
40148 +
40149 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\"><span id=\"requests_sliding_avg\">");
40150  
40151         mod_status_get_multiplier(&avg, &multiplier, 1000);
40152  
40153         buffer_append_long(b, avg);
40154 -       BUFFER_APPEND_STRING_CONST(b, " ");
40155 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_sliding_avg_mult\">");
40156         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40157 -       
40158 -       BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n");
40159 -       
40160 +
40161 +       BUFFER_APPEND_STRING_CONST(b, "</span>req/s</td></tr>\n");
40162 +
40163         for (j = 0, avg = 0; j < 5; j++) {
40164                 avg += p->mod_5s_traffic_out[j];
40165         }
40166 -       
40167 +
40168         avg /= 5;
40169 -       
40170 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
40171 +
40172 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"requests_sliding_traffic\">");
40173  
40174         mod_status_get_multiplier(&avg, &multiplier, 1024);
40175  
40176         sprintf(buf, "%.2f", avg);
40177         buffer_append_string(b, buf);
40178 -       BUFFER_APPEND_STRING_CONST(b, " ");
40179 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_sliding_traffic_mult\">");
40180         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40181 -       BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n");
40182 -       
40183 +       BUFFER_APPEND_STRING_CONST(b, "</span>byte/s</td></tr>\n");
40184 +
40185         BUFFER_APPEND_STRING_CONST(b, "</table>\n");
40186 -       
40187 -       
40188 +
40189 +
40190         BUFFER_APPEND_STRING_CONST(b, "<hr />\n<pre><b>legend</b>\n");
40191         BUFFER_APPEND_STRING_CONST(b, ". = connect, C = close, E = hard error\n");
40192         BUFFER_APPEND_STRING_CONST(b, "r = read, R = read-POST, W = write, h = handle-request\n");
40193         BUFFER_APPEND_STRING_CONST(b, "q = request-start,  Q = request-end\n");
40194         BUFFER_APPEND_STRING_CONST(b, "s = response-start, S = response-end\n");
40195 -       
40196 -       BUFFER_APPEND_STRING_CONST(b, "<b>");
40197 +
40198 +       BUFFER_APPEND_STRING_CONST(b, "<strong><span id=\"connections\">");
40199         buffer_append_long(b, srv->conns->used);
40200 -       BUFFER_APPEND_STRING_CONST(b, " connections</b>\n");
40201 -       
40202 +       BUFFER_APPEND_STRING_CONST(b, "</span> connections</strong>\n");
40203 +
40204         for (j = 0; j < srv->conns->used; j++) {
40205                 connection *c = srv->conns->ptr[j];
40206                 const char *state = connection_get_short_state(c->state);
40207 -               
40208 +
40209                 buffer_append_string_len(b, state, 1);
40210 -               
40211 +
40212                 if (((j + 1) % 50) == 0) {
40213                         BUFFER_APPEND_STRING_CONST(b, "\n");
40214                 }
40215         }
40216 -       
40217 +
40218         BUFFER_APPEND_STRING_CONST(b, "\n</pre><hr />\n<h2>Connections</h2>\n");
40219 -       
40220 -       BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\">\n");
40221 +
40222 +       BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\" summary=\"Current connections\" id=\"clients\">\n");
40223         BUFFER_APPEND_STRING_CONST(b, "<tr>");
40224         mod_status_header_append_sort(b, p_d, "Client IP");
40225         mod_status_header_append_sort(b, p_d, "Read");
40226 @@ -473,16 +472,16 @@
40227         mod_status_header_append_sort(b, p_d, "URI");
40228         mod_status_header_append_sort(b, p_d, "File");
40229         BUFFER_APPEND_STRING_CONST(b, "</tr>\n");
40230 -       
40231 +
40232         for (j = 0; j < srv->conns->used; j++) {
40233                 connection *c = srv->conns->ptr[j];
40234 -               
40235 -               BUFFER_APPEND_STRING_CONST(b, "<tr><td class=\"string\">");
40236 -               
40237 +
40238 +               BUFFER_APPEND_STRING_CONST(b, "<tr><td class=\"string ip\">");
40239 +
40240                 buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(c->dst_addr)));
40241 -               
40242 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
40243 -               
40244 +
40245 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int bytes_read\">");
40246 +
40247                 if (con->request.content_length) {
40248                         buffer_append_long(b, c->request_content_queue->bytes_in);
40249                         BUFFER_APPEND_STRING_CONST(b, "/");
40250 @@ -490,55 +489,55 @@
40251                 } else {
40252                         BUFFER_APPEND_STRING_CONST(b, "0/0");
40253                 }
40254 -       
40255 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
40256 -               
40257 +
40258 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int bytes_written\">");
40259 +
40260                 buffer_append_off_t(b, chunkqueue_written(c->write_queue));
40261                 BUFFER_APPEND_STRING_CONST(b, "/");
40262                 buffer_append_off_t(b, chunkqueue_length(c->write_queue));
40263 -               
40264 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40265 -               
40266 +
40267 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string state\">");
40268 +
40269                 buffer_append_string(b, connection_get_state(c->state));
40270 -               
40271 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
40272 -               
40273 +
40274 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int time\">");
40275 +
40276                 buffer_append_long(b, srv->cur_ts - c->request_start);
40277 -               
40278 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40279 -               
40280 +
40281 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string host\">");
40282 +
40283                 if (buffer_is_empty(c->server_name)) {
40284                         buffer_append_string_buffer(b, c->uri.authority);
40285                 }
40286                 else {
40287                         buffer_append_string_buffer(b, c->server_name);
40288                 }
40289 -               
40290 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40291 -               
40292 +
40293 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string uri\">");
40294 +
40295                 if (!buffer_is_empty(c->uri.path)) {
40296                         buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.path), ENCODING_HTML);
40297                 }
40298 -               
40299 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40300 -               
40301 +
40302 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string file\">");
40303 +
40304                 buffer_append_string_buffer(b, c->physical.path);
40305 -               
40306 +
40307                 BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
40308         }
40309 -       
40310 -       
40311 -       BUFFER_APPEND_STRING_CONST(b, 
40312 +
40313 +
40314 +       BUFFER_APPEND_STRING_CONST(b,
40315                       "</table>\n");
40316 -       
40317 -       
40318 -       BUFFER_APPEND_STRING_CONST(b, 
40319 +
40320 +
40321 +       BUFFER_APPEND_STRING_CONST(b,
40322                       " </body>\n"
40323                       "</html>\n"
40324                       );
40325 -       
40326 +
40327         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
40328 -       
40329 +
40330         return 0;
40331  }
40332  
40333 @@ -548,7 +547,7 @@
40334         buffer *b;
40335         double avg;
40336         time_t ts;
40337 -       
40338 +
40339         b = chunkqueue_get_append_buffer(con->write_queue);
40340  
40341         /* output total number of requests */
40342 @@ -556,19 +555,19 @@
40343         avg = p->abs_requests;
40344         buffer_append_long(b, avg);
40345         BUFFER_APPEND_STRING_CONST(b, "\n");
40346 -       
40347 +
40348         /* output total traffic out in kbytes */
40349         BUFFER_APPEND_STRING_CONST(b, "Total kBytes: ");
40350         avg = p->abs_traffic_out / 1024;
40351         buffer_append_long(b, avg);
40352         BUFFER_APPEND_STRING_CONST(b, "\n");
40353 -       
40354 +
40355         /* output uptime */
40356         BUFFER_APPEND_STRING_CONST(b, "Uptime: ");
40357         ts = srv->cur_ts - srv->startup_ts;
40358         buffer_append_long(b, ts);
40359         BUFFER_APPEND_STRING_CONST(b, "\n");
40360 -       
40361 +
40362         /* output busy servers */
40363         BUFFER_APPEND_STRING_CONST(b, "BusyServers: ");
40364         buffer_append_long(b, srv->conns->used);
40365 @@ -577,7 +576,7 @@
40366         /* set text/plain output */
40367  
40368         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
40369 -       
40370 +
40371         return 0;
40372  }
40373  
40374 @@ -591,10 +590,10 @@
40375                 /* we have nothing to send */
40376                 con->http_status = 204;
40377                 con->file_finished = 1;
40378 -       
40379 +
40380                 return HANDLER_FINISHED;
40381         }
40382 -       
40383 +
40384         b = chunkqueue_get_append_buffer(con->write_queue);
40385  
40386         for (i = 0; i < st->used; i++) {
40387 @@ -605,27 +604,27 @@
40388                 buffer_append_long(b, ((data_integer *)(st->data[ndx]))->value);
40389                 buffer_append_string(b, "\n");
40390         }
40391 -       
40392 +
40393         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
40394 -       
40395 +
40396         con->http_status = 200;
40397         con->file_finished = 1;
40398 -       
40399 +
40400         return HANDLER_FINISHED;
40401  }
40402  
40403  
40404  static handler_t mod_status_handle_server_status(server *srv, connection *con, void *p_d) {
40405 -       
40406 +
40407         if (buffer_is_equal_string(con->uri.query, CONST_STR_LEN("auto"))) {
40408                 mod_status_handle_server_status_text(srv, con, p_d);
40409         } else {
40410                 mod_status_handle_server_status_html(srv, con, p_d);
40411         }
40412 -       
40413 +
40414         con->http_status = 200;
40415         con->file_finished = 1;
40416 -       
40417 +
40418         return HANDLER_FINISHED;
40419  }
40420  
40421 @@ -634,9 +633,9 @@
40422         plugin_data *p = p_d;
40423         buffer *b, *m = p->module_list;
40424         size_t i;
40425 -       
40426 -       struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] = 
40427 -       { 
40428 +
40429 +       struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
40430 +       {
40431                 /* - poll is most reliable
40432                  * - select works everywhere
40433                  * - linux-* are experimental
40434 @@ -661,10 +660,10 @@
40435  #endif
40436                 { FDEVENT_HANDLER_UNSET,          NULL }
40437         };
40438 -       
40439 +
40440         b = chunkqueue_get_append_buffer(con->write_queue);
40441 -       
40442 -       BUFFER_COPY_STRING_CONST(b, 
40443 +
40444 +       BUFFER_COPY_STRING_CONST(b,
40445                            "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
40446                            "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
40447                            "         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
40448 @@ -675,7 +674,7 @@
40449                            " <body>\n"
40450                            "  <h1>" PACKAGE_NAME " " PACKAGE_VERSION "</h1>\n"
40451                            "  <table border=\"1\">\n");
40452 -       
40453 +
40454         mod_status_header_append(b, "Server-Features");
40455  #ifdef HAVE_PCRE_H
40456         mod_status_row_append(b, "RegEx Conditionals", "enabled");
40457 @@ -683,21 +682,21 @@
40458         mod_status_row_append(b, "RegEx Conditionals", "disabled - pcre missing");
40459  #endif
40460         mod_status_header_append(b, "Network Engine");
40461 -       
40462 +
40463         for (i = 0; event_handlers[i].name; i++) {
40464                 if (event_handlers[i].et == srv->event_handler) {
40465                         mod_status_row_append(b, "fd-Event-Handler", event_handlers[i].name);
40466                         break;
40467                 }
40468         }
40469 -       
40470 +
40471         mod_status_header_append(b, "Config-File-Settings");
40472 -       
40473 +
40474         for (i = 0; i < srv->plugins.used; i++) {
40475                 plugin **ps = srv->plugins.ptr;
40476 -               
40477 +
40478                 plugin *pl = ps[i];
40479 -       
40480 +
40481                 if (i == 0) {
40482                         buffer_copy_string_buffer(m, pl->name);
40483                 } else {
40484 @@ -705,137 +704,135 @@
40485                         buffer_append_string_buffer(m, pl->name);
40486                 }
40487         }
40488 -       
40489 +
40490         mod_status_row_append(b, "Loaded Modules", m->ptr);
40491 -       
40492 +
40493         BUFFER_APPEND_STRING_CONST(b, "  </table>\n");
40494 -       
40495 -       BUFFER_APPEND_STRING_CONST(b, 
40496 +
40497 +       BUFFER_APPEND_STRING_CONST(b,
40498                       " </body>\n"
40499                       "</html>\n"
40500                       );
40501 -       
40502 +
40503         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
40504 -       
40505 +
40506         con->http_status = 200;
40507         con->file_finished = 1;
40508 -       
40509 +
40510         return HANDLER_FINISHED;
40511  }
40512  
40513 -#define PATCH(x) \
40514 -       p->conf.x = s->x;
40515  static int mod_status_patch_connection(server *srv, connection *con, plugin_data *p) {
40516         size_t i, j;
40517         plugin_config *s = p->config_storage[0];
40518 -       
40519 -       PATCH(status_url);
40520 -       PATCH(config_url);
40521 -       PATCH(sort);
40522 -       PATCH(statistics_url);
40523 -       
40524 +
40525 +       PATCH_OPTION(status_url);
40526 +       PATCH_OPTION(config_url);
40527 +       PATCH_OPTION(sort);
40528 +       PATCH_OPTION(statistics_url);
40529 +
40530         /* skip the first, the global context */
40531         for (i = 1; i < srv->config_context->used; i++) {
40532                 data_config *dc = (data_config *)srv->config_context->data[i];
40533                 s = p->config_storage[i];
40534 -               
40535 +
40536                 /* condition didn't match */
40537                 if (!config_check_cond(srv, con, dc)) continue;
40538 -               
40539 +
40540                 /* merge config */
40541                 for (j = 0; j < dc->value->used; j++) {
40542                         data_unset *du = dc->value->data[j];
40543 -                       
40544 +
40545                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.status-url"))) {
40546 -                               PATCH(status_url);
40547 +                               PATCH_OPTION(status_url);
40548                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.config-url"))) {
40549 -                               PATCH(config_url);
40550 +                               PATCH_OPTION(config_url);
40551                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.enable-sort"))) {
40552 -                               PATCH(sort);
40553 +                               PATCH_OPTION(sort);
40554                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.statistics-url"))) {
40555 -                               PATCH(statistics_url);
40556 -                       } 
40557 +                               PATCH_OPTION(statistics_url);
40558 +                       }
40559                 }
40560         }
40561 -       
40562 +
40563         return 0;
40564  }
40565  
40566  static handler_t mod_status_handler(server *srv, connection *con, void *p_d) {
40567         plugin_data *p = p_d;
40568 -       
40569 +
40570         mod_status_patch_connection(srv, con, p);
40571 -       
40572 -       if (!buffer_is_empty(p->conf.status_url) && 
40573 +
40574 +       if (!buffer_is_empty(p->conf.status_url) &&
40575             buffer_is_equal(p->conf.status_url, con->uri.path)) {
40576                 return mod_status_handle_server_status(srv, con, p_d);
40577 -       } else if (!buffer_is_empty(p->conf.config_url) && 
40578 +       } else if (!buffer_is_empty(p->conf.config_url) &&
40579             buffer_is_equal(p->conf.config_url, con->uri.path)) {
40580                 return mod_status_handle_server_config(srv, con, p_d);
40581 -       } else if (!buffer_is_empty(p->conf.statistics_url) && 
40582 +       } else if (!buffer_is_empty(p->conf.statistics_url) &&
40583             buffer_is_equal(p->conf.statistics_url, con->uri.path)) {
40584                 return mod_status_handle_server_statistics(srv, con, p_d);
40585         }
40586 -       
40587 +
40588         return HANDLER_GO_ON;
40589  }
40590  
40591  TRIGGER_FUNC(mod_status_trigger) {
40592         plugin_data *p = p_d;
40593         size_t i;
40594 -       
40595 +
40596         /* check all connections */
40597         for (i = 0; i < srv->conns->used; i++) {
40598                 connection *c = srv->conns->ptr[i];
40599 -               
40600 +
40601                 p->bytes_written += c->bytes_written_cur_second;
40602         }
40603 -       
40604 +
40605         /* a sliding average */
40606         p->mod_5s_traffic_out[p->mod_5s_ndx] = p->bytes_written;
40607         p->mod_5s_requests   [p->mod_5s_ndx] = p->requests;
40608 -       
40609 +
40610         p->mod_5s_ndx = (p->mod_5s_ndx+1) % 5;
40611 -       
40612 +
40613         p->abs_traffic_out += p->bytes_written;
40614         p->rel_traffic_out += p->bytes_written;
40615 -       
40616 +
40617         p->bytes_written = 0;
40618 -       
40619 +
40620         /* reset storage - second */
40621         p->traffic_out = 0;
40622         p->requests    = 0;
40623 -       
40624 +
40625         return HANDLER_GO_ON;
40626  }
40627  
40628  REQUESTDONE_FUNC(mod_status_account) {
40629         plugin_data *p = p_d;
40630 -       
40631 +
40632         UNUSED(srv);
40633  
40634         p->requests++;
40635         p->rel_requests++;
40636         p->abs_requests++;
40637 -       
40638 +
40639         p->bytes_written += con->bytes_written_cur_second;
40640 -       
40641 +
40642         return HANDLER_GO_ON;
40643  }
40644  
40645  int mod_status_plugin_init(plugin *p) {
40646         p->version     = LIGHTTPD_VERSION_ID;
40647         p->name        = buffer_init_string("status");
40648 -       
40649 +
40650         p->init        = mod_status_init;
40651         p->cleanup     = mod_status_free;
40652         p->set_defaults= mod_status_set_defaults;
40653 -       
40654 +
40655         p->handle_uri_clean    = mod_status_handler;
40656         p->handle_trigger      = mod_status_trigger;
40657         p->handle_request_done = mod_status_account;
40658 -       
40659 +
40660         p->data        = NULL;
40661 -       
40662 +
40663         return 0;
40664  }
40665 --- ../lighttpd-1.4.11/src/mod_trigger_b4_dl.c  2005-09-23 22:53:55.000000000 +0300
40666 +++ lighttpd-1.4.12/src/mod_trigger_b4_dl.c     2006-07-16 00:26:03.000000000 +0300
40667 @@ -24,18 +24,18 @@
40668  
40669  /**
40670   * this is a trigger_b4_dl for a lighttpd plugin
40671 - * 
40672 + *
40673   */
40674  
40675  /* plugin config for all request/connections */
40676  
40677  typedef struct {
40678         buffer *db_filename;
40679 -       
40680 +
40681         buffer *trigger_url;
40682         buffer *download_url;
40683         buffer *deny_url;
40684 -       
40685 +
40686         array  *mc_hosts;
40687         buffer *mc_namespace;
40688  #if defined(HAVE_PCRE_H)
40689 @@ -46,58 +46,58 @@
40690         GDBM_FILE db;
40691  #endif
40692  
40693 -#if defined(HAVE_MEMCACHE_H) 
40694 +#if defined(HAVE_MEMCACHE_H)
40695         struct memcache *mc;
40696  #endif
40697 -       
40698 +
40699         unsigned short trigger_timeout;
40700         unsigned short debug;
40701  } plugin_config;
40702  
40703  typedef struct {
40704         PLUGIN_DATA;
40705 -       
40706 +
40707         buffer *tmp_buf;
40708 -       
40709 +
40710         plugin_config **config_storage;
40711 -       
40712 -       plugin_config conf; 
40713 +
40714 +       plugin_config conf;
40715  } plugin_data;
40716  
40717  /* init the plugin data */
40718  INIT_FUNC(mod_trigger_b4_dl_init) {
40719         plugin_data *p;
40720 -       
40721 +
40722         p = calloc(1, sizeof(*p));
40723 -       
40724 +
40725         p->tmp_buf = buffer_init();
40726 -       
40727 +
40728         return p;
40729  }
40730  
40731  /* detroy the plugin data */
40732  FREE_FUNC(mod_trigger_b4_dl_free) {
40733         plugin_data *p = p_d;
40734 -       
40735 +
40736         UNUSED(srv);
40737  
40738         if (!p) return HANDLER_GO_ON;
40739 -       
40740 +
40741         if (p->config_storage) {
40742                 size_t i;
40743                 for (i = 0; i < srv->config_context->used; i++) {
40744                         plugin_config *s = p->config_storage[i];
40745  
40746                         if (!s) continue;
40747 -                       
40748 +
40749                         buffer_free(s->db_filename);
40750                         buffer_free(s->download_url);
40751                         buffer_free(s->trigger_url);
40752                         buffer_free(s->deny_url);
40753 -                       
40754 +
40755                         buffer_free(s->mc_namespace);
40756                         array_free(s->mc_hosts);
40757 -                       
40758 +
40759  #if defined(HAVE_PCRE_H)
40760                         if (s->trigger_regex) pcre_free(s->trigger_regex);
40761                         if (s->download_regex) pcre_free(s->download_regex);
40762 @@ -108,16 +108,16 @@
40763  #if defined(HAVE_MEMCACHE_H)
40764                         if (s->mc) mc_free(s->mc);
40765  #endif
40766 -                       
40767 +
40768                         free(s);
40769                 }
40770                 free(p->config_storage);
40771         }
40772 -       
40773 +
40774         buffer_free(p->tmp_buf);
40775 -       
40776 +
40777         free(p);
40778 -       
40779 +
40780         return HANDLER_GO_ON;
40781  }
40782  
40783 @@ -126,9 +126,9 @@
40784  SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) {
40785         plugin_data *p = p_d;
40786         size_t i = 0;
40787 -       
40788 -       
40789 -       config_values_t cv[] = { 
40790 +
40791 +
40792 +       config_values_t cv[] = {
40793                 { "trigger-before-download.gdbm-filename",   NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
40794                 { "trigger-before-download.trigger-url",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
40795                 { "trigger-before-download.download-url",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
40796 @@ -139,18 +139,18 @@
40797                 { "trigger-before-download.debug",           NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 7 */
40798                 { NULL,                        NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
40799         };
40800 -       
40801 +
40802         if (!p) return HANDLER_ERROR;
40803 -       
40804 +
40805         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
40806 -       
40807 +
40808         for (i = 0; i < srv->config_context->used; i++) {
40809                 plugin_config *s;
40810  #if defined(HAVE_PCRE_H)
40811                 const char *errptr;
40812                 int erroff;
40813  #endif
40814 -               
40815 +
40816                 s = calloc(1, sizeof(plugin_config));
40817                 s->db_filename    = buffer_init();
40818                 s->download_url   = buffer_init();
40819 @@ -158,7 +158,7 @@
40820                 s->deny_url       = buffer_init();
40821                 s->mc_hosts       = array_init();
40822                 s->mc_namespace   = buffer_init();
40823 -               
40824 +
40825                 cv[0].destination = s->db_filename;
40826                 cv[1].destination = s->trigger_url;
40827                 cv[2].destination = s->download_url;
40828 @@ -167,41 +167,41 @@
40829                 cv[5].destination = s->mc_hosts;
40830                 cv[6].destination = s->mc_namespace;
40831                 cv[7].destination = &(s->debug);
40832 -               
40833 +
40834                 p->config_storage[i] = s;
40835 -       
40836 +
40837                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
40838                         return HANDLER_ERROR;
40839                 }
40840  #if defined(HAVE_GDBM_H)
40841                 if (!buffer_is_empty(s->db_filename)) {
40842                         if (NULL == (s->db = gdbm_open(s->db_filename->ptr, 4096, GDBM_WRCREAT | GDBM_NOLOCK, S_IRUSR | S_IWUSR, 0))) {
40843 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
40844 +                               log_error_write(srv, __FILE__, __LINE__, "s",
40845                                                 "gdbm-open failed");
40846                                 return HANDLER_ERROR;
40847                         }
40848                 }
40849  #endif
40850 -#if defined(HAVE_PCRE_H)               
40851 +#if defined(HAVE_PCRE_H)
40852                 if (!buffer_is_empty(s->download_url)) {
40853                         if (NULL == (s->download_regex = pcre_compile(s->download_url->ptr,
40854                                                                       0, &errptr, &erroff, NULL))) {
40855 -                               
40856 -                               log_error_write(srv, __FILE__, __LINE__, "sbss", 
40857 -                                               "compiling regex for download-url failed:", 
40858 +
40859 +                               log_error_write(srv, __FILE__, __LINE__, "sbss",
40860 +                                               "compiling regex for download-url failed:",
40861                                                 s->download_url, "pos:", erroff);
40862                                 return HANDLER_ERROR;
40863                         }
40864                 }
40865 -               
40866 +
40867                 if (!buffer_is_empty(s->trigger_url)) {
40868                         if (NULL == (s->trigger_regex = pcre_compile(s->trigger_url->ptr,
40869                                                                      0, &errptr, &erroff, NULL))) {
40870 -                               
40871 -                               log_error_write(srv, __FILE__, __LINE__, "sbss", 
40872 -                                               "compiling regex for trigger-url failed:", 
40873 +
40874 +                               log_error_write(srv, __FILE__, __LINE__, "sbss",
40875 +                                               "compiling regex for trigger-url failed:",
40876                                                 s->trigger_url, "pos:", erroff);
40877 -                               
40878 +
40879                                 return HANDLER_ERROR;
40880                         }
40881                 }
40882 @@ -211,100 +211,97 @@
40883  #if defined(HAVE_MEMCACHE_H)
40884                         size_t k;
40885                         s->mc = mc_new();
40886 -               
40887 +
40888                         for (k = 0; k < s->mc_hosts->used; k++) {
40889                                 data_string *ds = (data_string *)s->mc_hosts->data[k];
40890 -                               
40891 +
40892                                 if (0 != mc_server_add4(s->mc, ds->value->ptr)) {
40893 -                                       log_error_write(srv, __FILE__, __LINE__, "sb", 
40894 -                                                       "connection to host failed:", 
40895 +                                       log_error_write(srv, __FILE__, __LINE__, "sb",
40896 +                                                       "connection to host failed:",
40897                                                         ds->value);
40898 -                                       
40899 +
40900                                         return HANDLER_ERROR;
40901                                 }
40902                         }
40903  #else
40904 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
40905 +                       log_error_write(srv, __FILE__, __LINE__, "s",
40906                                         "memcache support is not compiled in but trigger-before-download.memcache-hosts is set, aborting");
40907                         return HANDLER_ERROR;
40908  #endif
40909                 }
40910 -               
40911 +
40912  
40913  #if (!defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H)) || !defined(HAVE_PCRE_H)
40914 -               log_error_write(srv, __FILE__, __LINE__, "s", 
40915 +               log_error_write(srv, __FILE__, __LINE__, "s",
40916                                 "(either gdbm or libmemcache) and pcre are require, but were not found, aborting");
40917                 return HANDLER_ERROR;
40918  #endif
40919         }
40920 -       
40921 +
40922         return HANDLER_GO_ON;
40923  }
40924  
40925 -#define PATCH(x) \
40926 -       p->conf.x = s->x;
40927  static int mod_trigger_b4_dl_patch_connection(server *srv, connection *con, plugin_data *p) {
40928         size_t i, j;
40929         plugin_config *s = p->config_storage[0];
40930 -       
40931 +
40932  #if defined(HAVE_GDBM)
40933 -       PATCH(db);
40934 -#endif 
40935 +       PATCH_OPTION(db);
40936 +#endif
40937  #if defined(HAVE_PCRE_H)
40938 -       PATCH(download_regex);
40939 -       PATCH(trigger_regex);
40940 -#endif 
40941 -       PATCH(trigger_timeout);
40942 -       PATCH(deny_url);
40943 -       PATCH(mc_namespace);
40944 -       PATCH(debug);
40945 +       PATCH_OPTION(download_regex);
40946 +       PATCH_OPTION(trigger_regex);
40947 +#endif
40948 +       PATCH_OPTION(trigger_timeout);
40949 +       PATCH_OPTION(deny_url);
40950 +       PATCH_OPTION(mc_namespace);
40951 +       PATCH_OPTION(debug);
40952  #if defined(HAVE_MEMCACHE_H)
40953 -       PATCH(mc);
40954 +       PATCH_OPTION(mc);
40955  #endif
40956 -       
40957 +
40958         /* skip the first, the global context */
40959         for (i = 1; i < srv->config_context->used; i++) {
40960                 data_config *dc = (data_config *)srv->config_context->data[i];
40961                 s = p->config_storage[i];
40962 -               
40963 +
40964                 /* condition didn't match */
40965                 if (!config_check_cond(srv, con, dc)) continue;
40966 -               
40967 +
40968                 /* merge config */
40969                 for (j = 0; j < dc->value->used; j++) {
40970                         data_unset *du = dc->value->data[j];
40971  
40972                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.download-url"))) {
40973  #if defined(HAVE_PCRE_H)
40974 -                               PATCH(download_regex);
40975 +                               PATCH_OPTION(download_regex);
40976  #endif
40977                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-url"))) {
40978  # if defined(HAVE_PCRE_H)
40979 -                               PATCH(trigger_regex);
40980 +                               PATCH_OPTION(trigger_regex);
40981  # endif
40982                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.gdbm-filename"))) {
40983  #if defined(HAVE_GDBM_H)
40984 -                               PATCH(db);
40985 +                               PATCH_OPTION(db);
40986  #endif
40987                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-timeout"))) {
40988 -                               PATCH(trigger_timeout);
40989 +                               PATCH_OPTION(trigger_timeout);
40990                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.debug"))) {
40991 -                               PATCH(debug);
40992 +                               PATCH_OPTION(debug);
40993                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.deny-url"))) {
40994 -                               PATCH(deny_url);
40995 +                               PATCH_OPTION(deny_url);
40996                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-namespace"))) {
40997 -                               PATCH(mc_namespace);
40998 +                               PATCH_OPTION(mc_namespace);
40999                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-hosts"))) {
41000  #if defined(HAVE_MEMCACHE_H)
41001 -                               PATCH(mc);
41002 +                               PATCH_OPTION(mc);
41003  #endif
41004                         }
41005                 }
41006         }
41007 -       
41008 +
41009         return 0;
41010  }
41011 -#undef PATCH
41012  
41013  URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
41014         plugin_data *p = p_d;
41015 @@ -315,20 +312,20 @@
41016         int n;
41017  # define N 10
41018         int ovec[N * 3];
41019 -       
41020 +
41021         if (con->uri.path->used == 0) return HANDLER_GO_ON;
41022 -       
41023 +
41024         mod_trigger_b4_dl_patch_connection(srv, con, p);
41025 -       
41026 +
41027         if (!p->conf.trigger_regex || !p->conf.download_regex) return HANDLER_GO_ON;
41028 -       
41029 +
41030  # if !defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H)
41031         return HANDLER_GO_ON;
41032  # elif defined(HAVE_GDBM_H) && defined(HAVE_MEMCACHE_H)
41033         if (!p->conf.db && !p->conf.mc) return HANDLER_GO_ON;
41034         if (p->conf.db && p->conf.mc) {
41035                 /* can't decide which one */
41036 -               
41037 +
41038                 return HANDLER_GO_ON;
41039         }
41040  # elif defined(HAVE_GDBM_H)
41041 @@ -336,12 +333,12 @@
41042  # else
41043         if (!p->conf.mc) return HANDLER_GO_ON;
41044  # endif
41045 -       
41046 +
41047         if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "X-Forwarded-For"))) {
41048                 /* X-Forwarded-For contains the ip behind the proxy */
41049 -               
41050 +
41051                 remote_ip = ds->value->ptr;
41052 -               
41053 +
41054                 /* memcache can't handle spaces */
41055         } else {
41056                 remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
41057 @@ -350,13 +347,13 @@
41058         if (p->conf.debug) {
41059                 log_error_write(srv, __FILE__, __LINE__, "ss", "(debug) remote-ip:", remote_ip);
41060         }
41061 -               
41062 +
41063         /* check if URL is a trigger -> insert IP into DB */
41064         if ((n = pcre_exec(p->conf.trigger_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
41065                 if (n != PCRE_ERROR_NOMATCH) {
41066                         log_error_write(srv, __FILE__, __LINE__, "sd",
41067                                         "execution error while matching:", n);
41068 -                       
41069 +
41070                         return HANDLER_ERROR;
41071                 }
41072         } else {
41073 @@ -364,34 +361,34 @@
41074                 if (p->conf.db) {
41075                         /* the trigger matched */
41076                         datum key, val;
41077 -                       
41078 +
41079                         key.dptr = (char *)remote_ip;
41080                         key.dsize = strlen(remote_ip);
41081 -                       
41082 +
41083                         val.dptr = (char *)&(srv->cur_ts);
41084                         val.dsize = sizeof(srv->cur_ts);
41085 -                       
41086 +
41087                         if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
41088                                 log_error_write(srv, __FILE__, __LINE__, "s",
41089                                                 "insert failed");
41090                         }
41091                 }
41092  # endif
41093 -# if defined(HAVE_MEMCACHE_H)          
41094 +# if defined(HAVE_MEMCACHE_H)
41095                 if (p->conf.mc) {
41096                         size_t i;
41097                         buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace);
41098                         buffer_append_string(p->tmp_buf, remote_ip);
41099 -                       
41100 +
41101                         for (i = 0; i < p->tmp_buf->used - 1; i++) {
41102                                 if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
41103                         }
41104 -                       
41105 +
41106                         if (p->conf.debug) {
41107                                 log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) triggered IP:", p->tmp_buf);
41108                         }
41109  
41110 -                       if (0 != mc_set(p->conf.mc, 
41111 +                       if (0 != mc_set(p->conf.mc,
41112                                         CONST_BUF_LEN(p->tmp_buf),
41113                                         (char *)&(srv->cur_ts), sizeof(srv->cur_ts),
41114                                         p->conf.trigger_timeout, 0)) {
41115 @@ -401,7 +398,7 @@
41116                 }
41117  # endif
41118         }
41119 -               
41120 +
41121         /* check if URL is a download -> check IP in DB, update timestamp */
41122         if ((n = pcre_exec(p->conf.download_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
41123                 if (n != PCRE_ERROR_NOMATCH) {
41124 @@ -411,93 +408,93 @@
41125                 }
41126         } else {
41127                 /* the download uri matched */
41128 -# if defined(HAVE_GDBM_H)              
41129 +# if defined(HAVE_GDBM_H)
41130                 if (p->conf.db) {
41131                         datum key, val;
41132                         time_t last_hit;
41133 -               
41134 +
41135                         key.dptr = (char *)remote_ip;
41136                         key.dsize = strlen(remote_ip);
41137 -                       
41138 +
41139                         val = gdbm_fetch(p->conf.db, key);
41140 -               
41141 +
41142                         if (val.dptr == NULL) {
41143                                 /* not found, redirect */
41144 -                               
41145 +
41146                                 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
41147 -                               
41148 +
41149                                 con->http_status = 307;
41150 -                               
41151 +
41152                                 return HANDLER_FINISHED;
41153                         }
41154 -                       
41155 +
41156                         last_hit = *(time_t *)(val.dptr);
41157 -                       
41158 +
41159                         free(val.dptr);
41160 -                       
41161 +
41162                         if (srv->cur_ts - last_hit > p->conf.trigger_timeout) {
41163                                 /* found, but timeout, redirect */
41164 -                               
41165 +
41166                                 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
41167                                 con->http_status = 307;
41168 -                               
41169 +
41170                                 if (p->conf.db) {
41171                                         if (0 != gdbm_delete(p->conf.db, key)) {
41172                                                 log_error_write(srv, __FILE__, __LINE__, "s",
41173                                                                 "delete failed");
41174                                         }
41175                                 }
41176 -                               
41177 +
41178                                 return HANDLER_FINISHED;
41179                         }
41180 -                       
41181 +
41182                         val.dptr = (char *)&(srv->cur_ts);
41183                         val.dsize = sizeof(srv->cur_ts);
41184 -                       
41185 +
41186                         if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
41187                                 log_error_write(srv, __FILE__, __LINE__, "s",
41188                                                 "insert failed");
41189                         }
41190                 }
41191  # endif
41192 -               
41193 -# if defined(HAVE_MEMCACHE_H)          
41194 +
41195 +# if defined(HAVE_MEMCACHE_H)
41196                 if (p->conf.mc) {
41197                         void *r;
41198                         size_t i;
41199 -                       
41200 +
41201                         buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace);
41202                         buffer_append_string(p->tmp_buf, remote_ip);
41203 -                       
41204 +
41205                         for (i = 0; i < p->tmp_buf->used - 1; i++) {
41206                                 if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
41207                         }
41208 -                       
41209 +
41210                         if (p->conf.debug) {
41211                                 log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) checking IP:", p->tmp_buf);
41212                         }
41213  
41214                         /**
41215 -                        * 
41216 +                        *
41217                          * memcached is do expiration for us, as long as we can fetch it every thing is ok
41218 -                        * and the timestamp is updated 
41219 -                        * 
41220 +                        * and the timestamp is updated
41221 +                        *
41222                          */
41223 -                       if (NULL == (r = mc_aget(p->conf.mc, 
41224 +                       if (NULL == (r = mc_aget(p->conf.mc,
41225                                                  CONST_BUF_LEN(p->tmp_buf)
41226                                                  ))) {
41227 -                               
41228 +
41229                                 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
41230 -                               
41231 +
41232                                 con->http_status = 307;
41233 -                               
41234 +
41235                                 return HANDLER_FINISHED;
41236                         }
41237 -                       
41238 +
41239                         free(r);
41240 -                       
41241 +
41242                         /* set a new timeout */
41243 -                       if (0 != mc_set(p->conf.mc, 
41244 +                       if (0 != mc_set(p->conf.mc,
41245                                         CONST_BUF_LEN(p->tmp_buf),
41246                                         (char *)&(srv->cur_ts), sizeof(srv->cur_ts),
41247                                         p->conf.trigger_timeout, 0)) {
41248 @@ -507,13 +504,13 @@
41249                 }
41250  # endif
41251         }
41252 -       
41253 +
41254  #else
41255         UNUSED(srv);
41256         UNUSED(con);
41257         UNUSED(p_d);
41258  #endif
41259 -       
41260 +
41261         return HANDLER_GO_ON;
41262  }
41263  
41264 @@ -521,21 +518,21 @@
41265  TRIGGER_FUNC(mod_trigger_b4_dl_handle_trigger) {
41266         plugin_data *p = p_d;
41267         size_t i;
41268 -       
41269 +
41270         /* check DB each minute */
41271         if (srv->cur_ts % 60 != 0) return HANDLER_GO_ON;
41272 -       
41273 +
41274         /* cleanup */
41275         for (i = 0; i < srv->config_context->used; i++) {
41276                 plugin_config *s = p->config_storage[i];
41277                 datum key, val, okey;
41278 -               
41279 +
41280                 if (!s->db) continue;
41281 -               
41282 +
41283                 okey.dptr = NULL;
41284 -               
41285 -               /* according to the manual this loop + delete does delete all entries on its way 
41286 -                * 
41287 +
41288 +               /* according to the manual this loop + delete does delete all entries on its way
41289 +                *
41290                  * we don't care as the next round will remove them. We don't have to perfect here.
41291                  */
41292                 for (key = gdbm_firstkey(s->db); key.dptr; key = gdbm_nextkey(s->db, okey)) {
41293 @@ -544,21 +541,21 @@
41294                                 free(okey.dptr);
41295                                 okey.dptr = NULL;
41296                         }
41297 -                       
41298 +
41299                         val = gdbm_fetch(s->db, key);
41300 -                       
41301 +
41302                         last_hit = *(time_t *)(val.dptr);
41303 -                       
41304 +
41305                         free(val.dptr);
41306 -                       
41307 +
41308                         if (srv->cur_ts - last_hit > s->trigger_timeout) {
41309                                 gdbm_delete(s->db, key);
41310                         }
41311 -                       
41312 +
41313                         okey = key;
41314                 }
41315                 if (okey.dptr) free(okey.dptr);
41316 -               
41317 +
41318                 /* reorg once a day */
41319                 if ((srv->cur_ts % (60 * 60 * 24) != 0)) gdbm_reorganize(s->db);
41320         }
41321 @@ -571,7 +568,7 @@
41322  int mod_trigger_b4_dl_plugin_init(plugin *p) {
41323         p->version     = LIGHTTPD_VERSION_ID;
41324         p->name        = buffer_init_string("trigger_b4_dl");
41325 -       
41326 +
41327         p->init        = mod_trigger_b4_dl_init;
41328         p->handle_uri_clean  = mod_trigger_b4_dl_uri_handler;
41329         p->set_defaults  = mod_trigger_b4_dl_set_defaults;
41330 @@ -579,8 +576,8 @@
41331         p->handle_trigger  = mod_trigger_b4_dl_handle_trigger;
41332  #endif
41333         p->cleanup     = mod_trigger_b4_dl_free;
41334 -       
41335 +
41336         p->data        = NULL;
41337 -       
41338 +
41339         return 0;
41340  }
41341 --- ../lighttpd-1.4.11/src/mod_userdir.c        2005-10-28 16:48:28.000000000 +0300
41342 +++ lighttpd-1.4.12/src/mod_userdir.c   2006-07-16 00:26:04.000000000 +0300
41343 @@ -10,6 +10,7 @@
41344  #include "response.h"
41345  
41346  #include "plugin.h"
41347 +#include "sys-files.h"
41348  
41349  #ifdef HAVE_PWD_H
41350  #include <pwd.h>
41351 @@ -25,54 +26,54 @@
41352  
41353  typedef struct {
41354         PLUGIN_DATA;
41355 -       
41356 +
41357         buffer *username;
41358         buffer *temp_path;
41359 -       
41360 +
41361         plugin_config **config_storage;
41362 -       
41363 -       plugin_config conf; 
41364 +
41365 +       plugin_config conf;
41366  } plugin_data;
41367  
41368  /* init the plugin data */
41369  INIT_FUNC(mod_userdir_init) {
41370         plugin_data *p;
41371 -       
41372 +
41373         p = calloc(1, sizeof(*p));
41374 -       
41375 +
41376         p->username = buffer_init();
41377         p->temp_path = buffer_init();
41378 -       
41379 +
41380         return p;
41381  }
41382  
41383  /* detroy the plugin data */
41384  FREE_FUNC(mod_userdir_free) {
41385         plugin_data *p = p_d;
41386 -       
41387 +
41388         if (!p) return HANDLER_GO_ON;
41389 -       
41390 +
41391         if (p->config_storage) {
41392                 size_t i;
41393 -               
41394 +
41395                 for (i = 0; i < srv->config_context->used; i++) {
41396                         plugin_config *s = p->config_storage[i];
41397 -                       
41398 +
41399                         array_free(s->include_user);
41400                         array_free(s->exclude_user);
41401                         buffer_free(s->path);
41402                         buffer_free(s->basepath);
41403 -                       
41404 +
41405                         free(s);
41406                 }
41407                 free(p->config_storage);
41408         }
41409 -       
41410 +
41411         buffer_free(p->username);
41412         buffer_free(p->temp_path);
41413 -       
41414 +
41415         free(p);
41416 -       
41417 +
41418         return HANDLER_GO_ON;
41419  }
41420  
41421 @@ -81,81 +82,78 @@
41422  SETDEFAULTS_FUNC(mod_userdir_set_defaults) {
41423         plugin_data *p = p_d;
41424         size_t i;
41425 -       
41426 -       config_values_t cv[] = { 
41427 +
41428 +       config_values_t cv[] = {
41429                 { "userdir.path",               NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
41430                 { "userdir.exclude-user",       NULL, T_CONFIG_ARRAY,  T_CONFIG_SCOPE_CONNECTION },       /* 1 */
41431                 { "userdir.include-user",       NULL, T_CONFIG_ARRAY,  T_CONFIG_SCOPE_CONNECTION },       /* 2 */
41432                 { "userdir.basepath",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
41433                 { NULL,                         NULL, T_CONFIG_UNSET,  T_CONFIG_SCOPE_UNSET }
41434         };
41435 -       
41436 +
41437         if (!p) return HANDLER_ERROR;
41438 -       
41439 +
41440         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
41441 -       
41442 +
41443         for (i = 0; i < srv->config_context->used; i++) {
41444                 plugin_config *s;
41445 -               
41446 +
41447                 s = calloc(1, sizeof(plugin_config));
41448                 s->exclude_user = array_init();
41449                 s->include_user = array_init();
41450                 s->path = buffer_init();
41451                 s->basepath = buffer_init();
41452 -       
41453 +
41454                 cv[0].destination = s->path;
41455                 cv[1].destination = s->exclude_user;
41456                 cv[2].destination = s->include_user;
41457                 cv[3].destination = s->basepath;
41458 -               
41459 +
41460                 p->config_storage[i] = s;
41461 -       
41462 +
41463                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
41464                         return HANDLER_ERROR;
41465                 }
41466         }
41467 -       
41468 +
41469         return HANDLER_GO_ON;
41470  }
41471  
41472 -#define PATCH(x) \
41473 -       p->conf.x = s->x;
41474  static int mod_userdir_patch_connection(server *srv, connection *con, plugin_data *p) {
41475         size_t i, j;
41476         plugin_config *s = p->config_storage[0];
41477 -       
41478 -       PATCH(path);
41479 -       PATCH(exclude_user);
41480 -       PATCH(include_user);
41481 -       PATCH(basepath);
41482 -       
41483 +
41484 +       PATCH_OPTION(path);
41485 +       PATCH_OPTION(exclude_user);
41486 +       PATCH_OPTION(include_user);
41487 +       PATCH_OPTION(basepath);
41488 +
41489         /* skip the first, the global context */
41490         for (i = 1; i < srv->config_context->used; i++) {
41491                 data_config *dc = (data_config *)srv->config_context->data[i];
41492                 s = p->config_storage[i];
41493 -               
41494 +
41495                 /* condition didn't match */
41496                 if (!config_check_cond(srv, con, dc)) continue;
41497 -               
41498 +
41499                 /* merge config */
41500                 for (j = 0; j < dc->value->used; j++) {
41501                         data_unset *du = dc->value->data[j];
41502 -                       
41503 +
41504                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.path"))) {
41505 -                               PATCH(path);
41506 +                               PATCH_OPTION(path);
41507                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.exclude-user"))) {
41508 -                               PATCH(exclude_user);
41509 +                               PATCH_OPTION(exclude_user);
41510                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.include-user"))) {
41511 -                               PATCH(include_user);
41512 +                               PATCH_OPTION(include_user);
41513                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.basepath"))) {
41514 -                               PATCH(basepath);
41515 +                               PATCH_OPTION(basepath);
41516                         }
41517                 }
41518         }
41519 -       
41520 +
41521         return 0;
41522  }
41523 -#undef PATCH
41524  
41525  URIHANDLER_FUNC(mod_userdir_docroot_handler) {
41526         plugin_data *p = p_d;
41527 @@ -169,18 +167,18 @@
41528         if (con->uri.path->used == 0) return HANDLER_GO_ON;
41529  
41530         mod_userdir_patch_connection(srv, con, p);
41531 -       
41532 +
41533         uri_len = con->uri.path->used - 1;
41534 -       
41535 +
41536         /* /~user/foo.html -> /home/user/public_html/foo.html */
41537 -       
41538 +
41539         if (con->uri.path->ptr[0] != '/' ||
41540             con->uri.path->ptr[1] != '~') return HANDLER_GO_ON;
41541 -       
41542 +
41543         if (NULL == (rel_url = strchr(con->uri.path->ptr + 2, '/'))) {
41544                 /* / is missing -> redirect to .../ as we are a user - DIRECTORY ! :) */
41545                 http_response_redirect_to_directory(srv, con);
41546 -               
41547 +
41548                 return HANDLER_FINISHED;
41549         }
41550  
41551 @@ -188,10 +186,10 @@
41552         if (0 == rel_url - (con->uri.path->ptr + 2)) {
41553                 return HANDLER_GO_ON;
41554         }
41555 -       
41556 +
41557         buffer_copy_string_len(p->username, con->uri.path->ptr + 2, rel_url - (con->uri.path->ptr + 2));
41558 -       
41559 -       if (buffer_is_empty(p->conf.basepath) 
41560 +
41561 +       if (buffer_is_empty(p->conf.basepath)
41562  #ifdef HAVE_PWD_H
41563             && NULL == (pwd = getpwnam(p->username->ptr))
41564  #endif
41565 @@ -200,31 +198,31 @@
41566                 return HANDLER_GO_ON;
41567         }
41568  
41569 -       
41570 +
41571         for (k = 0; k < p->conf.exclude_user->used; k++) {
41572                 data_string *ds = (data_string *)p->conf.exclude_user->data[k];
41573 -               
41574 +
41575                 if (buffer_is_equal(ds->value, p->username)) {
41576                         /* user in exclude list */
41577                         return HANDLER_GO_ON;
41578                 }
41579         }
41580 -       
41581 +
41582         if (p->conf.include_user->used) {
41583                 int found_user = 0;
41584                 for (k = 0; k < p->conf.include_user->used; k++) {
41585                         data_string *ds = (data_string *)p->conf.include_user->data[k];
41586 -                       
41587 +
41588                         if (buffer_is_equal(ds->value, p->username)) {
41589                                 /* user in include list */
41590                                 found_user = 1;
41591                                 break;
41592                         }
41593                 }
41594 -               
41595 +
41596                 if (!found_user) return HANDLER_GO_ON;
41597         }
41598 -       
41599 +
41600         /* we build the physical path */
41601  
41602         if (buffer_is_empty(p->conf.basepath)) {
41603 @@ -252,23 +250,23 @@
41604                 }
41605  
41606                 buffer_copy_string_buffer(p->temp_path, p->conf.basepath);
41607 -               BUFFER_APPEND_SLASH(p->temp_path);
41608 +               PATHNAME_APPEND_SLASH(p->temp_path);
41609                 buffer_append_string_buffer(p->temp_path, p->username);
41610         }
41611 -       BUFFER_APPEND_SLASH(p->temp_path);
41612 -       buffer_append_string_buffer(p->temp_path, p->conf.path); 
41613 +       PATHNAME_APPEND_SLASH(p->temp_path);
41614 +       buffer_append_string_buffer(p->temp_path, p->conf.path);
41615  
41616         if (buffer_is_empty(p->conf.basepath)) {
41617                 struct stat st;
41618                 int ret;
41619 -               
41620 +
41621                 ret = stat(p->temp_path->ptr, &st);
41622                 if (ret < 0 || S_ISDIR(st.st_mode) != 1) {
41623                         return HANDLER_GO_ON;
41624 -               } 
41625 +               }
41626         }
41627  
41628 -       BUFFER_APPEND_SLASH(p->temp_path);
41629 +       PATHNAME_APPEND_SLASH(p->temp_path);
41630         buffer_append_string(p->temp_path, rel_url + 1); /* skip the / */
41631         buffer_copy_string_buffer(con->physical.path, p->temp_path);
41632  
41633 @@ -282,13 +280,13 @@
41634  int mod_userdir_plugin_init(plugin *p) {
41635         p->version     = LIGHTTPD_VERSION_ID;
41636         p->name        = buffer_init_string("userdir");
41637 -       
41638 +
41639         p->init           = mod_userdir_init;
41640         p->handle_physical = mod_userdir_docroot_handler;
41641         p->set_defaults   = mod_userdir_set_defaults;
41642         p->cleanup        = mod_userdir_free;
41643 -       
41644 +
41645         p->data        = NULL;
41646 -       
41647 +
41648         return 0;
41649  }
41650 --- ../lighttpd-1.4.11/src/mod_usertrack.c      2006-01-31 15:01:20.000000000 +0200
41651 +++ lighttpd-1.4.12/src/mod_usertrack.c 2006-07-16 00:26:04.000000000 +0300
41652 @@ -24,44 +24,44 @@
41653  
41654  typedef struct {
41655         PLUGIN_DATA;
41656 -       
41657 +
41658         plugin_config **config_storage;
41659 -       
41660 -       plugin_config conf; 
41661 +
41662 +       plugin_config conf;
41663  } plugin_data;
41664  
41665  /* init the plugin data */
41666  INIT_FUNC(mod_usertrack_init) {
41667         plugin_data *p;
41668 -       
41669 +
41670         p = calloc(1, sizeof(*p));
41671 -       
41672 +
41673         return p;
41674  }
41675  
41676  /* detroy the plugin data */
41677  FREE_FUNC(mod_usertrack_free) {
41678         plugin_data *p = p_d;
41679 -       
41680 +
41681         UNUSED(srv);
41682 -       
41683 +
41684         if (!p) return HANDLER_GO_ON;
41685 -       
41686 +
41687         if (p->config_storage) {
41688                 size_t i;
41689                 for (i = 0; i < srv->config_context->used; i++) {
41690                         plugin_config *s = p->config_storage[i];
41691 -                       
41692 +
41693                         buffer_free(s->cookie_name);
41694                         buffer_free(s->cookie_domain);
41695 -                       
41696 +
41697                         free(s);
41698                 }
41699                 free(p->config_storage);
41700         }
41701 -       
41702 +
41703         free(p);
41704 -       
41705 +
41706         return HANDLER_GO_ON;
41707  }
41708  
41709 @@ -70,38 +70,38 @@
41710  SETDEFAULTS_FUNC(mod_usertrack_set_defaults) {
41711         plugin_data *p = p_d;
41712         size_t i = 0;
41713 -       
41714 -       config_values_t cv[] = { 
41715 +
41716 +       config_values_t cv[] = {
41717                 { "usertrack.cookie-name",       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
41718                 { "usertrack.cookie-max-age",    NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 1 */
41719                 { "usertrack.cookie-domain",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
41720 -               
41721 -               { "usertrack.cookiename",        NULL, T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION },   
41722 +
41723 +               { "usertrack.cookiename",        NULL, T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION },
41724                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
41725         };
41726 -       
41727 +
41728         if (!p) return HANDLER_ERROR;
41729 -       
41730 +
41731         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
41732 -       
41733 +
41734         for (i = 0; i < srv->config_context->used; i++) {
41735                 plugin_config *s;
41736 -               
41737 +
41738                 s = calloc(1, sizeof(plugin_config));
41739                 s->cookie_name    = buffer_init();
41740                 s->cookie_domain  = buffer_init();
41741                 s->cookie_max_age = 0;
41742 -               
41743 +
41744                 cv[0].destination = s->cookie_name;
41745                 cv[1].destination = &(s->cookie_max_age);
41746                 cv[2].destination = s->cookie_domain;
41747 -               
41748 +
41749                 p->config_storage[i] = s;
41750 -       
41751 +
41752                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
41753                         return HANDLER_ERROR;
41754                 }
41755 -       
41756 +
41757                 if (buffer_is_empty(s->cookie_name)) {
41758                         buffer_copy_string(s->cookie_name, "TRACKID");
41759                 } else {
41760 @@ -109,68 +109,65 @@
41761                         for (j = 0; j < s->cookie_name->used - 1; j++) {
41762                                 char c = s->cookie_name->ptr[j] | 32;
41763                                 if (c < 'a' || c > 'z') {
41764 -                                       log_error_write(srv, __FILE__, __LINE__, "sb", 
41765 -                                                       "invalid character in usertrack.cookie-name:", 
41766 +                                       log_error_write(srv, __FILE__, __LINE__, "sb",
41767 +                                                       "invalid character in usertrack.cookie-name:",
41768                                                         s->cookie_name);
41769 -                                       
41770 +
41771                                         return HANDLER_ERROR;
41772                                 }
41773                         }
41774                 }
41775 -               
41776 +
41777                 if (!buffer_is_empty(s->cookie_domain)) {
41778                         size_t j;
41779                         for (j = 0; j < s->cookie_domain->used - 1; j++) {
41780                                 char c = s->cookie_domain->ptr[j];
41781                                 if (c <= 32 || c >= 127 || c == '"' || c == '\\') {
41782 -                                       log_error_write(srv, __FILE__, __LINE__, "sb", 
41783 -                                                       "invalid character in usertrack.cookie-domain:", 
41784 +                                       log_error_write(srv, __FILE__, __LINE__, "sb",
41785 +                                                       "invalid character in usertrack.cookie-domain:",
41786                                                         s->cookie_domain);
41787 -                                       
41788 +
41789                                         return HANDLER_ERROR;
41790                                 }
41791                         }
41792                 }
41793         }
41794 -               
41795 +
41796         return HANDLER_GO_ON;
41797  }
41798  
41799 -#define PATCH(x) \
41800 -       p->conf.x = s->x;
41801  static int mod_usertrack_patch_connection(server *srv, connection *con, plugin_data *p) {
41802         size_t i, j;
41803         plugin_config *s = p->config_storage[0];
41804 -       
41805 -       PATCH(cookie_name);
41806 -       PATCH(cookie_domain);
41807 -       PATCH(cookie_max_age);
41808 -       
41809 +
41810 +       PATCH_OPTION(cookie_name);
41811 +       PATCH_OPTION(cookie_domain);
41812 +       PATCH_OPTION(cookie_max_age);
41813 +
41814         /* skip the first, the global context */
41815         for (i = 1; i < srv->config_context->used; i++) {
41816                 data_config *dc = (data_config *)srv->config_context->data[i];
41817                 s = p->config_storage[i];
41818 -               
41819 +
41820                 /* condition didn't match */
41821                 if (!config_check_cond(srv, con, dc)) continue;
41822 -               
41823 +
41824                 /* merge config */
41825                 for (j = 0; j < dc->value->used; j++) {
41826                         data_unset *du = dc->value->data[j];
41827 -                       
41828 +
41829                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-name"))) {
41830 -                               PATCH(cookie_name);
41831 +                               PATCH_OPTION(cookie_name);
41832                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-max-age"))) {
41833 -                               PATCH(cookie_max_age);
41834 +                               PATCH_OPTION(cookie_max_age);
41835                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-domain"))) {
41836 -                               PATCH(cookie_domain);
41837 +                               PATCH_OPTION(cookie_domain);
41838                         }
41839                 }
41840         }
41841 -       
41842 +
41843         return 0;
41844  }
41845 -#undef PATCH
41846  
41847  URIHANDLER_FUNC(mod_usertrack_uri_handler) {
41848         plugin_data *p = p_d;
41849 @@ -178,38 +175,38 @@
41850         unsigned char h[16];
41851         MD5_CTX Md5Ctx;
41852         char hh[32];
41853 -       
41854 +
41855         if (con->uri.path->used == 0) return HANDLER_GO_ON;
41856 -       
41857 +
41858         mod_usertrack_patch_connection(srv, con, p);
41859 -       
41860 +
41861         if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) {
41862                 char *g;
41863                 /* we have a cookie, does it contain a valid name ? */
41864 -               
41865 -               /* parse the cookie 
41866 -                * 
41867 +
41868 +               /* parse the cookie
41869 +                *
41870                  * check for cookiename + (WS | '=')
41871 -                * 
41872 +                *
41873                  */
41874 -               
41875 +
41876                 if (NULL != (g = strstr(ds->value->ptr, p->conf.cookie_name->ptr))) {
41877                         char *nc;
41878 -                       
41879 +
41880                         /* skip WS */
41881                         for (nc = g + p->conf.cookie_name->used-1; *nc == ' ' || *nc == '\t'; nc++);
41882 -                       
41883 +
41884                         if (*nc == '=') {
41885                                 /* ok, found the key of our own cookie */
41886 -                               
41887 +
41888                                 if (strlen(nc) > 32) {
41889                                         /* i'm lazy */
41890                                         return HANDLER_GO_ON;
41891                                 }
41892                         }
41893                 }
41894 -       } 
41895 -       
41896 +       }
41897 +
41898         /* set a cookie */
41899         if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
41900                 ds = data_response_init();
41901 @@ -217,39 +214,39 @@
41902         buffer_copy_string(ds->key, "Set-Cookie");
41903         buffer_copy_string_buffer(ds->value, p->conf.cookie_name);
41904         buffer_append_string(ds->value, "=");
41905 -       
41906 +
41907  
41908         /* taken from mod_auth.c */
41909 -       
41910 +
41911         /* generate shared-secret */
41912         MD5_Init(&Md5Ctx);
41913         MD5_Update(&Md5Ctx, (unsigned char *)con->uri.path->ptr, con->uri.path->used - 1);
41914         MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
41915 -       
41916 +
41917         /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
41918         ltostr(hh, srv->cur_ts);
41919         MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
41920         ltostr(hh, rand());
41921         MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
41922 -       
41923 +
41924         MD5_Final(h, &Md5Ctx);
41925 -       
41926 +
41927         buffer_append_string_encoded(ds->value, (char *)h, 16, ENCODING_HEX);
41928         buffer_append_string(ds->value, "; Path=/");
41929         buffer_append_string(ds->value, "; Version=1");
41930 -       
41931 +
41932         if (!buffer_is_empty(p->conf.cookie_domain)) {
41933                 buffer_append_string(ds->value, "; Domain=");
41934                 buffer_append_string_encoded(ds->value, CONST_BUF_LEN(p->conf.cookie_domain), ENCODING_REL_URI);
41935         }
41936 -       
41937 +
41938         if (p->conf.cookie_max_age) {
41939                 buffer_append_string(ds->value, "; max-age=");
41940                 buffer_append_long(ds->value, p->conf.cookie_max_age);
41941         }
41942 -       
41943 +
41944         array_insert_unique(con->response.headers, (data_unset *)ds);
41945 -       
41946 +
41947         return HANDLER_GO_ON;
41948  }
41949  
41950 @@ -258,13 +255,13 @@
41951  int mod_usertrack_plugin_init(plugin *p) {
41952         p->version     = LIGHTTPD_VERSION_ID;
41953         p->name        = buffer_init_string("usertrack");
41954 -       
41955 +
41956         p->init        = mod_usertrack_init;
41957         p->handle_uri_clean  = mod_usertrack_uri_handler;
41958         p->set_defaults  = mod_usertrack_set_defaults;
41959         p->cleanup     = mod_usertrack_free;
41960 -       
41961 +
41962         p->data        = NULL;
41963 -       
41964 +
41965         return 0;
41966  }
41967 --- ../lighttpd-1.4.11/src/mod_webdav.c 2006-03-03 01:28:58.000000000 +0200
41968 +++ lighttpd-1.4.12/src/mod_webdav.c    2006-07-18 13:03:40.000000000 +0300
41969 @@ -3,13 +3,10 @@
41970  #include <ctype.h>
41971  #include <stdlib.h>
41972  #include <string.h>
41973 -#include <dirent.h>
41974  #include <errno.h>
41975 -#include <unistd.h>
41976  #include <fcntl.h>
41977  #include <stdio.h>
41978  #include <assert.h>
41979 -#include <sys/mman.h>
41980  
41981  #ifdef HAVE_CONFIG_H
41982  #include "config.h"
41983 @@ -23,6 +20,11 @@
41984  #include <sqlite3.h>
41985  #endif
41986  
41987 +#if defined(HAVE_LIBXML_H) && defined(HAVE_SQLITE3_H) && defined(HAVE_UUID_H)
41988 +#define USE_LOCKS
41989 +#include <uuid/uuid.h>
41990 +#endif
41991 +
41992  #include "base.h"
41993  #include "log.h"
41994  #include "buffer.h"
41995 @@ -33,13 +35,16 @@
41996  #include "stream.h"
41997  #include "stat_cache.h"
41998  
41999 +#include "sys-files.h"
42000 +#include "sys-mmap.h"
42001 +#include "sys-strings.h"
42002  
42003  /**
42004   * this is a webdav for a lighttpd plugin
42005   *
42006 - * at least a very basic one. 
42007 + * at least a very basic one.
42008   * - for now it is read-only and we only support PROPFIND
42009 - * 
42010 + *
42011   */
42012  
42013  
42014 @@ -58,64 +63,70 @@
42015         sqlite3_stmt *stmt_delete_prop;
42016         sqlite3_stmt *stmt_select_prop;
42017         sqlite3_stmt *stmt_select_propnames;
42018 -       
42019 +
42020         sqlite3_stmt *stmt_delete_uri;
42021         sqlite3_stmt *stmt_move_uri;
42022         sqlite3_stmt *stmt_copy_uri;
42023 +
42024 +       sqlite3_stmt *stmt_remove_lock;
42025 +       sqlite3_stmt *stmt_create_lock;
42026 +       sqlite3_stmt *stmt_read_lock;
42027 +       sqlite3_stmt *stmt_read_lock_by_uri;
42028 +       sqlite3_stmt *stmt_refresh_lock;
42029  #endif
42030  } plugin_config;
42031  
42032  typedef struct {
42033         PLUGIN_DATA;
42034 -       
42035 +
42036         buffer *tmp_buf;
42037         request_uri uri;
42038         physical physical;
42039  
42040         plugin_config **config_storage;
42041 -       
42042 -       plugin_config conf; 
42043 +
42044 +       plugin_config conf;
42045  } plugin_data;
42046  
42047  /* init the plugin data */
42048  INIT_FUNC(mod_webdav_init) {
42049         plugin_data *p;
42050 -       
42051 +
42052         p = calloc(1, sizeof(*p));
42053 -       
42054 +
42055         p->tmp_buf = buffer_init();
42056  
42057         p->uri.scheme = buffer_init();
42058         p->uri.path_raw = buffer_init();
42059         p->uri.path = buffer_init();
42060         p->uri.authority = buffer_init();
42061 -       
42062 +
42063         p->physical.path = buffer_init();
42064         p->physical.rel_path = buffer_init();
42065         p->physical.doc_root = buffer_init();
42066         p->physical.basedir = buffer_init();
42067 -       
42068 +
42069         return p;
42070  }
42071  
42072  /* detroy the plugin data */
42073  FREE_FUNC(mod_webdav_free) {
42074         plugin_data *p = p_d;
42075 -       
42076 +
42077         UNUSED(srv);
42078  
42079         if (!p) return HANDLER_GO_ON;
42080 -       
42081 +
42082         if (p->config_storage) {
42083                 size_t i;
42084                 for (i = 0; i < srv->config_context->used; i++) {
42085                         plugin_config *s = p->config_storage[i];
42086  
42087                         if (!s) continue;
42088 -       
42089 +
42090                         buffer_free(s->sqlite_db_name);
42091  #ifdef USE_PROPPATCH
42092 -                       if (s->sql) {   
42093 +                       if (s->sql) {
42094                                 sqlite3_finalize(s->stmt_delete_prop);
42095                                 sqlite3_finalize(s->stmt_delete_uri);
42096                                 sqlite3_finalize(s->stmt_copy_uri);
42097 @@ -123,9 +134,15 @@
42098                                 sqlite3_finalize(s->stmt_update_prop);
42099                                 sqlite3_finalize(s->stmt_select_prop);
42100                                 sqlite3_finalize(s->stmt_select_propnames);
42101 +
42102 +                               sqlite3_finalize(s->stmt_read_lock);
42103 +                               sqlite3_finalize(s->stmt_read_lock_by_uri);
42104 +                               sqlite3_finalize(s->stmt_create_lock);
42105 +                               sqlite3_finalize(s->stmt_remove_lock);
42106 +                               sqlite3_finalize(s->stmt_refresh_lock);
42107                                 sqlite3_close(s->sql);
42108                         }
42109 -#endif 
42110 +#endif
42111                         free(s);
42112                 }
42113                 free(p->config_storage);
42114 @@ -135,16 +152,16 @@
42115         buffer_free(p->uri.path_raw);
42116         buffer_free(p->uri.path);
42117         buffer_free(p->uri.authority);
42118 -       
42119 +
42120         buffer_free(p->physical.path);
42121         buffer_free(p->physical.rel_path);
42122         buffer_free(p->physical.doc_root);
42123         buffer_free(p->physical.basedir);
42124 -       
42125 +
42126         buffer_free(p->tmp_buf);
42127 -       
42128 +
42129         free(p);
42130 -       
42131 +
42132         return HANDLER_GO_ON;
42133  }
42134  
42135 @@ -153,32 +170,32 @@
42136  SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
42137         plugin_data *p = p_d;
42138         size_t i = 0;
42139 -       
42140 -       config_values_t cv[] = { 
42141 +
42142 +       config_values_t cv[] = {
42143                 { "webdav.activate",            NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
42144                 { "webdav.is-readonly",         NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
42145                 { "webdav.sqlite-db-name",      NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_CONNECTION },       /* 2 */
42146                 { "webdav.log-xml",             NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
42147                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
42148         };
42149 -       
42150 +
42151         if (!p) return HANDLER_ERROR;
42152 -       
42153 +
42154         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
42155 -       
42156 +
42157         for (i = 0; i < srv->config_context->used; i++) {
42158                 plugin_config *s;
42159 -               
42160 +
42161                 s = calloc(1, sizeof(plugin_config));
42162                 s->sqlite_db_name = buffer_init();
42163 -               
42164 +
42165                 cv[0].destination = &(s->enabled);
42166                 cv[1].destination = &(s->is_readonly);
42167                 cv[2].destination = s->sqlite_db_name;
42168                 cv[3].destination = &(s->log_xml);
42169 -               
42170 +
42171                 p->config_storage[i] = s;
42172 -       
42173 +
42174                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
42175                         return HANDLER_ERROR;
42176                 }
42177 @@ -193,8 +210,26 @@
42178                                 return HANDLER_ERROR;
42179                         }
42180  
42181 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42182 -                               CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"), 
42183 +                       if (SQLITE_OK != sqlite3_exec(s->sql,
42184 +                                       "CREATE TABLE properties ("
42185 +                                       "  resource TEXT NOT NULL,"
42186 +                                       "  prop TEXT NOT NULL,"
42187 +                                       "  ns TEXT NOT NULL,"
42188 +                                       "  value TEXT NOT NULL,"
42189 +                                       "  PRIMARY KEY(resource, prop, ns))",
42190 +                                       NULL, NULL, &err)) {
42191 +
42192 +                               if (0 != strcmp(err, "table properties already exists")) {
42193 +                                       log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
42194 +                                       sqlite3_free(err);
42195 +
42196 +                                       return HANDLER_ERROR;
42197 +                               }
42198 +                               sqlite3_free(err);
42199 +                       }
42200 +
42201 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42202 +                               CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
42203                                 &(s->stmt_select_prop), &next_stmt)) {
42204                                 /* prepare failed */
42205  
42206 @@ -202,8 +237,8 @@
42207                                 return HANDLER_ERROR;
42208                         }
42209  
42210 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42211 -                               CONST_STR_LEN("SELECT ns, prop FROM properties WHERE resource = ?"), 
42212 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42213 +                               CONST_STR_LEN("SELECT ns, prop FROM properties WHERE resource = ?"),
42214                                 &(s->stmt_select_propnames), &next_stmt)) {
42215                                 /* prepare failed */
42216  
42217 @@ -211,16 +246,67 @@
42218                                 return HANDLER_ERROR;
42219                         }
42220  
42221 -                       if (SQLITE_OK != sqlite3_exec(s->sql, 
42222 -                                       "CREATE TABLE properties ("
42223 +
42224 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42225 +                               CONST_STR_LEN("REPLACE INTO properties (resource, prop, ns, value) VALUES (?, ?, ?, ?)"),
42226 +                               &(s->stmt_update_prop), &next_stmt)) {
42227 +                               /* prepare failed */
42228 +
42229 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
42230 +                               return HANDLER_ERROR;
42231 +                       }
42232 +
42233 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42234 +                               CONST_STR_LEN("DELETE FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
42235 +                               &(s->stmt_delete_prop), &next_stmt)) {
42236 +                               /* prepare failed */
42237 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42238 +
42239 +                               return HANDLER_ERROR;
42240 +                       }
42241 +
42242 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42243 +                               CONST_STR_LEN("DELETE FROM properties WHERE resource = ?"),
42244 +                               &(s->stmt_delete_uri), &next_stmt)) {
42245 +                               /* prepare failed */
42246 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42247 +
42248 +                               return HANDLER_ERROR;
42249 +                       }
42250 +
42251 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42252 +                               CONST_STR_LEN("INSERT INTO properties SELECT ?, prop, ns, value FROM properties WHERE resource = ?"),
42253 +                               &(s->stmt_copy_uri), &next_stmt)) {
42254 +                               /* prepare failed */
42255 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42256 +
42257 +                               return HANDLER_ERROR;
42258 +                       }
42259 +
42260 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42261 +                               CONST_STR_LEN("UPDATE properties SET resource = ? WHERE resource = ?"),
42262 +                               &(s->stmt_move_uri), &next_stmt)) {
42263 +                               /* prepare failed */
42264 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42265 +
42266 +                               return HANDLER_ERROR;
42267 +                       }
42268 +
42269 +                       /* LOCKS */
42270 +
42271 +                       if (SQLITE_OK != sqlite3_exec(s->sql,
42272 +                                       "CREATE TABLE locks ("
42273 +                                       "  locktoken TEXT NOT NULL,"
42274                                         "  resource TEXT NOT NULL,"
42275 -                                       "  prop TEXT NOT NULL,"
42276 -                                       "  ns TEXT NOT NULL,"
42277 -                                       "  value TEXT NOT NULL,"
42278 -                                       "  PRIMARY KEY(resource, prop, ns))",
42279 +                                       "  lockscope TEXT NOT NULL,"
42280 +                                       "  locktype TEXT NOT NULL,"
42281 +                                       "  owner TEXT NOT NULL,"
42282 +                                       "  depth INT NOT NULL,"
42283 +                                       "  timeout TIMESTAMP NOT NULL,"
42284 +                                       "  PRIMARY KEY(locktoken))",
42285                                         NULL, NULL, &err)) {
42286  
42287 -                               if (0 != strcmp(err, "table properties already exists")) {
42288 +                               if (0 != strcmp(err, "table locks already exists")) {
42289                                         log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
42290                                         sqlite3_free(err);
42291  
42292 @@ -228,127 +314,138 @@
42293                                 }
42294                                 sqlite3_free(err);
42295                         }
42296 -       
42297 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42298 -                               CONST_STR_LEN("REPLACE INTO properties (resource, prop, ns, value) VALUES (?, ?, ?, ?)"), 
42299 -                               &(s->stmt_update_prop), &next_stmt)) {
42300 +
42301 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42302 +                               CONST_STR_LEN("INSERT INTO locks (locktoken, resource, lockscope, locktype, owner, depth, timeout) VALUES (?,?,?,?,?,?, CURRENT_TIME + 600)"),
42303 +                               &(s->stmt_create_lock), &next_stmt)) {
42304                                 /* prepare failed */
42305 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42306  
42307 -                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
42308                                 return HANDLER_ERROR;
42309                         }
42310  
42311 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42312 -                               CONST_STR_LEN("DELETE FROM properties WHERE resource = ? AND prop = ? AND ns = ?"), 
42313 -                               &(s->stmt_delete_prop), &next_stmt)) {
42314 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42315 +                               CONST_STR_LEN("DELETE FROM locks WHERE locktoken = ?"),
42316 +                               &(s->stmt_remove_lock), &next_stmt)) {
42317                                 /* prepare failed */
42318                                 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42319  
42320                                 return HANDLER_ERROR;
42321                         }
42322  
42323 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42324 -                               CONST_STR_LEN("DELETE FROM properties WHERE resource = ?"), 
42325 -                               &(s->stmt_delete_uri), &next_stmt)) {
42326 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42327 +                               CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout FROM locks WHERE locktoken = ?"),
42328 +                               &(s->stmt_read_lock), &next_stmt)) {
42329                                 /* prepare failed */
42330                                 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42331  
42332                                 return HANDLER_ERROR;
42333                         }
42334  
42335 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42336 -                               CONST_STR_LEN("INSERT INTO properties SELECT ?, prop, ns, value FROM properties WHERE resource = ?"), 
42337 -                               &(s->stmt_copy_uri), &next_stmt)) {
42338 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42339 +                               CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout FROM locks WHERE resource = ?"),
42340 +                               &(s->stmt_read_lock_by_uri), &next_stmt)) {
42341                                 /* prepare failed */
42342                                 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42343  
42344                                 return HANDLER_ERROR;
42345                         }
42346  
42347 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42348 -                               CONST_STR_LEN("UPDATE properties SET resource = ? WHERE resource = ?"), 
42349 -                               &(s->stmt_move_uri), &next_stmt)) {
42350 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42351 +                               CONST_STR_LEN("UPDATE locks SET timeout = CURRENT_TIME + 600 WHERE locktoken = ?"),
42352 +                               &(s->stmt_refresh_lock), &next_stmt)) {
42353                                 /* prepare failed */
42354                                 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42355  
42356                                 return HANDLER_ERROR;
42357                         }
42358 +
42359 +
42360  #else
42361                         log_error_write(srv, __FILE__, __LINE__, "s", "Sorry, no sqlite3 and libxml2 support include, compile with --with-webdav-props");
42362                         return HANDLER_ERROR;
42363  #endif
42364                 }
42365         }
42366 -       
42367 +
42368         return HANDLER_GO_ON;
42369  }
42370  
42371 -#define PATCH(x) \
42372 -       p->conf.x = s->x;
42373  static int mod_webdav_patch_connection(server *srv, connection *con, plugin_data *p) {
42374         size_t i, j;
42375         plugin_config *s = p->config_storage[0];
42376 -       
42377 -       PATCH(enabled);
42378 -       PATCH(is_readonly);
42379 -       PATCH(log_xml);
42380 -       
42381 +
42382 +       PATCH_OPTION(enabled);
42383 +       PATCH_OPTION(is_readonly);
42384 +       PATCH_OPTION(log_xml);
42385 +
42386  #ifdef USE_PROPPATCH
42387 -       PATCH(sql);
42388 -       PATCH(stmt_update_prop);
42389 -       PATCH(stmt_delete_prop);
42390 -       PATCH(stmt_select_prop);
42391 -       PATCH(stmt_select_propnames);
42392 -
42393 -       PATCH(stmt_delete_uri);
42394 -       PATCH(stmt_move_uri);
42395 -       PATCH(stmt_copy_uri);
42396 +       PATCH_OPTION(sql);
42397 +       PATCH_OPTION(stmt_update_prop);
42398 +       PATCH_OPTION(stmt_delete_prop);
42399 +       PATCH_OPTION(stmt_select_prop);
42400 +       PATCH_OPTION(stmt_select_propnames);
42401 +
42402 +       PATCH_OPTION(stmt_delete_uri);
42403 +       PATCH_OPTION(stmt_move_uri);
42404 +       PATCH_OPTION(stmt_copy_uri);
42405 +
42406 +       PATCH_OPTION(stmt_remove_lock);
42407 +       PATCH_OPTION(stmt_refresh_lock);
42408 +       PATCH_OPTION(stmt_create_lock);
42409 +       PATCH_OPTION(stmt_read_lock);
42410 +       PATCH_OPTION(stmt_read_lock_by_uri);
42411  #endif
42412         /* skip the first, the global context */
42413         for (i = 1; i < srv->config_context->used; i++) {
42414                 data_config *dc = (data_config *)srv->config_context->data[i];
42415                 s = p->config_storage[i];
42416 -               
42417 +
42418                 /* condition didn't match */
42419                 if (!config_check_cond(srv, con, dc)) continue;
42420 -               
42421 +
42422                 /* merge config */
42423                 for (j = 0; j < dc->value->used; j++) {
42424                         data_unset *du = dc->value->data[j];
42425 -                       
42426 +
42427                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.activate"))) {
42428 -                               PATCH(enabled);
42429 +                               PATCH_OPTION(enabled);
42430                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.is-readonly"))) {
42431 -                               PATCH(is_readonly);
42432 +                               PATCH_OPTION(is_readonly);
42433                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.log-xml"))) {
42434 -                               PATCH(log_xml);
42435 +                               PATCH_OPTION(log_xml);
42436                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.sqlite-db-name"))) {
42437  #ifdef USE_PROPPATCH
42438 -                               PATCH(sql);
42439 -                               PATCH(stmt_update_prop);
42440 -                               PATCH(stmt_delete_prop);
42441 -                               PATCH(stmt_select_prop);
42442 -                               PATCH(stmt_select_propnames);
42443 -                               
42444 -                               PATCH(stmt_delete_uri);
42445 -                               PATCH(stmt_move_uri);
42446 -                               PATCH(stmt_copy_uri);
42447 +                               PATCH_OPTION(sql);
42448 +                               PATCH_OPTION(stmt_update_prop);
42449 +                               PATCH_OPTION(stmt_delete_prop);
42450 +                               PATCH_OPTION(stmt_select_prop);
42451 +                               PATCH_OPTION(stmt_select_propnames);
42452 +
42453 +                               PATCH_OPTION(stmt_delete_uri);
42454 +                               PATCH_OPTION(stmt_move_uri);
42455 +                               PATCH_OPTION(stmt_copy_uri);
42456 +
42457 +                               PATCH_OPTION(stmt_remove_lock);
42458 +                               PATCH_OPTION(stmt_refresh_lock);
42459 +                               PATCH_OPTION(stmt_create_lock);
42460 +                               PATCH_OPTION(stmt_read_lock);
42461 +                               PATCH_OPTION(stmt_read_lock_by_uri);
42462  #endif
42463                         }
42464                 }
42465         }
42466 -       
42467 +
42468         return 0;
42469  }
42470 -#undef PATCH
42471  
42472  URIHANDLER_FUNC(mod_webdav_uri_handler) {
42473         plugin_data *p = p_d;
42474 -       
42475 +
42476         UNUSED(srv);
42477  
42478         if (con->uri.path->used == 0) return HANDLER_GO_ON;
42479 -       
42480 +
42481         mod_webdav_patch_connection(srv, con, p);
42482  
42483         if (!p->conf.enabled) return HANDLER_GO_ON;
42484 @@ -362,20 +459,20 @@
42485                 if (p->conf.is_readonly) {
42486                         response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND"));
42487                 } else {
42488 -                       response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH"));
42489 +                       response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH, LOCK, UNLOCK"));
42490                 }
42491                 break;
42492         default:
42493                 break;
42494         }
42495 -       
42496 +
42497         /* not found */
42498         return HANDLER_GO_ON;
42499  }
42500 -static int webdav_gen_prop_tag(server *srv, connection *con, 
42501 -               char *prop_name, 
42502 -               char *prop_ns, 
42503 -               char *value, 
42504 +static int webdav_gen_prop_tag(server *srv, connection *con,
42505 +               char *prop_name,
42506 +               char *prop_ns,
42507 +               char *value,
42508                 buffer *b) {
42509  
42510         UNUSED(srv);
42511 @@ -414,7 +511,7 @@
42512         buffer_append_string_buffer(b, dst->rel_path);
42513         buffer_append_string(b,"</D:href>\n");
42514         buffer_append_string(b,"<D:status>\n");
42515 -       
42516 +
42517         if (con->request.http_version == HTTP_VERSION_1_1) {
42518                 BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 ");
42519         } else {
42520 @@ -458,14 +555,13 @@
42521  
42522                         /* bind the values to the insert */
42523  
42524 -                       sqlite3_bind_text(stmt, 1, 
42525 -                                         dst->rel_path->ptr, 
42526 +                       sqlite3_bind_text(stmt, 1,
42527 +                                         dst->rel_path->ptr,
42528                                           dst->rel_path->used - 1,
42529                                           SQLITE_TRANSIENT);
42530 -                                                                       
42531 +
42532                         if (SQLITE_DONE != sqlite3_step(stmt)) {
42533                                 /* */
42534 -                               WP();
42535                         }
42536                 }
42537  #endif
42538 @@ -493,14 +589,14 @@
42539                             (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
42540                                 continue;
42541                                 /* ignore the parent dir */
42542 -                       } 
42543 +                       }
42544  
42545                         buffer_copy_string_buffer(d.path, dst->path);
42546 -                       BUFFER_APPEND_SLASH(d.path);
42547 +                       PATHNAME_APPEND_SLASH(d.path);
42548                         buffer_append_string(d.path, de->d_name);
42549 -                       
42550 +
42551                         buffer_copy_string_buffer(d.rel_path, dst->rel_path);
42552 -                       BUFFER_APPEND_SLASH(d.rel_path);
42553 +                       PATHNAME_APPEND_SLASH(d.rel_path);
42554                         buffer_append_string(d.rel_path, de->d_name);
42555  
42556                         /* stat and unlink afterwards */
42557 @@ -508,7 +604,7 @@
42558                                 /* don't about it yet, rmdir will fail too */
42559                         } else if (S_ISDIR(st.st_mode)) {
42560                                 have_multi_status = webdav_delete_dir(srv, con, p, &d, b);
42561 -                                       
42562 +
42563                                 /* try to unlink it */
42564                                 if (-1 == rmdir(d.path->ptr)) {
42565                                         switch(errno) {
42566 @@ -535,14 +631,13 @@
42567  
42568                                                 /* bind the values to the insert */
42569  
42570 -                                               sqlite3_bind_text(stmt, 1, 
42571 -                                                                 d.rel_path->ptr, 
42572 +                                               sqlite3_bind_text(stmt, 1,
42573 +                                                                 d.rel_path->ptr,
42574                                                                   d.rel_path->used - 1,
42575                                                                   SQLITE_TRANSIENT);
42576 -                                                                                                       
42577 +
42578                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {
42579                                                         /* */
42580 -                                                       WP();
42581                                                 }
42582                                         }
42583  #endif
42584 @@ -569,7 +664,7 @@
42585         if (stream_open(&s, src->path)) {
42586                 return 403;
42587         }
42588 -                       
42589 +
42590         if (-1 == (ofd = open(dst->path->ptr, O_WRONLY|O_TRUNC|O_CREAT|(overwrite ? 0 : O_EXCL), 0600))) {
42591                 /* opening the destination failed for some reason */
42592                 switch(errno) {
42593 @@ -601,7 +696,7 @@
42594                         break;
42595                 }
42596         }
42597 -       
42598 +
42599         stream_close(&s);
42600         close(ofd);
42601  
42602 @@ -614,19 +709,18 @@
42603                         sqlite3_reset(stmt);
42604  
42605                         /* bind the values to the insert */
42606 -                       sqlite3_bind_text(stmt, 1, 
42607 -                                         dst->rel_path->ptr, 
42608 +                       sqlite3_bind_text(stmt, 1,
42609 +                                         dst->rel_path->ptr,
42610                                           dst->rel_path->used - 1,
42611                                           SQLITE_TRANSIENT);
42612  
42613 -                       sqlite3_bind_text(stmt, 2, 
42614 -                                         src->rel_path->ptr, 
42615 +                       sqlite3_bind_text(stmt, 2,
42616 +                                         src->rel_path->ptr,
42617                                           src->rel_path->used - 1,
42618                                           SQLITE_TRANSIENT);
42619 -                                                                                                       
42620 +
42621                         if (SQLITE_DONE != sqlite3_step(stmt)) {
42622                                 /* */
42623 -                               WP();
42624                         }
42625                 }
42626         }
42627 @@ -655,21 +749,21 @@
42628                             (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
42629                                 continue;
42630                         }
42631 -                       
42632 +
42633                         buffer_copy_string_buffer(s.path, src->path);
42634 -                       BUFFER_APPEND_SLASH(s.path);
42635 +                       PATHNAME_APPEND_SLASH(s.path);
42636                         buffer_append_string(s.path, de->d_name);
42637  
42638                         buffer_copy_string_buffer(d.path, dst->path);
42639 -                       BUFFER_APPEND_SLASH(d.path);
42640 +                       PATHNAME_APPEND_SLASH(d.path);
42641                         buffer_append_string(d.path, de->d_name);
42642  
42643                         buffer_copy_string_buffer(s.rel_path, src->rel_path);
42644 -                       BUFFER_APPEND_SLASH(s.rel_path);
42645 +                       PATHNAME_APPEND_SLASH(s.rel_path);
42646                         buffer_append_string(s.rel_path, de->d_name);
42647  
42648                         buffer_copy_string_buffer(d.rel_path, dst->rel_path);
42649 -                       BUFFER_APPEND_SLASH(d.rel_path);
42650 +                       PATHNAME_APPEND_SLASH(d.rel_path);
42651                         buffer_append_string(d.rel_path, de->d_name);
42652  
42653                         if (-1 == stat(s.path->ptr, &st)) {
42654 @@ -692,19 +786,18 @@
42655                                                 sqlite3_reset(stmt);
42656  
42657                                                 /* bind the values to the insert */
42658 -                                               sqlite3_bind_text(stmt, 1, 
42659 -                                                         dst->rel_path->ptr, 
42660 +                                               sqlite3_bind_text(stmt, 1,
42661 +                                                         dst->rel_path->ptr,
42662                                                           dst->rel_path->used - 1,
42663                                                           SQLITE_TRANSIENT);
42664  
42665 -                                               sqlite3_bind_text(stmt, 2, 
42666 -                                                         src->rel_path->ptr, 
42667 +                                               sqlite3_bind_text(stmt, 2,
42668 +                                                         src->rel_path->ptr,
42669                                                           src->rel_path->used - 1,
42670                                                           SQLITE_TRANSIENT);
42671 -                                                                                                       
42672 +
42673                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {
42674                                                         /* */
42675 -                                                       WP();
42676                                                 }
42677                                         }
42678  #endif
42679 @@ -721,7 +814,7 @@
42680                 buffer_free(s.rel_path);
42681                 buffer_free(d.path);
42682                 buffer_free(d.rel_path);
42683 -               
42684 +
42685                 closedir(srcdir);
42686         }
42687  
42688 @@ -748,12 +841,12 @@
42689                         if (S_ISDIR(sce->st.st_mode)) {
42690                                 buffer_append_string(b, "<D:getcontenttype>httpd/unix-directory</D:getcontenttype>");
42691                                 found = 1;
42692 -                       } else if(S_ISREG(sce->st.st_mode)) { 
42693 +                       } else if(S_ISREG(sce->st.st_mode)) {
42694                                 for (k = 0; k < con->conf.mimetypes->used; k++) {
42695                                         data_string *ds = (data_string *)con->conf.mimetypes->data[k];
42696 -               
42697 +
42698                                         if (ds->key->used == 0) continue;
42699 -                               
42700 +
42701                                         if (buffer_is_equal_right_len(dst->path, ds->key, ds->key->used - 1)) {
42702                                                 buffer_append_string(b,"<D:getcontenttype>");
42703                                                 buffer_append_string_buffer(b, ds->value);
42704 @@ -807,23 +900,23 @@
42705  
42706                         /* bind the values to the insert */
42707  
42708 -                       sqlite3_bind_text(stmt, 1, 
42709 -                                         dst->rel_path->ptr, 
42710 +                       sqlite3_bind_text(stmt, 1,
42711 +                                         dst->rel_path->ptr,
42712                                           dst->rel_path->used - 1,
42713                                           SQLITE_TRANSIENT);
42714 -                       sqlite3_bind_text(stmt, 2, 
42715 +                       sqlite3_bind_text(stmt, 2,
42716                                           prop_name,
42717                                           strlen(prop_name),
42718                                           SQLITE_TRANSIENT);
42719 -                       sqlite3_bind_text(stmt, 3, 
42720 +                       sqlite3_bind_text(stmt, 3,
42721                                           prop_ns,
42722                                           strlen(prop_ns),
42723                                           SQLITE_TRANSIENT);
42724  
42725                         /* it is the PK */
42726 -                       while (SQLITE_ROW == sqlite3_step(p->conf.stmt_select_prop)) {
42727 +                       while (SQLITE_ROW == sqlite3_step(stmt)) {
42728                                 /* there is a row for us, we only expect a single col 'value' */
42729 -                               webdav_gen_prop_tag(srv, con, prop_name, prop_ns, (char *)sqlite3_column_text(p->conf.stmt_select_prop, 0), b);
42730 +                               webdav_gen_prop_tag(srv, con, prop_name, prop_ns, (char *)sqlite3_column_text(stmt, 0), b);
42731                                 found = 1;
42732                         }
42733                 }
42734 @@ -840,7 +933,7 @@
42735         char *prop;
42736  } webdav_property;
42737  
42738 -webdav_property live_properties[] = { 
42739 +webdav_property live_properties[] = {
42740         { "DAV:", "creationdate" },
42741         { "DAV:", "displayname" },
42742         { "DAV:", "getcontentlanguage" },
42743 @@ -871,8 +964,8 @@
42744                         webdav_property *prop;
42745  
42746                         prop = props->ptr[i];
42747 -                       
42748 -                       if (0 != webdav_get_property(srv, con, p, 
42749 +
42750 +                       if (0 != webdav_get_property(srv, con, p,
42751                                 dst, prop->prop, prop->ns, b_200)) {
42752                                 webdav_gen_prop_tag(srv, con, prop->prop, prop->ns, NULL, b_404);
42753                         }
42754 @@ -916,12 +1009,12 @@
42755                                 if (-1 == c->file.fd &&  /* open the file if not already open */
42756                                     -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
42757                                         log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
42758 -               
42759 +
42760                                         return -1;
42761                                 }
42762 -       
42763 +
42764                                 if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
42765 -                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ", 
42766 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
42767                                                         strerror(errno), c->file.name,  c->file.fd);
42768  
42769                                         return -1;
42770 @@ -938,7 +1031,7 @@
42771                         if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->file.mmap.start + c->offset, weHave, 0))) {
42772                                 log_error_write(srv, __FILE__, __LINE__, "sddd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
42773                         }
42774 -                       
42775 +
42776                         c->offset += weHave;
42777                         cq->bytes_out += weHave;
42778  
42779 @@ -956,7 +1049,7 @@
42780                         if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->mem->ptr + c->offset, weHave, 0))) {
42781                                 log_error_write(srv, __FILE__, __LINE__, "sddd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
42782                         }
42783 -                       
42784 +
42785                         c->offset += weHave;
42786                         cq->bytes_out += weHave;
42787  
42788 @@ -991,6 +1084,113 @@
42789  }
42790  #endif
42791  
42792 +int webdav_lockdiscovery(server *srv, connection *con,
42793 +               buffer *locktoken, const char *lockscope, const char *locktype, int depth) {
42794 +
42795 +       buffer *b;
42796 +
42797 +       response_header_overwrite(srv, con, CONST_STR_LEN("Lock-Token"), CONST_BUF_LEN(locktoken));
42798 +
42799 +       response_header_overwrite(srv, con,
42800 +               CONST_STR_LEN("Content-Type"),
42801 +               CONST_STR_LEN("text/xml; charset=\"utf-8\""));
42802 +
42803 +       b = chunkqueue_get_append_buffer(con->write_queue);
42804 +
42805 +       buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
42806 +
42807 +       buffer_append_string(b,"<D:prop xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n");
42808 +       buffer_append_string(b,"<D:lockdiscovery>\n");
42809 +       buffer_append_string(b,"<D:activelock>\n");
42810 +
42811 +       buffer_append_string(b,"<D:lockscope>");
42812 +       buffer_append_string(b,"<D:");
42813 +       buffer_append_string(b, lockscope);
42814 +       buffer_append_string(b, "/>");
42815 +       buffer_append_string(b,"</D:lockscope>\n");
42816 +
42817 +       buffer_append_string(b,"<D:locktype>");
42818 +       buffer_append_string(b,"<D:");
42819 +       buffer_append_string(b, locktype);
42820 +       buffer_append_string(b, "/>");
42821 +       buffer_append_string(b,"</D:locktype>\n");
42822 +
42823 +       buffer_append_string(b,"<D:depth>");
42824 +       buffer_append_string(b, depth == 0 ? "0" : "infinity");
42825 +       buffer_append_string(b,"</D:depth>\n");
42826 +
42827 +       buffer_append_string(b,"<D:timeout>");
42828 +       buffer_append_string(b, "Second-600");
42829 +       buffer_append_string(b,"</D:timeout>\n");
42830 +
42831 +       buffer_append_string(b,"<D:owner>");
42832 +       buffer_append_string(b,"</D:owner>\n");
42833 +
42834 +       buffer_append_string(b,"<D:locktoken>");
42835 +       buffer_append_string(b, "<D:href>");
42836 +       buffer_append_string_buffer(b, locktoken);
42837 +       buffer_append_string(b, "</D:href>");
42838 +       buffer_append_string(b,"</D:locktoken>\n");
42839 +
42840 +       buffer_append_string(b,"</D:activelock>\n");
42841 +       buffer_append_string(b,"</D:lockdiscovery>\n");
42842 +       buffer_append_string(b,"</D:prop>\n");
42843 +
42844 +       return 0;
42845 +}
42846 +/**
42847 + * check if resource is having the right locks to access to resource
42848 + *
42849 + *
42850 + *
42851 + */
42852 +int webdav_has_lock(server *srv, connection *con, plugin_data *p, buffer *uri) {
42853 +       int has_lock = 1;
42854 +
42855 +#ifdef USE_LOCKS
42856 +       data_string *ds;
42857 +
42858 +       /**
42859 +        * If can have
42860 +        * - <lock-token>
42861 +        * - [etag]
42862 +        *
42863 +        * there is NOT, AND and OR
42864 +        * and a list can be tagged
42865 +        *
42866 +        * (<lock-token>) is untagged
42867 +        * <tag> (<lock-token>) is tagged
42868 +        *
42869 +        * as long as we don't handle collections it is simple. :)
42870 +        *
42871 +        * X-Litmus: locks: 11 (owner_modify)
42872 +        * If: <http://127.0.0.1:1025/dav/litmus/lockme> (<opaquelocktoken:2165478d-0611-49c4-be92-e790d68a38f1>)
42873 +        *
42874 +        * X-Litmus: locks: 16 (fail_cond_put)
42875 +        * If: (<DAV:no-lock> ["-1622396671"])
42876 +        */
42877 +       if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
42878 +       } else {
42879 +               /* we didn't provided a lock-token -> */
42880 +               /* if the resource is locked -> 423 */
42881 +
42882 +               sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
42883 +
42884 +               sqlite3_reset(stmt);
42885 +
42886 +               sqlite3_bind_text(stmt, 1,
42887 +                         CONST_BUF_LEN(uri),
42888 +                         SQLITE_TRANSIENT);
42889 +
42890 +               while (SQLITE_ROW == sqlite3_step(stmt)) {
42891 +                       has_lock = 0;
42892 +               }
42893 +       }
42894 +#endif
42895 +
42896 +       return has_lock;
42897 +}
42898 +
42899  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
42900         plugin_data *p = p_d;
42901         buffer *b;
42902 @@ -1001,7 +1201,8 @@
42903         buffer *prop_200;
42904         buffer *prop_404;
42905         webdav_properties *req_props;
42906 -       
42907 +       stat_cache_entry *sce = NULL;
42908 +
42909         UNUSED(srv);
42910  
42911         if (!p->conf.enabled) return HANDLER_GO_ON;
42912 @@ -1019,7 +1220,19 @@
42913                 req_props = NULL;
42914  
42915                 /* is there a content-body ? */
42916 -       
42917 +
42918 +               switch (stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
42919 +               case HANDLER_ERROR:
42920 +                       if (errno == ENOENT) {
42921 +                               con->http_status = 404;
42922 +                               return HANDLER_FINISHED;
42923 +                       }
42924 +                       break;
42925 +               default:
42926 +                       break;
42927 +               }
42928 +
42929 +
42930  #ifdef USE_PROPPATCH
42931                 /* any special requests or just allprop ? */
42932                 if (con->request.content_length) {
42933 @@ -1087,14 +1300,13 @@
42934                                                                 /* get all property names (EMPTY) */
42935                                                                 sqlite3_reset(stmt);
42936                                                                 /* bind the values to the insert */
42937 -       
42938 -                                                               sqlite3_bind_text(stmt, 1, 
42939 -                                                                                 con->uri.path->ptr, 
42940 +
42941 +                                                               sqlite3_bind_text(stmt, 1,
42942 +                                                                                 con->uri.path->ptr,
42943                                                                                   con->uri.path->used - 1,
42944                                                                                   SQLITE_TRANSIENT);
42945 -                                               
42946 +
42947                                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {
42948 -                                                                       WP();
42949                                                                 }
42950                                                         }
42951                                                 } else if (0 == xmlStrcmp(cmd->name, BAD_CAST "allprop")) {
42952 @@ -1115,13 +1327,13 @@
42953                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
42954  
42955                 b = chunkqueue_get_append_buffer(con->write_queue);
42956 -                               
42957 +
42958                 buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
42959  
42960                 buffer_append_string(b,"<D:multistatus xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n");
42961  
42962                 /* allprop */
42963 -               
42964 +
42965                 prop_200 = buffer_init();
42966                 prop_404 = buffer_init();
42967  
42968 @@ -1129,7 +1341,7 @@
42969                 case 0:
42970                         /* Depth: 0 */
42971                         webdav_get_props(srv, con, p, &(con->physical), req_props, prop_200, prop_404);
42972 -       
42973 +
42974                         buffer_append_string(b,"<D:response>\n");
42975                         buffer_append_string(b,"<D:href>");
42976                         buffer_append_string_buffer(b, con->uri.scheme);
42977 @@ -1145,9 +1357,9 @@
42978                                 buffer_append_string_buffer(b, prop_200);
42979  
42980                                 buffer_append_string(b,"</D:prop>\n");
42981 -       
42982 +
42983                                 buffer_append_string(b,"<D:status>HTTP/1.1 200 OK</D:status>\n");
42984 -       
42985 +
42986                                 buffer_append_string(b,"</D:propstat>\n");
42987                         }
42988                         if (!buffer_is_empty(prop_404)) {
42989 @@ -1157,16 +1369,16 @@
42990                                 buffer_append_string_buffer(b, prop_404);
42991  
42992                                 buffer_append_string(b,"</D:prop>\n");
42993 -       
42994 +
42995                                 buffer_append_string(b,"<D:status>HTTP/1.1 404 Not Found</D:status>\n");
42996 -       
42997 +
42998                                 buffer_append_string(b,"</D:propstat>\n");
42999                         }
43000  
43001                         buffer_append_string(b,"</D:response>\n");
43002  
43003                         break;
43004 -               case 1: 
43005 +               case 1:
43006                         if (NULL != (dir = opendir(con->physical.path->ptr))) {
43007                                 struct dirent *de;
43008                                 physical d;
43009 @@ -1179,16 +1391,16 @@
43010                                         if (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0') {
43011                                                 continue;
43012                                                 /* ignore the parent dir */
43013 -                                       } 
43014 +                                       }
43015  
43016                                         buffer_copy_string_buffer(d.path, dst->path);
43017 -                                       BUFFER_APPEND_SLASH(d.path);
43018 +                                       PATHNAME_APPEND_SLASH(d.path);
43019  
43020                                         buffer_copy_string_buffer(d.rel_path, dst->rel_path);
43021 -                                       BUFFER_APPEND_SLASH(d.rel_path);
43022 +                                       PATHNAME_APPEND_SLASH(d.rel_path);
43023  
43024                                         if (de->d_name[0] == '.' && de->d_name[1] == '\0') {
43025 -                                               /* don't append the . */ 
43026 +                                               /* don't append the . */
43027                                         } else {
43028                                                 buffer_append_string(d.path, de->d_name);
43029                                                 buffer_append_string(d.rel_path, de->d_name);
43030 @@ -1198,7 +1410,7 @@
43031                                         buffer_reset(prop_404);
43032  
43033                                         webdav_get_props(srv, con, p, &d, req_props, prop_200, prop_404);
43034 -                                       
43035 +
43036                                         buffer_append_string(b,"<D:response>\n");
43037                                         buffer_append_string(b,"<D:href>");
43038                                         buffer_append_string_buffer(b, con->uri.scheme);
43039 @@ -1214,9 +1426,9 @@
43040                                                 buffer_append_string_buffer(b, prop_200);
43041  
43042                                                 buffer_append_string(b,"</D:prop>\n");
43043 -                       
43044 +
43045                                                 buffer_append_string(b,"<D:status>HTTP/1.1 200 OK</D:status>\n");
43046 -                       
43047 +
43048                                                 buffer_append_string(b,"</D:propstat>\n");
43049                                         }
43050                                         if (!buffer_is_empty(prop_404)) {
43051 @@ -1226,9 +1438,9 @@
43052                                                 buffer_append_string_buffer(b, prop_404);
43053  
43054                                                 buffer_append_string(b,"</D:prop>\n");
43055 -       
43056 +
43057                                                 buffer_append_string(b,"<D:status>HTTP/1.1 404 Not Found</D:status>\n");
43058 -       
43059 +
43060                                                 buffer_append_string(b,"</D:propstat>\n");
43061                                         }
43062  
43063 @@ -1275,7 +1487,7 @@
43064  
43065                         return HANDLER_FINISHED;
43066                 }
43067 -       
43068 +
43069                 /* let's create the directory */
43070  
43071                 if (-1 == mkdir(con->physical.path->ptr, 0700)) {
43072 @@ -1303,7 +1515,13 @@
43073                         con->http_status = 403;
43074                         return HANDLER_FINISHED;
43075                 }
43076 -               
43077 +
43078 +               /* does the client have a lock for this connection ? */
43079 +               if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43080 +                       con->http_status = 423;
43081 +                       return HANDLER_FINISHED;
43082 +               }
43083 +
43084                 /* stat and unlink afterwards */
43085                 if (-1 == stat(con->physical.path->ptr, &st)) {
43086                         /* don't about it yet, unlink will fail too */
43087 @@ -1323,7 +1541,7 @@
43088                                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
43089  
43090                                 b = chunkqueue_get_append_buffer(con->write_queue);
43091 -                       
43092 +
43093                                 buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
43094  
43095                                 buffer_append_string(b,"<D:multistatus xmlns:D=\"DAV:\">\n");
43096 @@ -1331,7 +1549,7 @@
43097                                 buffer_append_string_buffer(b, multi_status_resp);
43098  
43099                                 buffer_append_string(b,"</D:multistatus>\n");
43100 -                       
43101 +
43102                                 if (p->conf.log_xml) {
43103                                         log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b);
43104                                 }
43105 @@ -1340,7 +1558,7 @@
43106                                 con->file_finished = 1;
43107                         } else {
43108                                 /* everything went fine, remove the directory */
43109 -       
43110 +
43111                                 if (-1 == rmdir(con->physical.path->ptr)) {
43112                                         switch(errno) {
43113                                         case ENOENT:
43114 @@ -1375,97 +1593,174 @@
43115         case HTTP_METHOD_PUT: {
43116                 int fd;
43117                 chunkqueue *cq = con->request_content_queue;
43118 +               chunk *c;
43119 +               data_string *ds_range;
43120  
43121                 if (p->conf.is_readonly) {
43122                         con->http_status = 403;
43123                         return HANDLER_FINISHED;
43124                 }
43125  
43126 +               /* is a exclusive lock set on the source */
43127 +               if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43128 +                       con->http_status = 423;
43129 +                       return HANDLER_FINISHED;
43130 +               }
43131 +
43132 +
43133                 assert(chunkqueue_length(cq) == (off_t)con->request.content_length);
43134  
43135 -               /* taken what we have in the request-body and write it to a file */
43136 -               if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC, 0600))) {
43137 -                       /* we can't open the file */
43138 -                       con->http_status = 403;
43139 -               } else {
43140 -                       chunk *c;
43141 +               /* RFC2616 Section 9.6 PUT requires us to send 501 on all Content-* we don't support
43142 +                * - most important Content-Range
43143 +                *
43144 +                *
43145 +                * Example: Content-Range: bytes 100-1037/1038 */
43146  
43147 -                       con->http_status = 201; /* created */
43148 -                       con->file_finished = 1;
43149 +               if (NULL != (ds_range = (data_string *)array_get_element(con->request.headers, "Content-Range"))) {
43150 +                       const char *num = ds_range->value->ptr;
43151 +                       off_t offset;
43152 +                       char *err = NULL;
43153  
43154 -                       for (c = cq->first; c; c = cq->first) {
43155 -                               int r = 0; 
43156 +                       if (0 != strncmp(num, "bytes ", 6)) {
43157 +                               con->http_status = 501; /* not implemented */
43158  
43159 -                               /* copy all chunks */
43160 -                               switch(c->type) {
43161 -                               case FILE_CHUNK:
43162 -
43163 -                                       if (c->file.mmap.start == MAP_FAILED) {
43164 -                                               if (-1 == c->file.fd &&  /* open the file if not already open */
43165 -                                                   -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
43166 -                                                       log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
43167 -                                       
43168 -                                                       return -1;
43169 -                                               }
43170 -                               
43171 -                                               if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
43172 -                                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ", 
43173 -                                                                       strerror(errno), c->file.name,  c->file.fd);
43174 +                               return HANDLER_FINISHED;
43175 +                       }
43176  
43177 -                                                       return -1;
43178 -                                               }
43179 +                       /* we only support <num>- ... */
43180  
43181 -                                               c->file.mmap.length = c->file.length;
43182 +                       num += 6;
43183  
43184 -                                               close(c->file.fd);
43185 -                                               c->file.fd = -1;
43186 -       
43187 -                                               /* chunk_reset() or chunk_free() will cleanup for us */
43188 -                                       }
43189 -
43190 -                                       if ((r = write(fd, c->file.mmap.start + c->offset, c->file.length - c->offset)) < 0) {
43191 -                                               switch(errno) {
43192 -                                               case ENOSPC:
43193 -                                                       con->http_status = 507;
43194 -               
43195 -                                                       break;
43196 -                                               default:
43197 -                                                       con->http_status = 403;
43198 -                                                       break;
43199 -                                               }
43200 -                                       }
43201 -                                       break;
43202 -                               case MEM_CHUNK:
43203 -                                       if ((r = write(fd, c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) {
43204 -                                               switch(errno) {
43205 -                                               case ENOSPC:
43206 -                                                       con->http_status = 507;
43207 -               
43208 -                                                       break;
43209 -                                               default:
43210 -                                                       con->http_status = 403;
43211 -                                                       break;
43212 -                                               }
43213 -                                       }
43214 +                       /* skip WS */
43215 +                       while (*num == ' ' || *num == '\t') num++;
43216 +
43217 +                       if (*num == '\0') {
43218 +                               con->http_status = 501; /* not implemented */
43219 +
43220 +                               return HANDLER_FINISHED;
43221 +                       }
43222 +
43223 +                       offset = strtoll(num, &err, 10);
43224 +
43225 +                       if (*err != '-' || offset < 0) {
43226 +                               con->http_status = 501; /* not implemented */
43227 +
43228 +                               return HANDLER_FINISHED;
43229 +                       }
43230 +
43231 +                       if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY, 0600))) {
43232 +                               switch (errno) {
43233 +                               case ENOENT:
43234 +                                       con->http_status = 404; /* not found */
43235                                         break;
43236 -                               case UNUSED_CHUNK:
43237 +                               default:
43238 +                                       con->http_status = 403; /* not found */
43239                                         break;
43240                                 }
43241 +                               return HANDLER_FINISHED;
43242 +                       }
43243 +
43244 +                       if (-1 == lseek(fd, offset, SEEK_SET)) {
43245 +                               con->http_status = 501; /* not implemented */
43246 +
43247 +                               close(fd);
43248 +
43249 +                               return HANDLER_FINISHED;
43250 +                       }
43251 +                       con->http_status = 200; /* modified */
43252 +               } else {
43253 +                       /* take what we have in the request-body and write it to a file */
43254 +
43255 +                       /* if the file doesn't exist, create it */
43256 +                       if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_TRUNC, 0600))) {
43257 +                               if (errno == ENOENT &&
43258 +                                   -1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0600))) {
43259 +                                       /* we can't open the file */
43260 +                                       con->http_status = 403;
43261  
43262 -                               if (r > 0) {
43263 -                                       c->offset += r;
43264 -                                       cq->bytes_out += r;
43265 +                                       return HANDLER_FINISHED;
43266                                 } else {
43267 -                                       break;
43268 +                                       con->http_status = 201; /* created */
43269 +                               }
43270 +                       } else {
43271 +                               con->http_status = 200; /* modified */
43272 +                       }
43273 +               }
43274 +
43275 +               con->file_finished = 1;
43276 +
43277 +               for (c = cq->first; c; c = cq->first) {
43278 +                       int r = 0;
43279 +
43280 +                       /* copy all chunks */
43281 +                       switch(c->type) {
43282 +                       case FILE_CHUNK:
43283 +
43284 +                               if (c->file.mmap.start == MAP_FAILED) {
43285 +                                       if (-1 == c->file.fd &&  /* open the file if not already open */
43286 +                                           -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
43287 +                                               log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
43288 +
43289 +                                               return -1;
43290 +                                       }
43291 +
43292 +                                       if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
43293 +                                               log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
43294 +                                                               strerror(errno), c->file.name,  c->file.fd);
43295 +
43296 +                                               return -1;
43297 +                                       }
43298 +
43299 +                                       c->file.mmap.length = c->file.length;
43300 +
43301 +                                       close(c->file.fd);
43302 +                                       c->file.fd = -1;
43303 +
43304 +                                       /* chunk_reset() or chunk_free() will cleanup for us */
43305 +                               }
43306 +
43307 +                               if ((r = write(fd, c->file.mmap.start + c->offset, c->file.length - c->offset)) < 0) {
43308 +                                       switch(errno) {
43309 +                                       case ENOSPC:
43310 +                                               con->http_status = 507;
43311 +
43312 +                                               break;
43313 +                                       default:
43314 +                                               con->http_status = 403;
43315 +                                               break;
43316 +                                       }
43317                                 }
43318 -                               chunkqueue_remove_finished_chunks(cq);
43319 +                               break;
43320 +                       case MEM_CHUNK:
43321 +                               if ((r = write(fd, c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) {
43322 +                                       switch(errno) {
43323 +                                       case ENOSPC:
43324 +                                               con->http_status = 507;
43325 +
43326 +                                               break;
43327 +                                       default:
43328 +                                               con->http_status = 403;
43329 +                                               break;
43330 +                                       }
43331 +                               }
43332 +                               break;
43333 +                       case UNUSED_CHUNK:
43334 +                               break;
43335                         }
43336 -                       close(fd);
43337  
43338 +                       if (r > 0) {
43339 +                               c->offset += r;
43340 +                               cq->bytes_out += r;
43341 +                       } else {
43342 +                               break;
43343 +                       }
43344 +                       chunkqueue_remove_finished_chunks(cq);
43345                 }
43346 +               close(fd);
43347 +
43348                 return HANDLER_FINISHED;
43349         }
43350 -       case HTTP_METHOD_MOVE: 
43351 +       case HTTP_METHOD_MOVE:
43352         case HTTP_METHOD_COPY: {
43353                 buffer *destination = NULL;
43354                 char *sep, *start;
43355 @@ -1475,7 +1770,15 @@
43356                         con->http_status = 403;
43357                         return HANDLER_FINISHED;
43358                 }
43359 -               
43360 +
43361 +               /* is a exclusive lock set on the source */
43362 +               if (con->request.http_method == HTTP_METHOD_MOVE) {
43363 +                       if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43364 +                               con->http_status = 423;
43365 +                               return HANDLER_FINISHED;
43366 +                       }
43367 +               }
43368 +
43369                 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Destination"))) {
43370                         destination = ds->value;
43371                 } else {
43372 @@ -1549,10 +1852,10 @@
43373                 }
43374  
43375                 buffer_copy_string_buffer(p->physical.path, p->physical.doc_root);
43376 -               BUFFER_APPEND_SLASH(p->physical.path);
43377 +               PATHNAME_APPEND_SLASH(p->physical.path);
43378                 buffer_copy_string_buffer(p->physical.basedir, p->physical.path);
43379  
43380 -               /* don't add a second / */ 
43381 +               /* don't add a second / */
43382                 if (p->physical.rel_path->ptr[0] == '/') {
43383                         buffer_append_string_len(p->physical.path, p->physical.rel_path->ptr + 1, p->physical.rel_path->used - 2);
43384                 } else {
43385 @@ -1613,6 +1916,12 @@
43386                         /* it is just a file, good */
43387                         int r;
43388  
43389 +                       /* does the client have a lock for this connection ? */
43390 +                       if (!webdav_has_lock(srv, con, p, p->uri.path)) {
43391 +                               con->http_status = 423;
43392 +                               return HANDLER_FINISHED;
43393 +                       }
43394 +
43395                         /* destination exists */
43396                         if (0 == (r = stat(p->physical.path->ptr, &st))) {
43397                                 if (S_ISDIR(st.st_mode)) {
43398 @@ -1636,7 +1945,7 @@
43399                                         return HANDLER_FINISHED;
43400                                 }
43401                         } else if (overwrite == 0) {
43402 -                               /* destination exists, but overwrite is not set */ 
43403 +                               /* destination exists, but overwrite is not set */
43404                                 con->http_status = 412;
43405                                 return HANDLER_FINISHED;
43406                         } else {
43407 @@ -1655,16 +1964,16 @@
43408                                                 sqlite3_reset(stmt);
43409  
43410                                                 /* bind the values to the insert */
43411 -                                               sqlite3_bind_text(stmt, 1, 
43412 -                                                                 p->uri.path->ptr, 
43413 +                                               sqlite3_bind_text(stmt, 1,
43414 +                                                                 p->uri.path->ptr,
43415                                                                   p->uri.path->used - 1,
43416                                                                   SQLITE_TRANSIENT);
43417  
43418 -                                               sqlite3_bind_text(stmt, 2, 
43419 -                                                                 con->uri.path->ptr, 
43420 +                                               sqlite3_bind_text(stmt, 2,
43421 +                                                                 con->uri.path->ptr,
43422                                                                   con->uri.path->used - 1,
43423                                                                   SQLITE_TRANSIENT);
43424 -                                               
43425 +
43426                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {
43427                                                         log_error_write(srv, __FILE__, __LINE__, "ss", "sql-move failed:", sqlite3_errmsg(p->conf.sql));
43428                                                 }
43429 @@ -1691,12 +2000,17 @@
43430  
43431                 return HANDLER_FINISHED;
43432         }
43433 -       case HTTP_METHOD_PROPPATCH: {
43434 +       case HTTP_METHOD_PROPPATCH:
43435                 if (p->conf.is_readonly) {
43436                         con->http_status = 403;
43437                         return HANDLER_FINISHED;
43438                 }
43439  
43440 +               if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43441 +                       con->http_status = 423;
43442 +                       return HANDLER_FINISHED;
43443 +               }
43444 +
43445                 /* check if destination exists */
43446                 if (-1 == stat(con->physical.path->ptr, &st)) {
43447                         switch(errno) {
43448 @@ -1737,7 +2051,7 @@
43449  
43450                                                         sqlite3_stmt *stmt;
43451  
43452 -                                                       stmt = (0 == xmlStrcmp(cmd->name, BAD_CAST "remove")) ? 
43453 +                                                       stmt = (0 == xmlStrcmp(cmd->name, BAD_CAST "remove")) ?
43454                                                                 p->conf.stmt_delete_prop : p->conf.stmt_update_prop;
43455  
43456                                                         for (props = cmd->children; props; props = props->next) {
43457 @@ -1762,34 +2076,35 @@
43458  
43459                                                                         /* bind the values to the insert */
43460  
43461 -                                                                       sqlite3_bind_text(stmt, 1, 
43462 -                                                                                         con->uri.path->ptr, 
43463 +                                                                       sqlite3_bind_text(stmt, 1,
43464 +                                                                                         con->uri.path->ptr,
43465                                                                                           con->uri.path->used - 1,
43466                                                                                           SQLITE_TRANSIENT);
43467 -                                                                       sqlite3_bind_text(stmt, 2, 
43468 +                                                                       sqlite3_bind_text(stmt, 2,
43469                                                                                           (char *)prop->name,
43470                                                                                           strlen((char *)prop->name),
43471                                                                                           SQLITE_TRANSIENT);
43472                                                                         if (prop->ns) {
43473 -                                                                               sqlite3_bind_text(stmt, 3, 
43474 +                                                                               sqlite3_bind_text(stmt, 3,
43475                                                                                                   (char *)prop->ns->href,
43476                                                                                                   strlen((char *)prop->ns->href),
43477                                                                                                   SQLITE_TRANSIENT);
43478                                                                         } else {
43479 -                                                                               sqlite3_bind_text(stmt, 3, 
43480 +                                                                               sqlite3_bind_text(stmt, 3,
43481                                                                                                   "",
43482                                                                                                   0,
43483                                                                                                   SQLITE_TRANSIENT);
43484                                                                         }
43485                                                                         if (stmt == p->conf.stmt_update_prop) {
43486 -                                                                               sqlite3_bind_text(stmt, 4, 
43487 +                                                                               sqlite3_bind_text(stmt, 4,
43488                                                                                           (char *)xmlNodeGetContent(prop),
43489                                                                                           strlen((char *)xmlNodeGetContent(prop)),
43490                                                                                           SQLITE_TRANSIENT);
43491                                                                         }
43492 -                                                               
43493 +
43494                                                                         if (SQLITE_DONE != (r = sqlite3_step(stmt))) {
43495 -                                                                               log_error_write(srv, __FILE__, __LINE__, "ss", "sql-set failed:", sqlite3_errmsg(p->conf.sql));
43496 +                                                                               log_error_write(srv, __FILE__, __LINE__, "ss",
43497 +                                                                                               "sql-set failed:", sqlite3_errmsg(p->conf.sql));
43498                                                                         }
43499                                                                 }
43500                                                         }
43501 @@ -1804,7 +2119,7 @@
43502  
43503                                                         goto propmatch_cleanup;
43504                                                 }
43505 -       
43506 +
43507                                                 con->http_status = 400;
43508                                         } else {
43509                                                 if (SQLITE_OK != sqlite3_exec(p->conf.sql, "COMMIT", NULL, NULL, &err)) {
43510 @@ -1821,6 +2136,7 @@
43511                                 }
43512  
43513  propmatch_cleanup:
43514 +
43515                                 xmlFreeDoc(xml);
43516                         } else {
43517                                 con->http_status = 400;
43518 @@ -1830,11 +2146,307 @@
43519  #endif
43520                 con->http_status = 501;
43521                 return HANDLER_FINISHED;
43522 -       }
43523 +       case HTTP_METHOD_LOCK:
43524 +               /**
43525 +                * a mac wants to write
43526 +                *
43527 +                * LOCK /dav/expire.txt HTTP/1.1\r\n
43528 +                * User-Agent: WebDAVFS/1.3 (01308000) Darwin/8.1.0 (Power Macintosh)\r\n
43529 +                * Accept: * / *\r\n
43530 +                * Depth: 0\r\n
43531 +                * Timeout: Second-600\r\n
43532 +                * Content-Type: text/xml; charset=\"utf-8\"\r\n
43533 +                * Content-Length: 229\r\n
43534 +                * Connection: keep-alive\r\n
43535 +                * Host: 192.168.178.23:1025\r\n
43536 +                * \r\n
43537 +                * <?xml version=\"1.0\" encoding=\"utf-8\"?>\n
43538 +                * <D:lockinfo xmlns:D=\"DAV:\">\n
43539 +                *  <D:lockscope><D:exclusive/></D:lockscope>\n
43540 +                *  <D:locktype><D:write/></D:locktype>\n
43541 +                *  <D:owner>\n
43542 +                *   <D:href>http://www.apple.com/webdav_fs/</D:href>\n
43543 +                *  </D:owner>\n
43544 +                * </D:lockinfo>\n
43545 +                */
43546 +
43547 +               if (depth != 0 && depth != -1) {
43548 +                       con->http_status = 400;
43549 +
43550 +                       return HANDLER_FINISHED;
43551 +               }
43552 +
43553 +#ifdef USE_LOCKS
43554 +               if (con->request.content_length) {
43555 +                       xmlDocPtr xml;
43556 +                       buffer *hdr_if = NULL;
43557 +
43558 +                       if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
43559 +                               hdr_if = ds->value;
43560 +                       }
43561 +
43562 +                       /* we don't support Depth: Infinity on locks */
43563 +                       if (hdr_if == NULL && depth == -1) {
43564 +                               con->http_status = 409; /* Conflict */
43565 +
43566 +                               return HANDLER_FINISHED;
43567 +                       }
43568 +
43569 +                       if (1 == webdav_parse_chunkqueue(srv, con, p, con->request_content_queue, &xml)) {
43570 +                               xmlNode *rootnode = xmlDocGetRootElement(xml);
43571 +
43572 +                               assert(rootnode);
43573 +
43574 +                               if (0 == xmlStrcmp(rootnode->name, BAD_CAST "lockinfo")) {
43575 +                                       xmlNode *lockinfo;
43576 +                                       const xmlChar *lockscope = NULL, *locktype = NULL, *owner = NULL;
43577 +
43578 +                                       for (lockinfo = rootnode->children; lockinfo; lockinfo = lockinfo->next) {
43579 +                                               if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "lockscope")) {
43580 +                                                       xmlNode *value;
43581 +                                                       for (value = lockinfo->children; value; value = value->next) {
43582 +                                                               if ((0 == xmlStrcmp(value->name, BAD_CAST "exclusive")) ||
43583 +                                                                   (0 == xmlStrcmp(value->name, BAD_CAST "shared"))) {
43584 +                                                                       lockscope = value->name;
43585 +                                                               } else {
43586 +                                                                       con->http_status = 400;
43587 +
43588 +                                                                       xmlFreeDoc(xml);
43589 +                                                                       return HANDLER_FINISHED;
43590 +                                                               }
43591 +                                                       }
43592 +                                               } else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "locktype")) {
43593 +                                                       xmlNode *value;
43594 +                                                       for (value = lockinfo->children; value; value = value->next) {
43595 +                                                               if ((0 == xmlStrcmp(value->name, BAD_CAST "write"))) {
43596 +                                                                       locktype = value->name;
43597 +                                                               } else {
43598 +                                                                       con->http_status = 400;
43599 +
43600 +                                                                       xmlFreeDoc(xml);
43601 +                                                                       return HANDLER_FINISHED;
43602 +                                                               }
43603 +                                                       }
43604 +
43605 +                                               } else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "owner")) {
43606 +                                               }
43607 +                                       }
43608 +
43609 +                                       if (lockscope && locktype) {
43610 +                                               sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
43611 +
43612 +                                               /* is this resourse already locked ? */
43613 +
43614 +                                               /* SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout
43615 +                                                *   FROM locks
43616 +                                                *  WHERE resource = ? */
43617 +
43618 +                                               if (stmt) {
43619 +
43620 +                                                       sqlite3_reset(stmt);
43621 +
43622 +                                                       sqlite3_bind_text(stmt, 1,
43623 +                                                                         p->uri.path->ptr,
43624 +                                                                         p->uri.path->used - 1,
43625 +                                                                         SQLITE_TRANSIENT);
43626 +
43627 +                                                       /* it is the PK */
43628 +                                                       while (SQLITE_ROW == sqlite3_step(stmt)) {
43629 +                                                               /* we found a lock
43630 +                                                                * 1. is it compatible ?
43631 +                                                                * 2. is it ours */
43632 +                                                               char *sql_lockscope = (char *)sqlite3_column_text(stmt, 2);
43633 +
43634 +                                                               if (strcmp(sql_lockscope, "exclusive")) {
43635 +                                                                       con->http_status = 423;
43636 +                                                               } else if (0 == xmlStrcmp(lockscope, BAD_CAST "exclusive")) {
43637 +                                                                       /* resourse is locked with a shared lock
43638 +                                                                        * client wants exclusive */
43639 +                                                                       con->http_status = 423;
43640 +                                                               }
43641 +                                                       }
43642 +                                                       if (con->http_status == 423) {
43643 +                                                               xmlFreeDoc(xml);
43644 +                                                               return HANDLER_FINISHED;
43645 +                                                       }
43646 +                                               }
43647 +
43648 +                                               stmt = p->conf.stmt_create_lock;
43649 +                                               if (stmt) {
43650 +                                                       /* create a lock-token */
43651 +                                                       uuid_t id;
43652 +                                                       char uuid[37] /* 36 + \0 */;
43653 +
43654 +                                                       uuid_generate(id);
43655 +                                                       uuid_unparse(id, uuid);
43656 +
43657 +                                                       buffer_copy_string(p->tmp_buf, "opaquelocktoken:");
43658 +                                                       buffer_append_string(p->tmp_buf, uuid);
43659 +
43660 +                                                       /* "CREATE TABLE locks ("
43661 +                                                        * "  locktoken TEXT NOT NULL,"
43662 +                                                        * "  resource TEXT NOT NULL,"
43663 +                                                        * "  lockscope TEXT NOT NULL,"
43664 +                                                        * "  locktype TEXT NOT NULL,"
43665 +                                                        * "  owner TEXT NOT NULL,"
43666 +                                                        * "  depth INT NOT NULL,"
43667 +                                                        */
43668 +
43669 +                                                       sqlite3_reset(stmt);
43670 +
43671 +                                                       sqlite3_bind_text(stmt, 1,
43672 +                                                                         CONST_BUF_LEN(p->tmp_buf),
43673 +                                                                         SQLITE_TRANSIENT);
43674 +
43675 +                                                       sqlite3_bind_text(stmt, 2,
43676 +                                                                         CONST_BUF_LEN(con->uri.path),
43677 +                                                                         SQLITE_TRANSIENT);
43678 +
43679 +                                                       sqlite3_bind_text(stmt, 3,
43680 +                                                                         lockscope,
43681 +                                                                         xmlStrlen(lockscope),
43682 +                                                                         SQLITE_TRANSIENT);
43683 +
43684 +                                                       sqlite3_bind_text(stmt, 4,
43685 +                                                                         locktype,
43686 +                                                                         xmlStrlen(locktype),
43687 +                                                                         SQLITE_TRANSIENT);
43688 +
43689 +                                                       /* owner */
43690 +                                                       sqlite3_bind_text(stmt, 5,
43691 +                                                                         "",
43692 +                                                                         0,
43693 +                                                                         SQLITE_TRANSIENT);
43694 +
43695 +                                                       /* depth */
43696 +                                                       sqlite3_bind_int(stmt, 6,
43697 +                                                                        depth);
43698 +
43699 +
43700 +                                                       if (SQLITE_DONE != sqlite3_step(stmt)) {
43701 +                                                               log_error_write(srv, __FILE__, __LINE__, "ss",
43702 +                                                                               "create lock:", sqlite3_errmsg(p->conf.sql));
43703 +                                                       }
43704 +
43705 +                                                       /* looks like we survived */
43706 +                                                       webdav_lockdiscovery(srv, con, p->tmp_buf, lockscope, locktype, depth);
43707 +
43708 +                                                       con->http_status = 201;
43709 +                                                       con->file_finished = 1;
43710 +                                               }
43711 +                                       }
43712 +                               }
43713 +
43714 +                               xmlFreeDoc(xml);
43715 +                               return HANDLER_FINISHED;
43716 +                       } else {
43717 +                               con->http_status = 400;
43718 +                               return HANDLER_FINISHED;
43719 +                       }
43720 +               } else {
43721 +
43722 +                       if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
43723 +                               buffer *locktoken = ds->value;
43724 +                               sqlite3_stmt *stmt = p->conf.stmt_refresh_lock;
43725 +
43726 +                               /* remove the < > around the token */
43727 +                               if (locktoken->used < 6) {
43728 +                                       con->http_status = 400;
43729 +
43730 +                                       return HANDLER_FINISHED;
43731 +                               }
43732 +
43733 +                               buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 2, locktoken->used - 5);
43734 +
43735 +                               sqlite3_reset(stmt);
43736 +
43737 +                               sqlite3_bind_text(stmt, 1,
43738 +                                         CONST_BUF_LEN(p->tmp_buf),
43739 +                                         SQLITE_TRANSIENT);
43740 +
43741 +                               if (SQLITE_DONE != sqlite3_step(stmt)) {
43742 +                                       log_error_write(srv, __FILE__, __LINE__, "ss",
43743 +                                               "refresh lock:", sqlite3_errmsg(p->conf.sql));
43744 +                               }
43745 +
43746 +                               webdav_lockdiscovery(srv, con, p->tmp_buf, "exclusive", "write", 0);
43747 +
43748 +                               con->http_status = 200;
43749 +                               con->file_finished = 1;
43750 +                               return HANDLER_FINISHED;
43751 +                       } else {
43752 +                               /* we need a lock-token to refresh */
43753 +                               con->http_status = 400;
43754 +
43755 +                               return HANDLER_FINISHED;
43756 +                       }
43757 +               }
43758 +               break;
43759 +#else
43760 +               con->http_status = 501;
43761 +               return HANDLER_FINISHED;
43762 +#endif
43763 +       case HTTP_METHOD_UNLOCK:
43764 +#ifdef USE_LOCKS
43765 +               if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Lock-Token"))) {
43766 +                       buffer *locktoken = ds->value;
43767 +                       sqlite3_stmt *stmt = p->conf.stmt_remove_lock;
43768 +
43769 +                       /* remove the < > around the token */
43770 +                       if (locktoken->used < 4) {
43771 +                               con->http_status = 400;
43772 +
43773 +                               return HANDLER_FINISHED;
43774 +                       }
43775 +
43776 +                       /**
43777 +                        * FIXME:
43778 +                        *
43779 +                        * if the resourse is locked:
43780 +                        * - by us: unlock
43781 +                        * - by someone else: 401
43782 +                        * if the resource is not locked:
43783 +                        * - 412
43784 +                        *  */
43785 +
43786 +                       buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 1, locktoken->used - 3);
43787 +
43788 +                       sqlite3_reset(stmt);
43789 +
43790 +                       sqlite3_bind_text(stmt, 1,
43791 +                                 CONST_BUF_LEN(p->tmp_buf),
43792 +                                 SQLITE_TRANSIENT);
43793 +
43794 +                       sqlite3_bind_text(stmt, 2,
43795 +                                 CONST_BUF_LEN(con->uri.path),
43796 +                                 SQLITE_TRANSIENT);
43797 +
43798 +                       if (SQLITE_DONE != sqlite3_step(stmt)) {
43799 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
43800 +                                       "remove lock:", sqlite3_errmsg(p->conf.sql));
43801 +                       }
43802 +
43803 +                       if (0 == sqlite3_changes(p->conf.sql)) {
43804 +                               con->http_status = 401;
43805 +                       } else {
43806 +                               con->http_status = 204;
43807 +                       }
43808 +                       return HANDLER_FINISHED;
43809 +               } else {
43810 +                       /* we need a lock-token to unlock */
43811 +                       con->http_status = 400;
43812 +
43813 +                       return HANDLER_FINISHED;
43814 +               }
43815 +               break;
43816 +#else
43817 +               con->http_status = 501;
43818 +               return HANDLER_FINISHED;
43819 +#endif
43820         default:
43821                 break;
43822         }
43823 -       
43824 +
43825         /* not found */
43826         return HANDLER_GO_ON;
43827  }
43828 @@ -1845,14 +2457,14 @@
43829  int mod_webdav_plugin_init(plugin *p) {
43830         p->version     = LIGHTTPD_VERSION_ID;
43831         p->name        = buffer_init_string("webdav");
43832 -       
43833 +
43834         p->init        = mod_webdav_init;
43835         p->handle_uri_clean  = mod_webdav_uri_handler;
43836         p->handle_physical   = mod_webdav_subrequest_handler;
43837         p->set_defaults  = mod_webdav_set_defaults;
43838         p->cleanup     = mod_webdav_free;
43839 -       
43840 +
43841         p->data        = NULL;
43842 -       
43843 +
43844         return 0;
43845  }
43846 --- ../lighttpd-1.4.11/src/network.c    2006-03-04 16:45:46.000000000 +0200
43847 +++ lighttpd-1.4.12/src/network.c       2006-07-18 13:03:40.000000000 +0300
43848 @@ -1,14 +1,14 @@
43849  #include <sys/types.h>
43850  #include <sys/stat.h>
43851 -#include <sys/time.h>
43852  
43853  #include <errno.h>
43854  #include <fcntl.h>
43855 -#include <unistd.h>
43856  #include <string.h>
43857  #include <stdlib.h>
43858  #include <assert.h>
43859  
43860 +#include <stdio.h>
43861 +
43862  #include "network.h"
43863  #include "fdevent.h"
43864  #include "log.h"
43865 @@ -19,11 +19,12 @@
43866  #include "network_backends.h"
43867  #include "sys-mmap.h"
43868  #include "sys-socket.h"
43869 +#include "sys-files.h"
43870  
43871  #ifdef USE_OPENSSL
43872 -# include <openssl/ssl.h> 
43873 -# include <openssl/err.h> 
43874 -# include <openssl/rand.h> 
43875 +# include <openssl/ssl.h>
43876 +# include <openssl/err.h>
43877 +# include <openssl/rand.h>
43878  #endif
43879  
43880  handler_t network_server_handle_fdevent(void *s, void *context, int revents) {
43881 @@ -31,25 +32,25 @@
43882         server_socket *srv_socket = (server_socket *)context;
43883         connection *con;
43884         int loops = 0;
43885 -       
43886 +
43887         UNUSED(context);
43888 -       
43889 +
43890         if (revents != FDEVENT_IN) {
43891 -               log_error_write(srv, __FILE__, __LINE__, "sdd", 
43892 +               log_error_write(srv, __FILE__, __LINE__, "sdd",
43893                                 "strange event for server socket",
43894 -                               srv_socket->fd,
43895 +                               srv_socket->sock->fd,
43896                                 revents);
43897                 return HANDLER_ERROR;
43898         }
43899  
43900         /* accept()s at most 100 connections directly
43901          *
43902 -        * we jump out after 100 to give the waiting connections a chance */    
43903 +        * we jump out after 100 to give the waiting connections a chance */
43904         for (loops = 0; loops < 100 && NULL != (con = connection_accept(srv, srv_socket)); loops++) {
43905                 handler_t r;
43906 -               
43907 +
43908                 connection_state_machine(srv, con);
43909 -               
43910 +
43911                 switch(r = plugins_call_handle_joblist(srv, con)) {
43912                 case HANDLER_FINISHED:
43913                 case HANDLER_GO_ON:
43914 @@ -72,18 +73,18 @@
43915         buffer *b;
43916         int is_unix_domain_socket = 0;
43917         int fd;
43918 -       
43919 +
43920  #ifdef SO_ACCEPTFILTER
43921         struct accept_filter_arg afa;
43922  #endif
43923  
43924 -#ifdef __WIN32
43925 +#ifdef _WIN32
43926         WORD wVersionRequested;
43927         WSADATA wsaData;
43928         int err;
43929 -        
43930 +
43931         wVersionRequested = MAKEWORD( 2, 2 );
43932 -        
43933 +
43934         err = WSAStartup( wVersionRequested, &wsaData );
43935         if ( err != 0 ) {
43936                     /* Tell the user that we could not find a usable */
43937 @@ -91,37 +92,37 @@
43938                     return -1;
43939         }
43940  #endif
43941 -       
43942 +
43943         srv_socket = calloc(1, sizeof(*srv_socket));
43944 -       srv_socket->fd = -1;
43945 -       
43946 +       srv_socket->sock = iosocket_init();
43947 +
43948         srv_socket->srv_token = buffer_init();
43949         buffer_copy_string_buffer(srv_socket->srv_token, host_token);
43950 -       
43951 +
43952         b = buffer_init();
43953         buffer_copy_string_buffer(b, host_token);
43954 -       
43955 -       /* ipv4:port 
43956 +
43957 +       /* ipv4:port
43958          * [ipv6]:port
43959          */
43960         if (NULL == (sp = strrchr(b->ptr, ':'))) {
43961                 log_error_write(srv, __FILE__, __LINE__, "sb", "value of $SERVER[\"socket\"] has to be \"ip:port\".", b);
43962 -               
43963 +
43964                 return -1;
43965         }
43966 -       
43967 +
43968         host = b->ptr;
43969 -       
43970 +
43971         /* check for [ and ] */
43972         if (b->ptr[0] == '[' && *(sp-1) == ']') {
43973                 *(sp-1) = '\0';
43974                 host++;
43975 -               
43976 +
43977                 s->use_ipv6 = 1;
43978         }
43979 -       
43980 +
43981         *(sp++) = '\0';
43982 -       
43983 +
43984         port = strtol(sp, NULL, 10);
43985  
43986         if (host[0] == '/') {
43987 @@ -129,18 +130,18 @@
43988                 is_unix_domain_socket = 1;
43989         } else if (port == 0 || port > 65535) {
43990                 log_error_write(srv, __FILE__, __LINE__, "sd", "port out of range:", port);
43991 -       
43992 +
43993                 return -1;
43994         }
43995 -       
43996 +
43997         if (*host == '\0') host = NULL;
43998  
43999         if (is_unix_domain_socket) {
44000  #ifdef HAVE_SYS_UN_H
44001  
44002                 srv_socket->addr.plain.sa_family = AF_UNIX;
44003 -               
44004 -               if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
44005 +
44006 +               if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
44007                         log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
44008                         return -1;
44009                 }
44010 @@ -154,32 +155,32 @@
44011  #ifdef HAVE_IPV6
44012         if (s->use_ipv6) {
44013                 srv_socket->addr.plain.sa_family = AF_INET6;
44014 -               
44015 -               if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44016 +
44017 +               if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44018                         log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
44019                         return -1;
44020                 }
44021                 srv_socket->use_ipv6 = 1;
44022         }
44023  #endif
44024 -                               
44025 -       if (srv_socket->fd == -1) {
44026 +
44027 +       if (srv_socket->sock->fd == -1) {
44028                 srv_socket->addr.plain.sa_family = AF_INET;
44029 -               if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44030 +               if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44031                         log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
44032                         return -1;
44033                 }
44034         }
44035 -       
44036 +
44037         /* */
44038 -       srv->cur_fds = srv_socket->fd;
44039 -       
44040 +       srv->cur_fds = srv_socket->sock->fd;
44041 +
44042         val = 1;
44043 -       if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
44044 +       if (setsockopt(srv_socket->sock->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
44045                 log_error_write(srv, __FILE__, __LINE__, "ss", "socketsockopt failed:", strerror(errno));
44046                 return -1;
44047         }
44048 -       
44049 +
44050         switch(srv_socket->addr.plain.sa_family) {
44051  #ifdef HAVE_IPV6
44052         case AF_INET6:
44053 @@ -190,23 +191,23 @@
44054                 } else {
44055                         struct addrinfo hints, *res;
44056                         int r;
44057 -                       
44058 +
44059                         memset(&hints, 0, sizeof(hints));
44060 -                       
44061 +
44062                         hints.ai_family   = AF_INET6;
44063                         hints.ai_socktype = SOCK_STREAM;
44064                         hints.ai_protocol = IPPROTO_TCP;
44065 -                       
44066 +
44067                         if (0 != (r = getaddrinfo(host, NULL, &hints, &res))) {
44068 -                               log_error_write(srv, __FILE__, __LINE__, 
44069 -                                               "sssss", "getaddrinfo failed: ", 
44070 +                               log_error_write(srv, __FILE__, __LINE__,
44071 +                                               "sssss", "getaddrinfo failed: ",
44072                                                 gai_strerror(r), "'", host, "'");
44073 -                               
44074 +
44075                                 return -1;
44076                         }
44077 -                       
44078 +
44079                         memcpy(&(srv_socket->addr), res->ai_addr, res->ai_addrlen);
44080 -                       
44081 +
44082                         freeaddrinfo(res);
44083                 }
44084                 srv_socket->addr.ipv6.sin6_port = htons(port);
44085 @@ -221,33 +222,34 @@
44086                 } else {
44087                         struct hostent *he;
44088                         if (NULL == (he = gethostbyname(host))) {
44089 -                               log_error_write(srv, __FILE__, __LINE__, 
44090 -                                               "sds", "gethostbyname failed: ", 
44091 +                               log_error_write(srv, __FILE__, __LINE__,
44092 +                                               "sds", "gethostbyname failed: ",
44093                                                 h_errno, host);
44094                                 return -1;
44095                         }
44096 -                       
44097 +
44098                         if (he->h_addrtype != AF_INET) {
44099                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
44100                                 return -1;
44101                         }
44102 -                       
44103 +
44104                         if (he->h_length != sizeof(struct in_addr)) {
44105                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
44106                                 return -1;
44107                         }
44108 -                       
44109 +
44110                         memcpy(&(srv_socket->addr.ipv4.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
44111                 }
44112                 srv_socket->addr.ipv4.sin_port = htons(port);
44113 -               
44114 +
44115                 addr_len = sizeof(struct sockaddr_in);
44116 -               
44117 +
44118                 break;
44119 +#ifndef _WIN32
44120         case AF_UNIX:
44121                 srv_socket->addr.un.sun_family = AF_UNIX;
44122                 strcpy(srv_socket->addr.un.sun_path, host);
44123 -               
44124 +
44125  #ifdef SUN_LEN
44126                 addr_len = SUN_LEN(&srv_socket->addr.un);
44127  #else
44128 @@ -256,11 +258,11 @@
44129  #endif
44130  
44131                 /* check if the socket exists and try to connect to it. */
44132 -               if (-1 != (fd = connect(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {
44133 +               if (-1 != (fd = connect(srv_socket->sock->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {
44134                         close(fd);
44135  
44136 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
44137 -                               "server socket is still in use:", 
44138 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
44139 +                               "server socket is still in use:",
44140                                 host);
44141  
44142  
44143 @@ -275,88 +277,89 @@
44144                 case ENOENT:
44145                         break;
44146                 default:
44147 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
44148 -                               "testing socket failed:", 
44149 +                       log_error_write(srv, __FILE__, __LINE__, "sds",
44150 +                               "testing socket failed:",
44151                                 host, strerror(errno));
44152  
44153                         return -1;
44154                 }
44155  
44156                 break;
44157 +#endif
44158         default:
44159                 addr_len = 0;
44160 -               
44161 +
44162                 return -1;
44163         }
44164 -       
44165 -       if (0 != bind(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
44166 +
44167 +       if (0 != bind(srv_socket->sock->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
44168                 switch(srv_socket->addr.plain.sa_family) {
44169                 case AF_UNIX:
44170 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
44171 -                                       "can't bind to socket:", 
44172 +                       log_error_write(srv, __FILE__, __LINE__, "sds",
44173 +                                       "can't bind to socket:",
44174                                         host, strerror(errno));
44175                         break;
44176                 default:
44177 -                       log_error_write(srv, __FILE__, __LINE__, "ssds", 
44178 -                                       "can't bind to port:", 
44179 +                       log_error_write(srv, __FILE__, __LINE__, "ssds",
44180 +                                       "can't bind to port:",
44181                                         host, port, strerror(errno));
44182                         break;
44183                 }
44184                 return -1;
44185         }
44186 -       
44187 -       if (-1 == listen(srv_socket->fd, 128 * 8)) {
44188 +
44189 +       if (-1 == listen(srv_socket->sock->fd, 128 * 8)) {
44190                 log_error_write(srv, __FILE__, __LINE__, "ss", "listen failed: ", strerror(errno));
44191                 return -1;
44192         }
44193 -       
44194 +
44195         if (s->is_ssl) {
44196  #ifdef USE_OPENSSL
44197                 if (srv->ssl_is_init == 0) {
44198                         SSL_load_error_strings();
44199                         SSL_library_init();
44200                         srv->ssl_is_init = 1;
44201 -                       
44202 +
44203                         if (0 == RAND_status()) {
44204 -                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
44205 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44206                                                 "not enough entropy in the pool");
44207                                 return -1;
44208                         }
44209                 }
44210 -               
44211 +
44212                 if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {
44213 -                       log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
44214 +                       log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44215                                         ERR_error_string(ERR_get_error(), NULL));
44216                         return -1;
44217                 }
44218 -               
44219 +
44220                 if (buffer_is_empty(s->ssl_pemfile)) {
44221                         log_error_write(srv, __FILE__, __LINE__, "s", "ssl.pemfile has to be set");
44222                         return -1;
44223                 }
44224 -               
44225 +
44226                 if (!buffer_is_empty(s->ssl_ca_file)) {
44227                         if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s->ssl_ca_file->ptr, NULL)) {
44228 -                               log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", 
44229 +                               log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44230                                                 ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);
44231                                 return -1;
44232                         }
44233                 }
44234 -               
44235 +
44236                 if (SSL_CTX_use_certificate_file(s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
44237 -                       log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", 
44238 +                       log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44239                                         ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
44240                         return -1;
44241                 }
44242 -               
44243 +
44244                 if (SSL_CTX_use_PrivateKey_file (s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
44245 -                       log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", 
44246 +                       log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44247                                         ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
44248                         return -1;
44249                 }
44250 -               
44251 +
44252                 if (SSL_CTX_check_private_key(s->ssl_ctx) != 1) {
44253 -                       log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:", 
44254 +                       log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:",
44255                                         "Private key does not match the certificate public key, reason:",
44256                                         ERR_error_string(ERR_get_error(), NULL),
44257                                         s->ssl_pemfile);
44258 @@ -364,15 +367,15 @@
44259                 }
44260                 srv_socket->ssl_ctx = s->ssl_ctx;
44261  #else
44262 -               
44263 +
44264                 buffer_free(srv_socket->srv_token);
44265                 free(srv_socket);
44266 -               
44267 +
44268                 buffer_free(b);
44269 -               
44270 -               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
44271 +
44272 +               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44273                                 "ssl requested but openssl support is not compiled in");
44274 -               
44275 +
44276                 return -1;
44277  #endif
44278         } else {
44279 @@ -383,17 +386,16 @@
44280                  */
44281                 memset(&afa, 0, sizeof(afa));
44282                 strcpy(afa.af_name, "httpready");
44283 -               if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
44284 +               if (setsockopt(srv_socket->sock->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
44285                         if (errno != ENOENT) {
44286                                 log_error_write(srv, __FILE__, __LINE__, "ss", "can't set accept-filter 'httpready': ", strerror(errno));
44287                         }
44288                 }
44289  #endif
44290         }
44291 -       
44292 +
44293         srv_socket->is_ssl = s->is_ssl;
44294 -       srv_socket->fde_ndx = -1;
44295 -       
44296 +
44297         if (srv->srv_sockets.size == 0) {
44298                 srv->srv_sockets.size = 4;
44299                 srv->srv_sockets.used = 0;
44300 @@ -402,11 +404,10 @@
44301                 srv->srv_sockets.size += 4;
44302                 srv->srv_sockets.ptr = realloc(srv->srv_sockets.ptr, srv->srv_sockets.size * sizeof(server_socket));
44303         }
44304 -       
44305 +
44306         srv->srv_sockets.ptr[srv->srv_sockets.used++] = srv_socket;
44307 -       
44308         buffer_free(b);
44309 -       
44310 +
44311         return 0;
44312  }
44313  
44314 @@ -414,45 +415,60 @@
44315         size_t i;
44316         for (i = 0; i < srv->srv_sockets.used; i++) {
44317                 server_socket *srv_socket = srv->srv_sockets.ptr[i];
44318 -               
44319 -               if (srv_socket->fd != -1) {
44320 +
44321 +               if (srv_socket->sock->fd != -1) {
44322                         /* check if server fd are already registered */
44323 -                       if (srv_socket->fde_ndx != -1) {
44324 -                               fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
44325 -                               fdevent_unregister(srv->ev, srv_socket->fd);
44326 +                       if (srv_socket->sock->fde_ndx != -1) {
44327 +                               fdevent_event_del(srv->ev, srv_socket->sock);
44328 +                               fdevent_unregister(srv->ev, srv_socket->sock);
44329                         }
44330 -               
44331 -                       close(srv_socket->fd);
44332 +
44333 +                       closesocket(srv_socket->sock->fd);
44334 +               }
44335 +
44336 +               if (srv_socket->is_ssl) {
44337 +#ifdef USE_OPENSSL
44338 +                       SSL_CTX_free(srv_socket->ssl_ctx);
44339 +#endif
44340                 }
44341 -               
44342 +
44343 +               iosocket_free(srv_socket->sock);
44344 +
44345                 buffer_free(srv_socket->srv_token);
44346 -               
44347 +
44348                 free(srv_socket);
44349         }
44350 -       
44351 +
44352 +#ifdef USE_OPENSSL
44353 +       ERR_free_strings();
44354 +#endif
44355         free(srv->srv_sockets.ptr);
44356 -       
44357 +
44358         return 0;
44359  }
44360  
44361  typedef enum {
44362         NETWORK_BACKEND_UNSET,
44363 +
44364         NETWORK_BACKEND_WRITE,
44365         NETWORK_BACKEND_WRITEV,
44366         NETWORK_BACKEND_LINUX_SENDFILE,
44367         NETWORK_BACKEND_FREEBSD_SENDFILE,
44368 -       NETWORK_BACKEND_SOLARIS_SENDFILEV
44369 +       NETWORK_BACKEND_SOLARIS_SENDFILEV,
44370 +
44371 +    NETWORK_BACKEND_WIN32_SEND,
44372 +    NETWORK_BACKEND_WIN32_TRANSMITFILE,
44373  } network_backend_t;
44374  
44375  int network_init(server *srv) {
44376         buffer *b;
44377         size_t i;
44378         network_backend_t backend;
44379 -       
44380 -       struct nb_map { 
44381 -               network_backend_t nb; 
44382 -               const char *name; 
44383 -       } network_backends[] = { 
44384 +
44385 +       struct nb_map {
44386 +               network_backend_t nb;
44387 +               const char *name;
44388 +       } network_backends[] = {
44389                 /* lowest id wins */
44390  #if defined USE_LINUX_SENDFILE
44391                 { NETWORK_BACKEND_LINUX_SENDFILE,       "linux-sendfile" },
44392 @@ -466,21 +482,30 @@
44393  #if defined USE_WRITEV
44394                 { NETWORK_BACKEND_WRITEV,               "writev" },
44395  #endif
44396 +#if defined USE_WRITE
44397                 { NETWORK_BACKEND_WRITE,                "write" },
44398 +#endif
44399 +#if defined USE_WIN32_TRANSMITFILE
44400 +               { NETWORK_BACKEND_WIN32_TRANSMITFILE,   "win32-transmitfile" },
44401 +#endif
44402 +#if defined USE_WIN32_SEND
44403 +               { NETWORK_BACKEND_WIN32_SEND,           "win32-send" },
44404 +#endif
44405 +
44406                 { NETWORK_BACKEND_UNSET,                NULL }
44407         };
44408 -       
44409 +
44410         b = buffer_init();
44411 -               
44412 +
44413         buffer_copy_string_buffer(b, srv->srvconf.bindhost);
44414         buffer_append_string(b, ":");
44415         buffer_append_long(b, srv->srvconf.port);
44416 -       
44417 +
44418         if (0 != network_server_init(srv, b, srv->config_storage[0])) {
44419                 return -1;
44420         }
44421         buffer_free(b);
44422 -               
44423 +
44424  #ifdef USE_OPENSSL
44425         srv->network_ssl_backend_write = network_write_chunkqueue_openssl;
44426  #endif
44427 @@ -500,54 +525,80 @@
44428                 if (NULL == network_backends[i].name) {
44429                         /* we don't know it */
44430  
44431 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
44432 -                                       "server.network-backend has a unknown value:", 
44433 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
44434 +                                       "server.network-backend has a unknown value:",
44435                                         srv->srvconf.network_backend);
44436  
44437                         return -1;
44438                 }
44439         }
44440  
44441 +#define SET_NETWORK_BACKEND(read, write) \
44442 +    srv->network_backend_write = network_write_chunkqueue_##write;\
44443 +    srv->network_backend_read = network_read_chunkqueue_##read
44444 +
44445 +#define SET_NETWORK_BACKEND_SSL(read, write) \
44446 +    srv->network_ssl_backend_write = network_write_chunkqueue_##write;\
44447 +    srv->network_ssl_backend_read = network_read_chunkqueue_##read
44448 +
44449         switch(backend) {
44450 +
44451 +#ifdef USE_WIN32_SEND
44452 +       case NETWORK_BACKEND_WIN32_SEND:
44453 +        SET_NETWORK_BACKEND(win32recv, win32send);
44454 +               break;
44455 +#ifdef USE_WIN32_TRANSMITFILE
44456 +       case NETWORK_BACKEND_WIN32_TRANSMITFILE:
44457 +        SET_NETWORK_BACKEND(win32recv, win32transmitfile);
44458 +               break;
44459 +#endif
44460 +#endif
44461 +
44462 +#ifdef USE_WRITE
44463         case NETWORK_BACKEND_WRITE:
44464 -               srv->network_backend_write = network_write_chunkqueue_write;
44465 +        SET_NETWORK_BACKEND(read, write);
44466                 break;
44467 +
44468  #ifdef USE_WRITEV
44469         case NETWORK_BACKEND_WRITEV:
44470 -               srv->network_backend_write = network_write_chunkqueue_writev;
44471 +        SET_NETWORK_BACKEND(read, writev);
44472                 break;
44473  #endif
44474  #ifdef USE_LINUX_SENDFILE
44475         case NETWORK_BACKEND_LINUX_SENDFILE:
44476 -               srv->network_backend_write = network_write_chunkqueue_linuxsendfile; 
44477 +        SET_NETWORK_BACKEND(read, linuxsendfile);
44478                 break;
44479  #endif
44480  #ifdef USE_FREEBSD_SENDFILE
44481         case NETWORK_BACKEND_FREEBSD_SENDFILE:
44482 -               srv->network_backend_write = network_write_chunkqueue_freebsdsendfile; 
44483 +        SET_NETWORK_BACKEND(read, freebsdsendfile);
44484                 break;
44485  #endif
44486  #ifdef USE_SOLARIS_SENDFILEV
44487         case NETWORK_BACKEND_SOLARIS_SENDFILEV:
44488 -               srv->network_backend_write = network_write_chunkqueue_solarissendfilev; 
44489 +        SET_NETWORK_BACKEND(read, solarissendfilev);
44490                 break;
44491  #endif
44492 +#endif
44493         default:
44494                 return -1;
44495         }
44496 +#ifdef USE_OPENSSL
44497 +        SET_NETWORK_BACKEND_SSL(openssl, openssl);
44498 +#endif
44499  
44500         /* check for $SERVER["socket"] */
44501         for (i = 1; i < srv->config_context->used; i++) {
44502                 data_config *dc = (data_config *)srv->config_context->data[i];
44503                 specific_config *s = srv->config_storage[i];
44504                 size_t j;
44505 -               
44506 +
44507                 /* not our stage */
44508                 if (COMP_SERVER_SOCKET != dc->comp) continue;
44509 -               
44510 +
44511                 if (dc->cond != CONFIG_COND_EQ) {
44512                         log_error_write(srv, __FILE__, __LINE__, "s", "only == is allowed for $SERVER[\"socket\"].");
44513 -                       
44514 +
44515                         return -1;
44516                 }
44517  
44518 @@ -558,36 +609,47 @@
44519                                 break;
44520                         }
44521                 }
44522 -               
44523 +
44524                 if (j == srv->srv_sockets.used) {
44525                         if (0 != network_server_init(srv, dc->string, s)) return -1;
44526                 }
44527         }
44528 -       
44529 +
44530         return 0;
44531  }
44532  
44533  int network_register_fdevents(server *srv) {
44534         size_t i;
44535 -       
44536         if (-1 == fdevent_reset(srv->ev)) {
44537                 return -1;
44538         }
44539 -       
44540         /* register fdevents after reset */
44541         for (i = 0; i < srv->srv_sockets.used; i++) {
44542                 server_socket *srv_socket = srv->srv_sockets.ptr[i];
44543 -               
44544 -               fdevent_register(srv->ev, srv_socket->fd, network_server_handle_fdevent, srv_socket);
44545 -               fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
44546 +               fdevent_register(srv->ev, srv_socket->sock, network_server_handle_fdevent, srv_socket);
44547 +               fdevent_event_add(srv->ev, srv_socket->sock, FDEVENT_IN);
44548         }
44549         return 0;
44550  }
44551  
44552 -int network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
44553 -       int ret = -1;
44554 +network_status_t network_read_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
44555 +       server_socket *srv_socket = con->srv_socket;
44556 +
44557 +       if (srv_socket->is_ssl) {
44558 +#ifdef USE_OPENSSL
44559 +               return srv->network_ssl_backend_read(srv, con, con->sock, cq);
44560 +#else
44561 +               return NETWORK_STATUS_FATAL_ERROR;
44562 +#endif
44563 +       } else {
44564 +               return srv->network_backend_read(srv, con, con->sock, cq);
44565 +       }
44566 +}
44567 +
44568 +network_status_t network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
44569 +       network_status_t ret = NETWORK_STATUS_UNSET;
44570         off_t written = 0;
44571 -#ifdef TCP_CORK        
44572 +#ifdef TCP_CORK
44573         int corked = 0;
44574  #endif
44575         server_socket *srv_socket = con->srv_socket;
44576 @@ -600,37 +662,42 @@
44577                 joblist_append(srv, con);
44578  
44579                 return 1;
44580 -       }  
44581 +       }
44582  
44583         written = cq->bytes_out;
44584  
44585 -#ifdef TCP_CORK        
44586 +#ifdef TCP_CORK
44587         /* Linux: put a cork into the socket as we want to combine the write() calls
44588          * but only if we really have multiple chunks
44589          */
44590         if (cq->first && cq->first->next) {
44591                 corked = 1;
44592 -               setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
44593 +               setsockopt(con->sock->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
44594         }
44595  #endif
44596 -       
44597 +
44598         if (srv_socket->is_ssl) {
44599  #ifdef USE_OPENSSL
44600 -               ret = srv->network_ssl_backend_write(srv, con, con->ssl, cq);
44601 +               ret = srv->network_ssl_backend_write(srv, con, con->sock, cq);
44602  #endif
44603         } else {
44604 -               ret = srv->network_backend_write(srv, con, con->fd, cq);
44605 +               ret = srv->network_backend_write(srv, con, con->sock, cq);
44606         }
44607 -       
44608 -       if (ret >= 0) {
44609 +
44610 +    switch (ret) {
44611 +    case NETWORK_STATUS_WAIT_FOR_EVENT:
44612 +    case NETWORK_STATUS_SUCCESS:
44613                 chunkqueue_remove_finished_chunks(cq);
44614 -               ret = chunkqueue_is_empty(cq) ? 0 : 1;
44615 +
44616 +        break;
44617 +    default:
44618 +        break;
44619         }
44620 -       
44621 +
44622  #ifdef TCP_CORK
44623         if (corked) {
44624                 corked = 0;
44625 -               setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
44626 +               setsockopt(con->sock->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
44627         }
44628  #endif
44629  
44630 @@ -639,13 +706,13 @@
44631         con->bytes_written_cur_second += written;
44632  
44633         *(con->conf.global_bytes_per_second_cnt_ptr) += written;
44634 -       
44635 +
44636         if (con->conf.kbytes_per_second &&
44637             (con->bytes_written_cur_second > con->conf.kbytes_per_second * 1024)) {
44638                 /* we reached the traffic limit */
44639  
44640                 con->traffic_limit_reached = 1;
44641                 joblist_append(srv, con);
44642 -       }  
44643 +       }
44644         return ret;
44645  }
44646 --- ../lighttpd-1.4.11/src/network.h    2005-08-11 01:26:42.000000000 +0300
44647 +++ lighttpd-1.4.12/src/network.h       2006-07-18 13:03:40.000000000 +0300
44648 @@ -3,11 +3,13 @@
44649  
44650  #include "server.h"
44651  
44652 -int network_write_chunkqueue(server *srv, connection *con, chunkqueue *c);
44653 +network_status_t network_write_chunkqueue(server *srv, connection *con, chunkqueue *c);
44654 +network_status_t network_read_chunkqueue(server *srv, connection *con, chunkqueue *c);
44655  
44656  int network_init(server *srv);
44657  int network_close(server *srv);
44658  
44659  int network_register_fdevents(server *srv);
44660 +handler_t network_server_handle_fdevent(void *s, void *context, int revents);
44661  
44662  #endif
44663 --- ../lighttpd-1.4.11/src/network_backends.h   2005-10-24 15:13:51.000000000 +0300
44664 +++ lighttpd-1.4.12/src/network_backends.h      2006-07-18 13:03:40.000000000 +0300
44665 @@ -43,16 +43,47 @@
44666  # define USE_AIX_SENDFILE
44667  #endif
44668  
44669 +/**
44670 +* unix can use read/write or recv/send on sockets
44671 +* win32 only recv/send
44672 +*/
44673 +#ifdef _WIN32
44674 +# define USE_WIN32_SEND
44675 +/* wait for async-io support
44676 +# define USE_WIN32_TRANSMITFILE
44677 +*/
44678 +#else
44679 +# define USE_WRITE
44680 +#endif
44681 +
44682  #include "base.h"
44683 +#include "network.h"
44684 +
44685 +#define NETWORK_BACKEND_WRITE_CHUNK(x) \
44686 +    network_status_t network_write_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq, chunk *c)
44687 +
44688 +#define NETWORK_BACKEND_WRITE(x) \
44689 +    network_status_t network_write_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq)
44690 +#define NETWORK_BACKEND_READ(x) \
44691 +    network_status_t network_read_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq)
44692 +
44693 +NETWORK_BACKEND_WRITE_CHUNK(writev_mem);
44694 +
44695 +NETWORK_BACKEND_WRITE(write);
44696 +NETWORK_BACKEND_WRITE(writev);
44697 +NETWORK_BACKEND_WRITE(linuxsendfile);
44698 +NETWORK_BACKEND_WRITE(freebsdsendfile);
44699 +NETWORK_BACKEND_WRITE(solarissendfilev);
44700 +
44701 +NETWORK_BACKEND_WRITE(win32transmitfile);
44702 +NETWORK_BACKEND_WRITE(win32send);
44703  
44704 +NETWORK_BACKEND_READ(read);
44705 +NETWORK_BACKEND_READ(win32recv);
44706  
44707 -int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq);
44708 -int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq);
44709 -int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq);
44710 -int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq);
44711 -int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq);
44712  #ifdef USE_OPENSSL
44713 -int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq);
44714 +NETWORK_BACKEND_WRITE(openssl);
44715 +NETWORK_BACKEND_READ(openssl);
44716  #endif
44717  
44718  #endif
44719 --- ../lighttpd-1.4.11/src/network_freebsd_sendfile.c   2005-10-22 12:28:18.000000000 +0300
44720 +++ lighttpd-1.4.12/src/network_freebsd_sendfile.c      2006-07-16 00:26:04.000000000 +0300
44721 @@ -26,142 +26,61 @@
44722  
44723  #ifndef UIO_MAXIOV
44724  # ifdef __FreeBSD__
44725 -/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */ 
44726 +/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */
44727  #  define UIO_MAXIOV 1024
44728  # endif
44729  #endif
44730  
44731 -int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq) {
44732 +NETWORK_BACKEND_WRITE(freebsdsendfile) {
44733         chunk *c;
44734         size_t chunks_written = 0;
44735 -       
44736 +
44737         for(c = cq->first; c; c = c->next, chunks_written++) {
44738                 int chunk_finished = 0;
44739 -               
44740 +               network_status_t ret;
44741 +
44742                 switch(c->type) {
44743 -               case MEM_CHUNK: {
44744 -                       char * offset;
44745 -                       size_t toSend;
44746 -                       ssize_t r;
44747 -                       
44748 -                       size_t num_chunks, i;
44749 -                       struct iovec chunks[UIO_MAXIOV];
44750 -                       chunk *tc;
44751 -                       size_t num_bytes = 0;
44752 -                       
44753 -                       /* we can't send more then SSIZE_MAX bytes in one chunk */
44754 -                       
44755 -                       /* build writev list 
44756 -                        * 
44757 -                        * 1. limit: num_chunks < UIO_MAXIOV
44758 -                        * 2. limit: num_bytes < SSIZE_MAX
44759 -                        */
44760 -                       for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
44761 -                       
44762 -                       for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
44763 -                               if (tc->mem->used == 0) {
44764 -                                       chunks[i].iov_base = tc->mem->ptr;
44765 -                                       chunks[i].iov_len  = 0;
44766 -                               } else {
44767 -                                       offset = tc->mem->ptr + tc->offset;
44768 -                                       toSend = tc->mem->used - 1 - tc->offset;
44769 -                                       
44770 -                                       chunks[i].iov_base = offset;
44771 -                                       
44772 -                                       /* protect the return value of writev() */
44773 -                                       if (toSend > SSIZE_MAX ||
44774 -                                           num_bytes + toSend > SSIZE_MAX) {
44775 -                                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
44776 -                                               
44777 -                                               num_chunks = i + 1;
44778 -                                               break;
44779 -                                       } else {
44780 -                                               chunks[i].iov_len = toSend;
44781 -                                       }
44782 -                                
44783 -                                       num_bytes += toSend;
44784 -                               }
44785 -                       }
44786 -                       
44787 -                       if ((r = writev(fd, chunks, num_chunks)) < 0) {
44788 -                               switch (errno) {
44789 -                               case EAGAIN:
44790 -                               case EINTR:
44791 -                                       r = 0;
44792 -                                       break;
44793 -                               case EPIPE:
44794 -                               case ECONNRESET:
44795 -                                       return -2;
44796 -                               default:
44797 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
44798 -                                                       "writev failed:", strerror(errno), fd);
44799 -                                       
44800 -                                       return -1;
44801 -                               }
44802 +               case MEM_CHUNK:
44803 +                       ret = network_write_chunkqueue_writev_mem(srv, con, fd, cq, &c);
44804  
44805 -                               r = 0;
44806 -                       }
44807 -                       
44808 -                       /* check which chunks have been written */
44809 -                       cq->bytes_out += r;
44810 -                       
44811 -                       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
44812 -                               if (r >= (ssize_t)chunks[i].iov_len) {
44813 -                                       /* written */
44814 -                                       r -= chunks[i].iov_len;
44815 -                                       tc->offset += chunks[i].iov_len;
44816 -                                       
44817 -                                       if (chunk_finished) {
44818 -                                               /* skip the chunks from further touches */
44819 -                                               chunks_written++;
44820 -                                               c = c->next;
44821 -                                       } else {
44822 -                                               /* chunks_written + c = c->next is done in the for()*/
44823 -                                               chunk_finished++;
44824 -                                       }
44825 -                               } else {
44826 -                                       /* partially written */
44827 -                                       
44828 -                                       tc->offset += r;
44829 -                                       chunk_finished = 0;
44830 -                                       
44831 -                                       break;
44832 -                               }
44833 +                       if (ret != NETWORK_STATUS_SUCCESS) {
44834 +                               return ret;
44835                         }
44836 -                       
44837 +
44838 +                       chunk_finished = 1;
44839 +
44840                         break;
44841 -               }
44842                 case FILE_CHUNK: {
44843                         off_t offset, r;
44844                         size_t toSend;
44845                         stat_cache_entry *sce = NULL;
44846                         int ifd;
44847 -                       
44848 +
44849                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
44850                                 log_error_write(srv, __FILE__, __LINE__, "sb",
44851                                                 strerror(errno), c->file.name);
44852 -                               return -1;
44853 +                               return NETWORK_STATUS_FATAL_ERROR;
44854                         }
44855 -                       
44856 +
44857                         offset = c->file.start + c->offset;
44858                         /* limit the toSend to 2^31-1 bytes in a chunk */
44859 -                       toSend = c->file.length - c->offset > ((1 << 30) - 1) ? 
44860 +                       toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
44861                                 ((1 << 30) - 1) : c->file.length - c->offset;
44862 -                               
44863 +
44864                         if (offset > sce->st.st_size) {
44865                                 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
44866 -                               
44867 -                               return -1;
44868 +
44869 +                               return NETWORK_STATUS_FATAL_ERROR;
44870                         }
44871 -                       
44872 +
44873                         if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
44874                                 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
44875 -                               
44876 -                               return -1;
44877 +
44878 +                               return NETWORK_STATUS_FATAL_ERROR;
44879                         }
44880 -                       
44881 +
44882                         r = 0;
44883 -                       
44884 +
44885                         /* FreeBSD sendfile() */
44886                         if (-1 == sendfile(ifd, fd, offset, toSend, NULL, &r, 0)) {
44887                                 switch(errno) {
44888 @@ -169,39 +88,39 @@
44889                                         break;
44890                                 case ENOTCONN:
44891                                         close(ifd);
44892 -                                       return -2;
44893 +                                       return NETWORK_STATUS_CONNECTION_CLOSE;
44894                                 default:
44895                                         log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
44896                                         close(ifd);
44897 -                                       return -1;
44898 +                                       return NETWORK_STATUS_FATAL_ERROR;
44899                                 }
44900                         }
44901                         close(ifd);
44902 -                       
44903 +
44904                         c->offset += r;
44905                         cq->bytes_out += r;
44906 -                       
44907 +
44908                         if (c->offset == c->file.length) {
44909                                 chunk_finished = 1;
44910                         }
44911 -                       
44912 +
44913                         break;
44914                 }
44915                 default:
44916 -                       
44917 +
44918                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
44919 -                       
44920 +
44921                         return -1;
44922                 }
44923 -               
44924 +
44925                 if (!chunk_finished) {
44926                         /* not finished yet */
44927 -                       
44928 +
44929                         break;
44930                 }
44931         }
44932  
44933 -       return chunks_written;
44934 +       return NETWORK_STATUS_SUCCESS;
44935  }
44936  
44937  #endif
44938 --- ../lighttpd-1.4.11/src/network_linux_sendfile.c     2006-02-15 20:02:36.000000000 +0200
44939 +++ lighttpd-1.4.12/src/network_linux_sendfile.c        2006-07-18 13:03:40.000000000 +0300
44940 @@ -26,122 +26,54 @@
44941  /* on linux 2.4.29 + debian/ubuntu we have crashes if this is enabled */
44942  #undef HAVE_POSIX_FADVISE
44943  
44944 -int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq) {
44945 -       chunk *c;
44946 +NETWORK_BACKEND_WRITE(linuxsendfile) {
44947 +       chunk *c, *tc;
44948         size_t chunks_written = 0;
44949 -       
44950 +
44951         for(c = cq->first; c; c = c->next, chunks_written++) {
44952                 int chunk_finished = 0;
44953 -               
44954 +               network_status_t ret;
44955 +
44956                 switch(c->type) {
44957 -               case MEM_CHUNK: {
44958 -                       char * offset;
44959 -                       size_t toSend;
44960 -                       ssize_t r;
44961 -                       
44962 -                       size_t num_chunks, i;
44963 -                       struct iovec chunks[UIO_MAXIOV];
44964 -                       chunk *tc;
44965 -                       size_t num_bytes = 0;
44966 -                       
44967 -                       /* we can't send more then SSIZE_MAX bytes in one chunk */
44968 -                       
44969 -                       /* build writev list 
44970 -                        * 
44971 -                        * 1. limit: num_chunks < UIO_MAXIOV
44972 -                        * 2. limit: num_bytes < SSIZE_MAX
44973 -                        */
44974 -                       for (num_chunks = 0, tc = c; 
44975 -                            tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; 
44976 -                            tc = tc->next, num_chunks++);
44977 -                       
44978 -                       for (tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
44979 -                               if (tc->mem->used == 0) {
44980 -                                       chunks[i].iov_base = tc->mem->ptr;
44981 -                                       chunks[i].iov_len  = 0;
44982 -                               } else {
44983 -                                       offset = tc->mem->ptr + tc->offset;
44984 -                                       toSend = tc->mem->used - 1 - tc->offset;
44985 -                               
44986 -                                       chunks[i].iov_base = offset;
44987 -                                       
44988 -                                       /* protect the return value of writev() */
44989 -                                       if (toSend > SSIZE_MAX ||
44990 -                                           num_bytes + toSend > SSIZE_MAX) {
44991 -                                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
44992 -                                               
44993 -                                               num_chunks = i + 1;
44994 -                                               break;
44995 -                                       } else {
44996 -                                               chunks[i].iov_len = toSend;
44997 -                                       }
44998 -                                
44999 -                                       num_bytes += toSend;
45000 -                               }
45001 -                       }
45002 -                       
45003 -                       if ((r = writev(fd, chunks, num_chunks)) < 0) {
45004 -                               switch (errno) {
45005 -                               case EAGAIN:
45006 -                               case EINTR:
45007 -                                       r = 0;
45008 -                                       break;
45009 -                               case EPIPE:
45010 -                               case ECONNRESET:
45011 -                                       return -2;
45012 -                               default:
45013 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
45014 -                                                       "writev failed:", strerror(errno), fd);
45015 -                               
45016 -                                       return -1;
45017 -                               }
45018 -                       }
45019 -                       
45020 -                       /* check which chunks have been written */
45021 -                       cq->bytes_out += r;
45022 +               case MEM_CHUNK:
45023 +                       ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
45024  
45025 -                       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
45026 -                               if (r >= (ssize_t)chunks[i].iov_len) {
45027 -                                       /* written */
45028 -                                       r -= chunks[i].iov_len;
45029 -                                       tc->offset += chunks[i].iov_len;
45030 -                                       
45031 +                       /* check which chunks are finished now */
45032 +                       for (tc = c; tc; tc = tc->next) {
45033 +                               /* finished the chunk */
45034 +                               if (tc->offset == tc->mem->used - 1) {
45035 +                                       /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
45036                                         if (chunk_finished) {
45037 -                                               /* skip the chunks from further touches */
45038 -                                               chunks_written++;
45039                                                 c = c->next;
45040                                         } else {
45041 -                                               /* chunks_written + c = c->next is done in the for()*/
45042 -                                               chunk_finished++;
45043 +                                               chunk_finished = 1;
45044                                         }
45045                                 } else {
45046 -                                       /* partially written */
45047 -                                       
45048 -                                       tc->offset += r;
45049 -                                       chunk_finished = 0;
45050 -                                       
45051                                         break;
45052                                 }
45053                         }
45054 -                       
45055 +
45056 +                       if (ret != NETWORK_STATUS_SUCCESS) {
45057 +                               return ret;
45058 +                       }
45059 +
45060                         break;
45061 -               }
45062                 case FILE_CHUNK: {
45063                         ssize_t r;
45064                         off_t offset;
45065                         size_t toSend;
45066                         stat_cache_entry *sce = NULL;
45067 -                       
45068 +
45069                         offset = c->file.start + c->offset;
45070                         /* limit the toSend to 2^31-1 bytes in a chunk */
45071 -                       toSend = c->file.length - c->offset > ((1 << 30) - 1) ? 
45072 +                       toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
45073                                 ((1 << 30) - 1) : c->file.length - c->offset;
45074 -                               
45075 -                       /* open file if not already opened */   
45076 +
45077 +                       /* open file if not already opened */
45078                         if (-1 == c->file.fd) {
45079                                 if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
45080                                         log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
45081 -                               
45082 +
45083                                         return -1;
45084                                 }
45085  #ifdef FD_CLOEXEC
45086 @@ -151,14 +83,14 @@
45087                                 /* tell the kernel that we want to stream the file */
45088                                 if (-1 == posix_fadvise(c->file.fd, 0, 0, POSIX_FADV_SEQUENTIAL)) {
45089                                         if (ENOSYS != errno) {
45090 -                                               log_error_write(srv, __FILE__, __LINE__, "ssd", 
45091 +                                               log_error_write(srv, __FILE__, __LINE__, "ssd",
45092                                                         "posix_fadvise failed:", strerror(errno), c->file.fd);
45093                                         }
45094                                 }
45095  #endif
45096                         }
45097  
45098 -                       if (-1 == (r = sendfile(fd, c->file.fd, &offset, toSend))) {
45099 +                       if (-1 == (r = sendfile(sock->fd, c->file.fd, &offset, toSend))) {
45100                                 switch (errno) {
45101                                 case EAGAIN:
45102                                 case EINTR:
45103 @@ -166,11 +98,11 @@
45104                                         break;
45105                                 case EPIPE:
45106                                 case ECONNRESET:
45107 -                                       return -2;
45108 +                                       return NETWORK_STATUS_CONNECTION_CLOSE;
45109                                 default:
45110 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
45111 -                                                       "sendfile failed:", strerror(errno), fd);
45112 -                                       return -1;
45113 +                                       log_error_write(srv, __FILE__, __LINE__, "ssd",
45114 +                                                       "sendfile failed:", strerror(errno), sock->fd);
45115 +                                       return NETWORK_STATUS_FATAL_ERROR;
45116                                 }
45117                         }
45118  
45119 @@ -179,39 +111,39 @@
45120                                  *
45121                                  * - the file shrinked -> error
45122                                  * - the remote side closed inbetween -> remote-close */
45123 -       
45124 +
45125                                 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
45126                                         /* file is gone ? */
45127 -                                       return -1;
45128 +                                       return NETWORK_STATUS_FATAL_ERROR;
45129                                 }
45130  
45131                                 if (offset > sce->st.st_size) {
45132                                         /* file shrinked, close the connection */
45133 -                                       return -1;
45134 +                                       return NETWORK_STATUS_FATAL_ERROR;
45135                                 }
45136  
45137 -                               return -2;
45138 +                               return NETWORK_STATUS_CONNECTION_CLOSE;
45139                         }
45140  
45141  #ifdef HAVE_POSIX_FADVISE
45142  #if 0
45143  #define K * 1024
45144 -#define M * 1024 K     
45145 +#define M * 1024 K
45146  #define READ_AHEAD 4 M
45147                         /* check if we need a new chunk */
45148                         if ((c->offset & ~(READ_AHEAD - 1)) != ((c->offset + r) & ~(READ_AHEAD - 1))) {
45149                                 /* tell the kernel that we want to stream the file */
45150                                 if (-1 == posix_fadvise(c->file.fd, (c->offset + r) & ~(READ_AHEAD - 1), READ_AHEAD, POSIX_FADV_NOREUSE)) {
45151 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
45152 +                                       log_error_write(srv, __FILE__, __LINE__, "ssd",
45153                                                 "posix_fadvise failed:", strerror(errno), c->file.fd);
45154                                 }
45155                         }
45156  #endif
45157  #endif
45158 -                       
45159 +
45160                         c->offset += r;
45161                         cq->bytes_out += r;
45162 -                       
45163 +
45164                         if (c->offset == c->file.length) {
45165                                 chunk_finished = 1;
45166  
45167 @@ -222,24 +154,24 @@
45168                                         c->file.fd = -1;
45169                                 }
45170                         }
45171 -                       
45172 +
45173                         break;
45174                 }
45175                 default:
45176 -                       
45177 +
45178                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
45179 -                       
45180 -                       return -1;
45181 +
45182 +                       return NETWORK_STATUS_FATAL_ERROR;
45183                 }
45184 -               
45185 +
45186                 if (!chunk_finished) {
45187                         /* not finished yet */
45188 -                       
45189 -                       break;
45190 +
45191 +                       return NETWORK_STATUS_WAIT_FOR_EVENT;
45192                 }
45193         }
45194  
45195 -       return chunks_written;
45196 +       return NETWORK_STATUS_SUCCESS;
45197  }
45198  
45199  #endif
45200 --- ../lighttpd-1.4.11/src/network_openssl.c    2005-11-17 14:53:29.000000000 +0200
45201 +++ lighttpd-1.4.12/src/network_openssl.c       2006-07-18 13:03:40.000000000 +0300
45202 @@ -23,17 +23,87 @@
45203  #include "log.h"
45204  #include "stat_cache.h"
45205  
45206 -# include <openssl/ssl.h> 
45207 -# include <openssl/err.h> 
45208 +# include <openssl/ssl.h>
45209 +# include <openssl/err.h>
45210  
45211 -int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq) {
45212 +NETWORK_BACKEND_READ(openssl) {
45213 +       buffer *b;
45214 +       off_t len;
45215 +
45216 +       b = chunkqueue_get_append_buffer(cq);
45217 +       buffer_prepare_copy(b, 8192);
45218 +       len = SSL_read(sock->ssl, b->ptr, b->size - 1);
45219 +
45220 +       log_error_write(srv, __FILE__, __LINE__, "so", "SSL:", len);
45221 +
45222 +       if (len < 0) {
45223 +               int r, ssl_err;
45224 +
45225 +               switch ((r = SSL_get_error(sock->ssl, len))) {
45226 +               case SSL_ERROR_WANT_READ:
45227 +                       return NETWORK_STATUS_WAIT_FOR_EVENT;
45228 +               case SSL_ERROR_SYSCALL:
45229 +                       /**
45230 +                        * man SSL_get_error()
45231 +                        *
45232 +                        * SSL_ERROR_SYSCALL
45233 +                        *   Some I/O error occurred.  The OpenSSL error queue may contain more
45234 +                        *   information on the error.  If the error queue is empty (i.e.
45235 +                        *   ERR_get_error() returns 0), ret can be used to find out more about
45236 +                        *   the error: If ret == 0, an EOF was observed that violates the
45237 +                        *   protocol.  If ret == -1, the underlying BIO reported an I/O error
45238 +                        *   (for socket I/O on Unix systems, consult errno for details).
45239 +                        *
45240 +                        */
45241 +                       while((ssl_err = ERR_get_error())) {
45242 +                               /* get all errors from the error-queue */
45243 +                               log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
45244 +                                               r, ERR_error_string(ssl_err, NULL));
45245 +                       }
45246 +
45247 +                       switch(errno) {
45248 +                       default:
45249 +                               log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
45250 +                                               len, r, errno,
45251 +                                               strerror(errno));
45252 +                               break;
45253 +                       }
45254 +
45255 +                       break;
45256 +               case SSL_ERROR_ZERO_RETURN:
45257 +                       /* clean shutdown on the remote side */
45258 +
45259 +                       if (r == 0) {
45260 +                               /* FIXME: later */
45261 +                       }
45262 +
45263 +                       /* fall thourgh */
45264 +               default:
45265 +                       while((ssl_err = ERR_get_error())) {
45266 +                               /* get all errors from the error-queue */
45267 +                               log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
45268 +                                               r, ERR_error_string(ssl_err, NULL));
45269 +                       }
45270 +                       break;
45271 +               }
45272 +       }
45273 +
45274 +       assert(len > 0);
45275 +       b->used += len;
45276 +       b->ptr[b->used - 1] = '\0';
45277 +
45278 +       return NETWORK_STATUS_SUCCESS;
45279 +}
45280 +
45281 +
45282 +NETWORK_BACKEND_WRITE(openssl) {
45283         int ssl_r;
45284         chunk *c;
45285         size_t chunks_written = 0;
45286  
45287         /* this is a 64k sendbuffer
45288          *
45289 -        * it has to stay at the same location all the time to satisfy the needs 
45290 +        * it has to stay at the same location all the time to satisfy the needs
45291          * of SSL_write to pass the SAME parameter in case of a _WANT_WRITE
45292          *
45293          * the buffer is allocated once, is NOT realloced and is NOT freed at shutdown
45294 @@ -43,59 +113,61 @@
45295          * In reality we would like to use mmap() but we don't have a guarantee that
45296          * we get the same mmap() address for each call. On openbsd the mmap() address
45297          * even randomized.
45298 -        *   That means either we keep the mmap() open or we do a read() into a 
45299 -        * constant buffer 
45300 +        *   That means either we keep the mmap() open or we do a read() into a
45301 +        * constant buffer
45302          * */
45303  #define LOCAL_SEND_BUFSIZE (64 * 1024)
45304         static char *local_send_buffer = NULL;
45305  
45306         /* the remote side closed the connection before without shutdown request
45307 -        * - IE 
45308 +        * - IE
45309          * - wget
45310          * if keep-alive is disabled */
45311  
45312         if (con->keep_alive == 0) {
45313 -               SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
45314 +               SSL_set_shutdown(sock->ssl, SSL_RECEIVED_SHUTDOWN);
45315         }
45316  
45317         for(c = cq->first; c; c = c->next) {
45318                 int chunk_finished = 0;
45319 -               
45320 +
45321                 switch(c->type) {
45322                 case MEM_CHUNK: {
45323                         char * offset;
45324                         size_t toSend;
45325 -                       ssize_t r;
45326 -                       
45327 +                       ssize_t r = 0;
45328 +
45329                         if (c->mem->used == 0) {
45330                                 chunk_finished = 1;
45331                                 break;
45332                         }
45333 -                       
45334 +
45335                         offset = c->mem->ptr + c->offset;
45336                         toSend = c->mem->used - 1 - c->offset;
45337 -                       
45338 +
45339                         /**
45340                          * SSL_write man-page
45341 -                        * 
45342 +                        *
45343                          * WARNING
45344                          *        When an SSL_write() operation has to be repeated because of
45345                          *        SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be
45346                          *        repeated with the same arguments.
45347 -                        * 
45348 +                        *
45349 +                        * SSL_write(..., 0) return 0 which is handle as an error (Success)
45350 +                        * checking toSend and not calling SSL_write() is simpler
45351                          */
45352 -                       
45353 -                       if ((r = SSL_write(ssl, offset, toSend)) <= 0) {
45354 +
45355 +                       if (toSend != 0 && (r = SSL_write(sock->ssl, offset, toSend)) <= 0) {
45356                                 unsigned long err;
45357  
45358 -                               switch ((ssl_r = SSL_get_error(ssl, r))) {
45359 +                               switch ((ssl_r = SSL_get_error(sock->ssl, r))) {
45360                                 case SSL_ERROR_WANT_WRITE:
45361                                         break;
45362                                 case SSL_ERROR_SYSCALL:
45363                                         /* perhaps we have error waiting in our error-queue */
45364                                         if (0 != (err = ERR_get_error())) {
45365                                                 do {
45366 -                                                       log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", 
45367 +                                                       log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45368                                                                         ssl_r, r,
45369                                                                         ERR_error_string(err, NULL));
45370                                                 } while((err = ERR_get_error()));
45371 @@ -105,43 +177,43 @@
45372                                                 case EPIPE:
45373                                                         return -2;
45374                                                 default:
45375 -                                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", 
45376 +                                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
45377                                                                         ssl_r, r, errno,
45378                                                                         strerror(errno));
45379                                                         break;
45380                                                 }
45381                                         } else {
45382                                                 /* neither error-queue nor errno ? */
45383 -                                               log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):", 
45384 +                                               log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
45385                                                                 ssl_r, r, errno,
45386                                                                 strerror(errno));
45387                                         }
45388 -                                       
45389 +
45390                                         return  -1;
45391                                 case SSL_ERROR_ZERO_RETURN:
45392                                         /* clean shutdown on the remote side */
45393 -                                       
45394 +
45395                                         if (r == 0) return -2;
45396 -                                       
45397 +
45398                                         /* fall through */
45399                                 default:
45400                                         while((err = ERR_get_error())) {
45401 -                                               log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", 
45402 +                                               log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45403                                                                 ssl_r, r,
45404                                                                 ERR_error_string(err, NULL));
45405                                         }
45406 -                                       
45407 +
45408                                         return  -1;
45409                                 }
45410                         } else {
45411                                 c->offset += r;
45412                                 cq->bytes_out += r;
45413                         }
45414 -                       
45415 +
45416                         if (c->offset == (off_t)c->mem->used - 1) {
45417                                 chunk_finished = 1;
45418                         }
45419 -                       
45420 +
45421                         break;
45422                 }
45423                 case FILE_CHUNK: {
45424 @@ -150,7 +222,7 @@
45425                         stat_cache_entry *sce = NULL;
45426                         int ifd;
45427                         int write_wait = 0;
45428 -                       
45429 +
45430                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
45431                                 log_error_write(srv, __FILE__, __LINE__, "sb",
45432                                                 strerror(errno), c->file.name);
45433 @@ -164,13 +236,13 @@
45434  
45435                         do {
45436                                 off_t offset = c->file.start + c->offset;
45437 -                               off_t toSend = c->file.length - c->offset; 
45438 +                               off_t toSend = c->file.length - c->offset;
45439  
45440                                 if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE;
45441 -                       
45442 +
45443                                 if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
45444                                         log_error_write(srv, __FILE__, __LINE__, "ss", "open failed:", strerror(errno));
45445 -                               
45446 +
45447                                         return -1;
45448                                 }
45449  
45450 @@ -183,13 +255,13 @@
45451                                 }
45452  
45453                                 s = local_send_buffer;
45454 -                       
45455 +
45456                                 close(ifd);
45457 -                       
45458 -                               if ((r = SSL_write(ssl, s, toSend)) <= 0) {
45459 +
45460 +                               if ((r = SSL_write(sock->ssl, s, toSend)) <= 0) {
45461                                         unsigned long err;
45462  
45463 -                                       switch ((ssl_r = SSL_get_error(ssl, r))) {
45464 +                                       switch ((ssl_r = SSL_get_error(sock->ssl, r))) {
45465                                         case SSL_ERROR_WANT_WRITE:
45466                                                 write_wait = 1;
45467                                                 break;
45468 @@ -197,7 +269,7 @@
45469                                                 /* perhaps we have error waiting in our error-queue */
45470                                                 if (0 != (err = ERR_get_error())) {
45471                                                         do {
45472 -                                                               log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", 
45473 +                                                               log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45474                                                                                 ssl_r, r,
45475                                                                                 ERR_error_string(err, NULL));
45476                                                         } while((err = ERR_get_error()));
45477 @@ -207,62 +279,62 @@
45478                                                         case EPIPE:
45479                                                                 return -2;
45480                                                         default:
45481 -                                                               log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", 
45482 +                                                               log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
45483                                                                                 ssl_r, r, errno,
45484                                                                                 strerror(errno));
45485                                                                 break;
45486                                                         }
45487                                                 } else {
45488                                                         /* neither error-queue nor errno ? */
45489 -                                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):", 
45490 +                                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
45491                                                                         ssl_r, r, errno,
45492                                                                         strerror(errno));
45493                                                 }
45494 -                                       
45495 +
45496                                                 return  -1;
45497                                         case SSL_ERROR_ZERO_RETURN:
45498                                                 /* clean shutdown on the remote side */
45499 -                                       
45500 +
45501                                                 if (r == 0)  return -2;
45502 -                                       
45503 +
45504                                                 /* fall thourgh */
45505                                         default:
45506                                                 while((err = ERR_get_error())) {
45507 -                                                       log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", 
45508 +                                                       log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45509                                                                         ssl_r, r,
45510                                                                         ERR_error_string(err, NULL));
45511                                                 }
45512 -                                       
45513 +
45514                                                 return -1;
45515                                         }
45516                                 } else {
45517                                         c->offset += r;
45518                                         cq->bytes_out += r;
45519                                 }
45520 -                       
45521 +
45522                                 if (c->offset == c->file.length) {
45523                                         chunk_finished = 1;
45524                                 }
45525                         } while(!chunk_finished && !write_wait);
45526 -                       
45527 +
45528                         break;
45529                 }
45530                 default:
45531                         log_error_write(srv, __FILE__, __LINE__, "s", "type not known");
45532 -                       
45533 +
45534                         return -1;
45535                 }
45536 -                       
45537 +
45538                 if (!chunk_finished) {
45539                         /* not finished yet */
45540 -                       
45541 +
45542                         break;
45543                 }
45544 -                       
45545 +
45546                 chunks_written++;
45547         }
45548  
45549 -       return chunks_written;
45550 +       return NETWORK_STATUS_SUCCESS;
45551  }
45552  #endif
45553  
45554 --- ../lighttpd-1.4.11/src/network_solaris_sendfilev.c  2005-10-22 12:28:27.000000000 +0300
45555 +++ lighttpd-1.4.12/src/network_solaris_sendfilev.c     2006-07-16 00:26:04.000000000 +0300
45556 @@ -29,114 +29,34 @@
45557  #endif
45558  
45559  /**
45560 - * a very simple sendfilev() interface for solaris which can be optimised a lot more 
45561 + * a very simple sendfilev() interface for solaris which can be optimised a lot more
45562   * as solaris sendfilev() supports 'sending everythin in one syscall()'
45563 - * 
45564 - * If you want such an interface and need the performance, just give me an account on 
45565 - * a solaris box. 
45566 + *
45567 + * If you want such an interface and need the performance, just give me an account on
45568 + * a solaris box.
45569   *   - jan@kneschke.de
45570   */
45571  
45572  
45573 -int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq) {
45574 +NETWORK_BACKEND_WRITE(solarissendfilev) {
45575         chunk *c;
45576         size_t chunks_written = 0;
45577 -       
45578 +
45579         for(c = cq->first; c; c = c->next, chunks_written++) {
45580                 int chunk_finished = 0;
45581 -               
45582 +               network_status_t ret;
45583 +
45584                 switch(c->type) {
45585 -               case MEM_CHUNK: {
45586 -                       char * offset;
45587 -                       size_t toSend;
45588 -                       ssize_t r;
45589 -                       
45590 -                       size_t num_chunks, i;
45591 -                       struct iovec chunks[UIO_MAXIOV];
45592 -                       chunk *tc;
45593 -                       
45594 -                       size_t num_bytes = 0;
45595 -                       
45596 -                       /* we can't send more then SSIZE_MAX bytes in one chunk */
45597 -                       
45598 -                       /* build writev list 
45599 -                        * 
45600 -                        * 1. limit: num_chunks < UIO_MAXIOV
45601 -                        * 2. limit: num_bytes < SSIZE_MAX
45602 -                        */
45603 -                       for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
45604 -                       
45605 -                       for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
45606 -                               if (tc->mem->used == 0) {
45607 -                                       chunks[i].iov_base = tc->mem->ptr;
45608 -                                       chunks[i].iov_len  = 0;
45609 -                               } else {
45610 -                                       offset = tc->mem->ptr + tc->offset;
45611 -                                       toSend = tc->mem->used - 1 - tc->offset;
45612 -                               
45613 -                                       chunks[i].iov_base = offset;
45614 -                                       
45615 -                                       /* protect the return value of writev() */
45616 -                                       if (toSend > SSIZE_MAX ||
45617 -                                           num_bytes + toSend > SSIZE_MAX) {
45618 -                                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
45619 -                                               
45620 -                                               num_chunks = i + 1;
45621 -                                               break;
45622 -                                       } else {
45623 -                                               chunks[i].iov_len = toSend;
45624 -                                       }
45625 -                                       
45626 -                                       num_bytes += toSend;
45627 -                               }
45628 -                       }
45629 -                       
45630 -                       if ((r = writev(fd, chunks, num_chunks)) < 0) {
45631 -                               switch (errno) {
45632 -                               case EAGAIN:
45633 -                               case EINTR:
45634 -                                       r = 0;
45635 -                                       break;
45636 -                               case EPIPE:
45637 -                               case ECONNRESET:
45638 -                                       return -2;
45639 -                               default:
45640 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
45641 -                                                       "writev failed:", strerror(errno), fd);
45642 -                               
45643 -                                       return -1;
45644 -                               }
45645 -                       }
45646 -                       
45647 -                       /* check which chunks have been written */
45648 -                       cq->bytes_out += r;
45649 -                       
45650 -                       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
45651 -                               if (r >= (ssize_t)chunks[i].iov_len) {
45652 -                                       /* written */
45653 -                                       r -= chunks[i].iov_len;
45654 -                                       tc->offset += chunks[i].iov_len;
45655 -                                       
45656 -                                       if (chunk_finished) {
45657 -                                               /* skip the chunks from further touches */
45658 -                                               chunks_written++;
45659 -                                               c = c->next;
45660 -                                       } else {
45661 -                                               /* chunks_written + c = c->next is done in the for()*/
45662 -                                               chunk_finished++;
45663 -                                       }
45664 -                               } else {
45665 -                                       /* partially written */
45666 -                                       
45667 -                                       tc->offset += r;
45668 -                                       chunk_finished = 0;
45669 -                                       
45670 -                                       break;
45671 -                               }
45672 +               case MEM_CHUNK:
45673 +                       ret = network_write_chunkqueue_writev_mem(srv, con, fd, cq, &c);
45674 +
45675 +                       if (ret != NETWORK_STATUS_SUCCESS) {
45676 +                               return ret;
45677                         }
45678 -                       
45679 +
45680 +                       chunk_finished = 1;
45681 +
45682                         break;
45683 -               }
45684                 case FILE_CHUNK: {
45685                         ssize_t r;
45686                         off_t offset;
45687 @@ -144,25 +64,25 @@
45688                         sendfilevec_t fvec;
45689                         stat_cache_entry *sce = NULL;
45690                         int ifd;
45691 -                       
45692 +
45693                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
45694                                 log_error_write(srv, __FILE__, __LINE__, "sb",
45695                                                 strerror(errno), c->file.name);
45696                                 return -1;
45697                         }
45698 -                                       
45699 +
45700                         offset = c->file.start + c->offset;
45701                         toSend = c->file.length - c->offset;
45702 -                       
45703 +
45704                         if (offset > sce->st.st_size) {
45705                                 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
45706 -                               
45707 +
45708                                 return -1;
45709                         }
45710  
45711                         if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
45712                                 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
45713 -                               
45714 +
45715                                 return -1;
45716                         }
45717  
45718 @@ -170,44 +90,43 @@
45719                         fvec.sfv_flag = 0;
45720                         fvec.sfv_off = offset;
45721                         fvec.sfv_len = toSend;
45722 -                       
45723 +
45724                         /* Solaris sendfilev() */
45725                         if (-1 == (r = sendfilev(fd, &fvec, 1, &written))) {
45726                                 if (errno != EAGAIN) {
45727                                         log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
45728 -                                       
45729 +
45730                                         close(ifd);
45731 -                                       return -1;
45732 +                                       return NETWORK_STATUS_FATAL_ERROR;
45733                                 }
45734 -                               
45735 +
45736                                 r = 0;
45737                         }
45738 -                       
45739 +
45740                         close(ifd);
45741                         c->offset += written;
45742                         cq->bytes_out += written;
45743 -                       
45744 +
45745                         if (c->offset == c->file.length) {
45746                                 chunk_finished = 1;
45747                         }
45748 -                       
45749 +
45750                         break;
45751                 }
45752                 default:
45753 -                       
45754                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
45755 -                       
45756 -                       return -1;
45757 +
45758 +                       return NETWORK_STATUS_FATAL_ERROR;
45759                 }
45760 -               
45761 +
45762                 if (!chunk_finished) {
45763                         /* not finished yet */
45764 -                       
45765 +
45766                         break;
45767                 }
45768         }
45769  
45770 -       return chunks_written;
45771 +       return NETWORK_STATUS_SUCCESS;
45772  }
45773  
45774  #endif
45775 --- ../lighttpd-1.4.11/src/network_write.c      2005-10-22 12:27:56.000000000 +0300
45776 +++ lighttpd-1.4.12/src/network_write.c 2006-07-18 13:03:40.000000000 +0300
45777 @@ -1,11 +1,11 @@
45778  #include <sys/types.h>
45779  #include <sys/stat.h>
45780 -#include <sys/time.h>
45781 +
45782  #include <errno.h>
45783  #include <fcntl.h>
45784 -#include <unistd.h>
45785  #include <string.h>
45786  #include <stdlib.h>
45787 +#include <assert.h>
45788  
45789  #include "network.h"
45790  #include "fdevent.h"
45791 @@ -13,9 +13,12 @@
45792  #include "stat_cache.h"
45793  
45794  #include "sys-socket.h"
45795 +#include "sys-files.h"
45796  
45797  #include "network_backends.h"
45798  
45799 +#ifdef USE_WRITE
45800 +
45801  #ifdef HAVE_SYS_FILIO_H
45802  # include <sys/filio.h>
45803  #endif
45804 @@ -24,47 +27,92 @@
45805  #include <sys/resource.h>
45806  #endif
45807  
45808 -int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq) {
45809 +
45810 +/**
45811 +* fill the chunkqueue will all the data that we can get
45812 +*
45813 +* this might be optimized into a readv() which uses the chunks
45814 +* as vectors
45815 +*/
45816 +NETWORK_BACKEND_READ(read) {
45817 +       int toread;
45818 +       buffer *b;
45819 +       off_t r;
45820 +
45821 +       /**
45822 +        * a EAGAIN is a successful read if we already read something to the chunkqueue
45823 +        */
45824 +       int read_something = 0;
45825 +
45826 +       /* use a chunk-size of 8k */
45827 +       do {
45828 +               toread = 8192;
45829 +
45830 +               b = chunkqueue_get_append_buffer(cq);
45831 +
45832 +               buffer_prepare_copy(b, toread);
45833 +
45834 +               if (-1 == (r = read(sock->fd, b->ptr, toread))) {
45835 +                       switch (errno) {
45836 +                       case EAGAIN:
45837 +                               /* remove the last chunk from the chunkqueue */
45838 +                               chunkqueue_remove_empty_last_chunk(cq);
45839 +                               return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_WAIT_FOR_EVENT;
45840 +                       default:
45841 +                               ERROR("oops, read from fd=%d failed: %s (%d)", sock->fd, strerror(errno), errno );
45842 +
45843 +                               return NETWORK_STATUS_FATAL_ERROR;
45844 +                       }
45845 +               }
45846 +
45847 +               if (r == 0) {
45848 +                       chunkqueue_remove_empty_last_chunk(cq);
45849 +                       return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_CONNECTION_CLOSE;
45850 +               }
45851 +
45852 +               read_something = 1;
45853 +
45854 +               b->used = r;
45855 +               b->ptr[b->used++] = '\0';
45856 +       } while (r == toread); 
45857 +
45858 +       return NETWORK_STATUS_SUCCESS;
45859 +}
45860 +
45861 +NETWORK_BACKEND_WRITE(write) {
45862         chunk *c;
45863         size_t chunks_written = 0;
45864 -       
45865 +
45866         for(c = cq->first; c; c = c->next) {
45867                 int chunk_finished = 0;
45868 -               
45869 +
45870                 switch(c->type) {
45871                 case MEM_CHUNK: {
45872                         char * offset;
45873                         size_t toSend;
45874                         ssize_t r;
45875 -                       
45876 +
45877                         if (c->mem->used == 0) {
45878                                 chunk_finished = 1;
45879                                 break;
45880                         }
45881 -                       
45882 +
45883                         offset = c->mem->ptr + c->offset;
45884                         toSend = c->mem->used - 1 - c->offset;
45885 -#ifdef __WIN32 
45886 -                       if ((r = send(fd, offset, toSend, 0)) < 0) {
45887 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd);
45888 -                               
45889 -                               return -1;
45890 -                       }
45891 -#else
45892 -                       if ((r = write(fd, offset, toSend)) < 0) {
45893 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd);
45894 -                               
45895 -                               return -1;
45896 +
45897 +                       if ((r = write(sock->fd, offset, toSend)) < 0) {
45898 +                               log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), sock->fd);
45899 +
45900 +                               return NETWORK_STATUS_FATAL_ERROR;
45901                         }
45902 -#endif
45903 -                       
45904 +
45905                         c->offset += r;
45906                         cq->bytes_out += r;
45907 -                       
45908 +
45909                         if (c->offset == (off_t)c->mem->used - 1) {
45910                                 chunk_finished = 1;
45911                         }
45912 -                       
45913 +
45914                         break;
45915                 }
45916                 case FILE_CHUNK: {
45917 @@ -76,93 +124,89 @@
45918                         size_t toSend;
45919                         stat_cache_entry *sce = NULL;
45920                         int ifd;
45921 -                       
45922 +
45923                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
45924                                 log_error_write(srv, __FILE__, __LINE__, "sb",
45925                                                 strerror(errno), c->file.name);
45926 -                               return -1;
45927 +                               return NETWORK_STATUS_FATAL_ERROR;
45928                         }
45929 -                       
45930 +
45931                         offset = c->file.start + c->offset;
45932                         toSend = c->file.length - c->offset;
45933 -                       
45934 +
45935                         if (offset > sce->st.st_size) {
45936                                 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
45937 -                               
45938 -                               return -1;
45939 +
45940 +                               return NETWORK_STATUS_FATAL_ERROR;
45941                         }
45942  
45943                         if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
45944                                 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
45945 -                               
45946 -                               return -1;
45947 +
45948 +                               return NETWORK_STATUS_FATAL_ERROR;
45949                         }
45950 -                       
45951 +
45952  #if defined USE_MMAP
45953                         if (MAP_FAILED == (p = mmap(0, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
45954                                 log_error_write(srv, __FILE__, __LINE__, "ss", "mmap failed: ", strerror(errno));
45955  
45956                                 close(ifd);
45957 -                               
45958 -                               return -1;
45959 +
45960 +                               return NETWORK_STATUS_FATAL_ERROR;
45961                         }
45962                         close(ifd);
45963  
45964 -                       if ((r = write(fd, p + offset, toSend)) <= 0) {
45965 +                       if ((r = write(sock->fd, p + offset, toSend)) <= 0) {
45966                                 log_error_write(srv, __FILE__, __LINE__, "ss", "write failed: ", strerror(errno));
45967                                 munmap(p, sce->st.st_size);
45968 -                               return -1;
45969 +                               return NETWORK_STATUS_FATAL_ERROR;
45970                         }
45971 -                       
45972 +
45973                         munmap(p, sce->st.st_size);
45974  #else
45975                         buffer_prepare_copy(srv->tmp_buf, toSend);
45976 -                       
45977 +
45978                         lseek(ifd, offset, SEEK_SET);
45979                         if (-1 == (toSend = read(ifd, srv->tmp_buf->ptr, toSend))) {
45980                                 log_error_write(srv, __FILE__, __LINE__, "ss", "read: ", strerror(errno));
45981                                 close(ifd);
45982 -                               
45983 -                               return -1;
45984 +
45985 +                               return NETWORK_STATUS_FATAL_ERROR;
45986                         }
45987                         close(ifd);
45988  
45989 -                       if (-1 == (r = send(fd, srv->tmp_buf->ptr, toSend, 0))) {
45990 +                       if (-1 == (r = send(sock->fd, srv->tmp_buf->ptr, toSend, 0))) {
45991                                 log_error_write(srv, __FILE__, __LINE__, "ss", "write: ", strerror(errno));
45992 -                               
45993 -                               return -1;
45994 +
45995 +                               return NETWORK_STATUS_FATAL_ERROR;
45996                         }
45997  #endif
45998                         c->offset += r;
45999                         cq->bytes_out += r;
46000 -                       
46001 +
46002                         if (c->offset == c->file.length) {
46003                                 chunk_finished = 1;
46004                         }
46005 -                       
46006 +
46007                         break;
46008                 }
46009                 default:
46010 -                       
46011 +
46012                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
46013 -                       
46014 -                       return -1;
46015 +
46016 +                       return NETWORK_STATUS_FATAL_ERROR;
46017                 }
46018 -               
46019 +
46020                 if (!chunk_finished) {
46021                         /* not finished yet */
46022 -                       
46023 +
46024                         break;
46025                 }
46026 -               
46027 +
46028                 chunks_written++;
46029         }
46030  
46031 -       return chunks_written;
46032 +       return NETWORK_STATUS_SUCCESS;
46033  }
46034  
46035 -#if 0
46036 -network_write_init(void) {
46037 -       p->write = network_write_write_chunkset;
46038 -}
46039  #endif
46040 --- ../lighttpd-1.4.11/src/network_writev.c     2006-02-15 01:02:36.000000000 +0200
46041 +++ lighttpd-1.4.12/src/network_writev.c        2006-07-18 13:03:40.000000000 +0300
46042 @@ -28,10 +28,10 @@
46043  
46044  #ifndef UIO_MAXIOV
46045  # if defined(__FreeBSD__) || defined(__APPLE__) || defined(__NetBSD__)
46046 -/* FreeBSD 4.7 defines it in sys/uio.h only if _KERNEL is specified */ 
46047 +/* FreeBSD 4.7 defines it in sys/uio.h only if _KERNEL is specified */
46048  #  define UIO_MAXIOV 1024
46049  # elif defined(__sgi)
46050 -/* IRIX 6.5 has sysconf(_SC_IOV_MAX) which might return 512 or bigger */ 
46051 +/* IRIX 6.5 has sysconf(_SC_IOV_MAX) which might return 512 or bigger */
46052  #  define UIO_MAXIOV 512
46053  # elif defined(__sun)
46054  /* Solaris (and SunOS?) defines IOV_MAX instead */
46055 @@ -51,105 +51,121 @@
46056  #define LOCAL_BUFFERING 1
46057  #endif
46058  
46059 -int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq) {
46060 -       chunk *c;
46061 +NETWORK_BACKEND_WRITE_CHUNK(writev_mem) {
46062 +       char * offset;
46063 +       size_t toSend;
46064 +       ssize_t r;
46065 +
46066 +       size_t num_chunks, i;
46067 +       struct iovec chunks[UIO_MAXIOV];
46068 +       chunk *tc; /* transfer chunks */
46069 +       size_t num_bytes = 0;
46070 +
46071 +       /* we can't send more then SSIZE_MAX bytes in one chunk */
46072 +
46073 +       /* build writev list
46074 +        *
46075 +        * 1. limit: num_chunks < UIO_MAXIOV
46076 +        * 2. limit: num_bytes < SSIZE_MAX
46077 +        */
46078 +       for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
46079 +
46080 +       for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
46081 +               if (tc->mem->used == 0) {
46082 +                       chunks[i].iov_base = tc->mem->ptr;
46083 +                       chunks[i].iov_len  = 0;
46084 +               } else {
46085 +                       offset = tc->mem->ptr + tc->offset;
46086 +                       toSend = tc->mem->used - 1 - tc->offset;
46087 +
46088 +                       chunks[i].iov_base = offset;
46089 +
46090 +                       /* protect the return value of writev() */
46091 +                       if (toSend > SSIZE_MAX ||
46092 +                           num_bytes + toSend > SSIZE_MAX) {
46093 +                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
46094 +
46095 +                               num_chunks = i + 1;
46096 +                               break;
46097 +                       } else {
46098 +                               chunks[i].iov_len = toSend;
46099 +                       }
46100 +
46101 +                       num_bytes += toSend;
46102 +               }
46103 +       }
46104 +
46105 +       if ((r = writev(sock->fd, chunks, num_chunks)) < 0) {
46106 +               switch (errno) {
46107 +               case EAGAIN:
46108 +                       return NETWORK_STATUS_WAIT_FOR_EVENT;
46109 +               case EINTR:
46110 +                       return NETWORK_STATUS_INTERRUPTED;
46111 +               case EPIPE:
46112 +               case ECONNRESET:
46113 +                       return NETWORK_STATUS_CONNECTION_CLOSE;
46114 +               default:
46115 +                       log_error_write(srv, __FILE__, __LINE__, "ssd",
46116 +                                       "writev failed:", strerror(errno), sock->fd);
46117 +
46118 +                       return NETWORK_STATUS_FATAL_ERROR;
46119 +               }
46120 +       }
46121 +
46122 +       cq->bytes_out += r;
46123 +
46124 +       /* check which chunks have been written */
46125 +
46126 +       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
46127 +               if (r >= (ssize_t)chunks[i].iov_len) {
46128 +                       /* written */
46129 +                       r -= chunks[i].iov_len;
46130 +                       tc->offset += chunks[i].iov_len;
46131 +               } else {
46132 +                       /* partially written */
46133 +
46134 +                       tc->offset += r;
46135 +
46136 +                       return NETWORK_STATUS_WAIT_FOR_EVENT;
46137 +               }
46138 +       }
46139 +
46140 +       /* all chunks have been pushed out */
46141 +       return NETWORK_STATUS_SUCCESS;
46142 +}
46143 +
46144 +NETWORK_BACKEND_WRITE(writev) {
46145 +       chunk *c, *tc;
46146         size_t chunks_written = 0;
46147 -       
46148 +
46149         for(c = cq->first; c; c = c->next) {
46150                 int chunk_finished = 0;
46151 -               
46152 +               network_status_t ret;
46153 +
46154                 switch(c->type) {
46155 -               case MEM_CHUNK: {
46156 -                       char * offset;
46157 -                       size_t toSend;
46158 -                       ssize_t r;
46159 -                       
46160 -                       size_t num_chunks, i;
46161 -                       struct iovec chunks[UIO_MAXIOV];
46162 -                       chunk *tc;
46163 -                       size_t num_bytes = 0;
46164 -                       
46165 -                       /* we can't send more then SSIZE_MAX bytes in one chunk */
46166 -                       
46167 -                       /* build writev list 
46168 -                        * 
46169 -                        * 1. limit: num_chunks < UIO_MAXIOV
46170 -                        * 2. limit: num_bytes < SSIZE_MAX
46171 -                        */
46172 -                       for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
46173 -                       
46174 -                       for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
46175 -                               if (tc->mem->used == 0) {
46176 -                                       chunks[i].iov_base = tc->mem->ptr;
46177 -                                       chunks[i].iov_len  = 0;
46178 -                               } else {
46179 -                                       offset = tc->mem->ptr + tc->offset;
46180 -                                       toSend = tc->mem->used - 1 - tc->offset;
46181 -                               
46182 -                                       chunks[i].iov_base = offset;
46183 -                                       
46184 -                                       /* protect the return value of writev() */
46185 -                                       if (toSend > SSIZE_MAX ||
46186 -                                           num_bytes + toSend > SSIZE_MAX) {
46187 -                                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
46188 -                                               
46189 -                                               num_chunks = i + 1;
46190 -                                               break;
46191 -                                       } else {
46192 -                                               chunks[i].iov_len = toSend;
46193 -                                       }
46194 -                                       
46195 -                                       num_bytes += toSend;
46196 -                               }
46197 -                       }
46198 -                       
46199 -                       if ((r = writev(fd, chunks, num_chunks)) < 0) {
46200 -                               switch (errno) {
46201 -                               case EAGAIN:
46202 -                               case EINTR:
46203 -                                       r = 0;
46204 -                                       break;
46205 -                               case EPIPE:
46206 -                               case ECONNRESET:
46207 -                                       return -2;
46208 -                               default:
46209 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
46210 -                                                       "writev failed:", strerror(errno), fd);
46211 -                               
46212 -                                       return -1;
46213 -                               }
46214 -                       }
46215 -                       
46216 -                       cq->bytes_out += r;
46217 +               case MEM_CHUNK:
46218 +                       ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
46219  
46220 -                       /* check which chunks have been written */
46221 -                       
46222 -                       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
46223 -                               if (r >= (ssize_t)chunks[i].iov_len) {
46224 -                                       /* written */
46225 -                                       r -= chunks[i].iov_len;
46226 -                                       tc->offset += chunks[i].iov_len;
46227 -                                       
46228 +                       /* check which chunks are finished now */
46229 +                       for (tc = c; tc; tc = tc->next) {
46230 +                               /* finished the chunk */
46231 +                               if (tc->offset == tc->mem->used - 1) {
46232 +                                       /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
46233                                         if (chunk_finished) {
46234 -                                               /* skip the chunks from further touches */
46235 -                                               chunks_written++;
46236                                                 c = c->next;
46237                                         } else {
46238 -                                               /* chunks_written + c = c->next is done in the for()*/
46239 -                                               chunk_finished++;
46240 +                                               chunk_finished = 1;
46241                                         }
46242                                 } else {
46243 -                                       /* partially written */
46244 -                                       
46245 -                                       tc->offset += r;
46246 -                                       chunk_finished = 0;
46247 -
46248                                         break;
46249                                 }
46250                         }
46251 -                       
46252 +
46253 +                       if (ret != NETWORK_STATUS_SUCCESS) {
46254 +                               return ret;
46255 +                       }
46256 +
46257                         break;
46258 -               }
46259                 case FILE_CHUNK: {
46260                         ssize_t r;
46261                         off_t abs_offset;
46262 @@ -159,26 +175,26 @@
46263  #define KByte * 1024
46264  #define MByte * 1024 KByte
46265  #define GByte * 1024 MByte
46266 -                       const off_t we_want_to_mmap = 512 KByte; 
46267 +                       const off_t we_want_to_mmap = 512 KByte;
46268                         char *start = NULL;
46269  
46270                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
46271                                 log_error_write(srv, __FILE__, __LINE__, "sb",
46272                                                 strerror(errno), c->file.name);
46273 -                               return -1;
46274 +                               return NETWORK_STATUS_FATAL_ERROR;
46275                         }
46276  
46277                         abs_offset = c->file.start + c->offset;
46278 -                       
46279 +
46280                         if (abs_offset > sce->st.st_size) {
46281 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
46282 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
46283                                                 "file was shrinked:", c->file.name);
46284 -                               
46285 -                               return -1;
46286 +
46287 +                               return NETWORK_STATUS_FATAL_ERROR;
46288                         }
46289  
46290 -                       /* mmap the buffer 
46291 -                        * - first mmap 
46292 +                       /* mmap the buffer
46293 +                        * - first mmap
46294                          * - new mmap as the we are at the end of the last one */
46295                         if (c->file.mmap.start == MAP_FAILED ||
46296                             abs_offset == (off_t)(c->file.mmap.offset + c->file.mmap.length)) {
46297 @@ -188,7 +204,7 @@
46298                                  * adaptive mem-mapping
46299                                  *   the problem:
46300                                  *     we mmap() the whole file. If someone has alot large files and 32bit
46301 -                                *     machine the virtual address area will be unrun and we will have a failing 
46302 +                                *     machine the virtual address area will be unrun and we will have a failing
46303                                  *     mmap() call.
46304                                  *   solution:
46305                                  *     only mmap 16M in one chunk and move the window as soon as we have finished
46306 @@ -234,8 +250,8 @@
46307                                 if (-1 == c->file.fd) {  /* open the file if not already open */
46308                                         if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
46309                                                 log_error_write(srv, __FILE__, __LINE__, "sbs", "open failed for:", c->file.name, strerror(errno));
46310 -                               
46311 -                                               return -1;
46312 +
46313 +                                               return NETWORK_STATUS_FATAL_ERROR;
46314                                         }
46315  #ifdef FD_CLOEXEC
46316                                         fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
46317 @@ -245,10 +261,10 @@
46318                                 if (MAP_FAILED == (c->file.mmap.start = mmap(0, to_mmap, PROT_READ, MAP_SHARED, c->file.fd, c->file.mmap.offset))) {
46319                                         /* close it here, otherwise we'd have to set FD_CLOEXEC */
46320  
46321 -                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:", 
46322 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:",
46323                                                         strerror(errno), c->file.name, c->file.fd);
46324  
46325 -                                       return -1;
46326 +                                       return NETWORK_STATUS_FATAL_ERROR;
46327                                 }
46328  
46329                                 c->file.mmap.length = to_mmap;
46330 @@ -258,7 +274,7 @@
46331  #ifdef HAVE_MADVISE
46332                                 /* don't advise files < 64Kb */
46333                                 if (c->file.mmap.length > (64 KByte)) {
46334 -                                       /* darwin 7 is returning EINVAL all the time and I don't know how to 
46335 +                                       /* darwin 7 is returning EINVAL all the time and I don't know how to
46336                                          * detect this at runtime.i
46337                                          *
46338                                          * ignore the return value for now */
46339 @@ -274,12 +290,12 @@
46340                         toSend = (c->file.mmap.offset + c->file.mmap.length) - (abs_offset);
46341  
46342                         if (toSend < 0) {
46343 -                               log_error_write(srv, __FILE__, __LINE__, "soooo", 
46344 +                               log_error_write(srv, __FILE__, __LINE__, "soooo",
46345                                                 "toSend is negative:",
46346                                                 toSend,
46347                                                 c->file.mmap.length,
46348                                                 abs_offset,
46349 -                                               c->file.mmap.offset); 
46350 +                                               c->file.mmap.offset);
46351                                 assert(toSend < 0);
46352                         }
46353  
46354 @@ -289,7 +305,7 @@
46355                         start = c->file.mmap.start;
46356  #endif
46357  
46358 -                       if ((r = write(fd, start + (abs_offset - c->file.mmap.offset), toSend)) < 0) {
46359 +                       if ((r = write(sock->fd, start + (abs_offset - c->file.mmap.offset), toSend)) < 0) {
46360                                 switch (errno) {
46361                                 case EAGAIN:
46362                                 case EINTR:
46363 @@ -297,18 +313,18 @@
46364                                         break;
46365                                 case EPIPE:
46366                                 case ECONNRESET:
46367 -                                       return -2;
46368 +                                       return NETWORK_STATUS_CONNECTION_CLOSE;
46369                                 default:
46370 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
46371 -                                                       "write failed:", strerror(errno), fd);
46372 -                                       
46373 -                                       return -1;
46374 +                                       log_error_write(srv, __FILE__, __LINE__, "ssd",
46375 +                                                       "write failed:", strerror(errno), sock->fd);
46376 +
46377 +                                       return NETWORK_STATUS_FATAL_ERROR;
46378                                 }
46379                         }
46380 -                       
46381 +
46382                         c->offset += r;
46383                         cq->bytes_out += r;
46384 -                       
46385 +
46386                         if (c->offset == c->file.length) {
46387                                 chunk_finished = 1;
46388  
46389 @@ -318,26 +334,26 @@
46390                                         c->file.mmap.start = MAP_FAILED;
46391                                 }
46392                         }
46393 -                       
46394 +
46395                         break;
46396                 }
46397                 default:
46398 -                       
46399 +
46400                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
46401 -                       
46402 -                       return -1;
46403 +
46404 +                       return NETWORK_STATUS_FATAL_ERROR;
46405                 }
46406 -               
46407 +
46408                 if (!chunk_finished) {
46409                         /* not finished yet */
46410 -                       
46411 +
46412                         break;
46413                 }
46414 -               
46415 +
46416                 chunks_written++;
46417         }
46418  
46419 -       return chunks_written;
46420 +       return NETWORK_STATUS_SUCCESS;
46421  }
46422  
46423  #endif
46424 --- ../lighttpd-1.4.11/src/plugin.c     2006-02-08 14:00:54.000000000 +0200
46425 +++ lighttpd-1.4.12/src/plugin.c        2006-07-16 00:26:04.000000000 +0300
46426 @@ -13,27 +13,27 @@
46427  #include <valgrind/valgrind.h>
46428  #endif
46429  
46430 -#ifndef __WIN32
46431 +#ifndef _WIN32
46432  #include <dlfcn.h>
46433  #endif
46434  /*
46435 - * 
46436 + *
46437   * if you change this enum to add a new callback, be sure
46438   * - that PLUGIN_FUNC_SIZEOF is the last entry
46439   * - that you add PLUGIN_TO_SLOT twice:
46440 - *   1. as callback-dispatcher 
46441 + *   1. as callback-dispatcher
46442   *   2. in plugins_call_init()
46443 - * 
46444 + *
46445   */
46446  
46447  typedef struct {
46448         PLUGIN_DATA;
46449  } plugin_data;
46450  
46451 -typedef enum { 
46452 +typedef enum {
46453         PLUGIN_FUNC_UNSET,
46454 -               PLUGIN_FUNC_HANDLE_URI_CLEAN, 
46455 -               PLUGIN_FUNC_HANDLE_URI_RAW, 
46456 +               PLUGIN_FUNC_HANDLE_URI_CLEAN,
46457 +               PLUGIN_FUNC_HANDLE_URI_RAW,
46458                 PLUGIN_FUNC_HANDLE_REQUEST_DONE,
46459                 PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE,
46460                 PLUGIN_FUNC_HANDLE_TRIGGER,
46461 @@ -44,38 +44,42 @@
46462                 PLUGIN_FUNC_HANDLE_DOCROOT,
46463                 PLUGIN_FUNC_HANDLE_PHYSICAL,
46464                 PLUGIN_FUNC_CONNECTION_RESET,
46465 -               PLUGIN_FUNC_INIT, 
46466 +               PLUGIN_FUNC_INIT,
46467                 PLUGIN_FUNC_CLEANUP,
46468                 PLUGIN_FUNC_SET_DEFAULTS,
46469 -               
46470 +
46471                 PLUGIN_FUNC_SIZEOF
46472  } plugin_t;
46473  
46474  static plugin *plugin_init(void) {
46475         plugin *p;
46476 -       
46477 +
46478         p = calloc(1, sizeof(*p));
46479 -       
46480 +
46481 +       p->required_plugins = array_init();
46482 +
46483         return p;
46484  }
46485  
46486  static void plugin_free(plugin *p) {
46487         int use_dlclose = 1;
46488         if (p->name) buffer_free(p->name);
46489 +
46490 +       array_free(p->required_plugins);
46491  #ifdef HAVE_VALGRIND_VALGRIND_H
46492         /*if (RUNNING_ON_VALGRIND) use_dlclose = 0;*/
46493  #endif
46494  
46495  #ifndef LIGHTTPD_STATIC
46496 -       if (use_dlclose && p->lib) {    
46497 -#ifdef __WIN32
46498 +       if (use_dlclose && p->lib) {
46499 +#ifdef _WIN32
46500                 FreeLibrary(p->lib);
46501  #else
46502                 dlclose(p->lib);
46503  #endif
46504         }
46505  #endif
46506 -               
46507 +
46508         free(p);
46509  }
46510  
46511 @@ -89,17 +93,17 @@
46512                 srv->plugins.size += 4;
46513                 srv->plugins.ptr   = realloc(srv->plugins.ptr, srv->plugins.size * sizeof(*ps));
46514         }
46515 -       
46516 +
46517         ps = srv->plugins.ptr;
46518         ps[srv->plugins.used++] = p;
46519 -       
46520 +
46521         return 0;
46522  }
46523  
46524  /**
46525 - * 
46526 - * 
46527 - * 
46528 + *
46529 + *
46530 + *
46531   */
46532  
46533  #ifdef LIGHTTPD_STATIC
46534 @@ -121,30 +125,35 @@
46535  #else
46536  int plugins_load(server *srv) {
46537         plugin *p;
46538 +#ifdef _WIN32
46539 +    FARPROC init;
46540 +#else
46541         int (*init)(plugin *pl);
46542 +#endif
46543 +
46544         const char *error;
46545 -       size_t i;
46546 -       
46547 +       size_t i, j, k;
46548 +
46549         for (i = 0; i < srv->srvconf.modules->used; i++) {
46550                 data_string *d = (data_string *)srv->srvconf.modules->data[i];
46551                 char *modules = d->value->ptr;
46552 -       
46553 +
46554                 buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.modules_dir);
46555  
46556                 buffer_append_string(srv->tmp_buf, "/");
46557                 buffer_append_string(srv->tmp_buf, modules);
46558 -#if defined(__WIN32) || defined(__CYGWIN__)
46559 +#if defined(_WIN32) || defined(__CYGWIN__)
46560                 buffer_append_string(srv->tmp_buf, ".dll");
46561  #else
46562                 buffer_append_string(srv->tmp_buf, ".so");
46563  #endif
46564 -       
46565 +
46566                 p = plugin_init();
46567 -#ifdef __WIN32
46568 +#ifdef _WIN32
46569                 if (NULL == (p->lib = LoadLibrary(srv->tmp_buf->ptr))) {
46570                         LPVOID lpMsgBuf;
46571                         FormatMessage(
46572 -                               FORMAT_MESSAGE_ALLOCATE_BUFFER | 
46573 +                               FORMAT_MESSAGE_ALLOCATE_BUFFER |
46574                                 FORMAT_MESSAGE_FROM_SYSTEM,
46575                                 NULL,
46576                                 GetLastError(),
46577 @@ -152,36 +161,36 @@
46578                                 (LPTSTR) &lpMsgBuf,
46579                                 0, NULL );
46580  
46581 -                       log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed", 
46582 +                       log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
46583                                         lpMsgBuf, srv->tmp_buf);
46584 -                       
46585 +
46586                         plugin_free(p);
46587 -                       
46588 +
46589                         return -1;
46590  
46591                 }
46592 -#else  
46593 +#else
46594                 if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_LAZY))) {
46595 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:", 
46596 +                       log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:",
46597                                         srv->tmp_buf, dlerror());
46598 -                       
46599 +
46600                         plugin_free(p);
46601 -                       
46602 +
46603                         return -1;
46604                 }
46605 -               
46606 +
46607  #endif
46608                 buffer_reset(srv->tmp_buf);
46609                 buffer_copy_string(srv->tmp_buf, modules);
46610                 buffer_append_string(srv->tmp_buf, "_plugin_init");
46611  
46612 -#ifdef __WIN32
46613 +#ifdef _WIN32
46614                 init = GetProcAddress(p->lib, srv->tmp_buf->ptr);
46615  
46616                 if (init == NULL)  {
46617                         LPVOID lpMsgBuf;
46618                         FormatMessage(
46619 -                               FORMAT_MESSAGE_ALLOCATE_BUFFER | 
46620 +                               FORMAT_MESSAGE_ALLOCATE_BUFFER |
46621                                 FORMAT_MESSAGE_FROM_SYSTEM,
46622                                 NULL,
46623                                 GetLastError(),
46624 @@ -190,7 +199,7 @@
46625                                 0, NULL );
46626  
46627                         log_error_write(srv, __FILE__, __LINE__, "sbs", "getprocaddress failed:", srv->tmp_buf, lpMsgBuf);
46628 -                       
46629 +
46630                         plugin_free(p);
46631                         return -1;
46632                 }
46633 @@ -203,24 +212,43 @@
46634  #endif
46635                 if ((error = dlerror()) != NULL)  {
46636                         log_error_write(srv, __FILE__, __LINE__, "s", error);
46637 -                       
46638 +
46639                         plugin_free(p);
46640                         return -1;
46641                 }
46642 -       
46643 +
46644  #endif
46645                 if ((*init)(p)) {
46646                         log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin init failed" );
46647 -                       
46648 +
46649                         plugin_free(p);
46650                         return -1;
46651                 }
46652  #if 0
46653                 log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin loaded" );
46654  #endif
46655 +               /* check if the required plugin is loaded */
46656 +               for (k = 0; k < p->required_plugins->used; k++) {
46657 +                       data_string *req = (data_string *)p->required_plugins->data[k];
46658 +
46659 +                       for (j = 0; j < i; j++) {
46660 +                               data_string *mod = (data_string *)srv->srvconf.modules->data[j];
46661 +
46662 +                               if (buffer_is_equal(req->value, mod->value)) break;
46663 +                       }
46664 +
46665 +                       if (j == i) {
46666 +                               /* not found */
46667 +                               log_error_write(srv, __FILE__, __LINE__, "ssbs", modules, "failed to load. required plugin", req->value, "was not loaded" );
46668 +
46669 +                               plugin_free(p);
46670 +                       
46671 +                               return -1;
46672 +                       }
46673 +               }
46674                 plugins_register(srv, p);
46675         }
46676 -       
46677 +
46678         return 0;
46679  }
46680  #endif
46681 @@ -253,8 +281,8 @@
46682         }
46683  
46684  /**
46685 - * plugins that use 
46686 - * 
46687 + * plugins that use
46688 + *
46689   * - server *srv
46690   * - connection *con
46691   * - void *p_d (plugin_data *)
46692 @@ -301,12 +329,12 @@
46693         }
46694  
46695  /**
46696 - * plugins that use 
46697 - * 
46698 + * plugins that use
46699 + *
46700   * - server *srv
46701   * - void *p_d (plugin_data *)
46702   */
46703 -                                                                       
46704 +
46705  PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger)
46706  PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup)
46707  PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup)
46708 @@ -314,18 +342,18 @@
46709  
46710  #undef PLUGIN_TO_SLOT
46711  
46712 -#if 0                                                                  
46713 +#if 0
46714  /**
46715 - * 
46716 + *
46717   * special handler
46718 - * 
46719 + *
46720   */
46721  handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) {
46722         size_t i;
46723         plugin **ps;
46724 -       
46725 +
46726         ps = srv->plugins.ptr;
46727 -       
46728 +
46729         for (i = 0; i < srv->plugins.used; i++) {
46730                 plugin *p = ps[i];
46731                 if (p->handle_fdevent) {
46732 @@ -344,34 +372,34 @@
46733                         }
46734                 }
46735         }
46736 -       
46737 +
46738         return HANDLER_GO_ON;
46739  }
46740  #endif
46741  /**
46742 - * 
46743 + *
46744   * - call init function of all plugins to init the plugin-internals
46745   * - added each plugin that supports has callback to the corresponding slot
46746 - * 
46747 + *
46748   * - is only called once.
46749   */
46750  
46751  handler_t plugins_call_init(server *srv) {
46752         size_t i;
46753         plugin **ps;
46754 -       
46755 +
46756         ps = srv->plugins.ptr;
46757 -       
46758 +
46759         /* fill slots */
46760 -       
46761 +
46762         srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps));
46763 -       
46764 +
46765         for (i = 0; i < srv->plugins.used; i++) {
46766                 size_t j;
46767                 /* check which calls are supported */
46768 -               
46769 +
46770                 plugin *p = ps[i];
46771 -               
46772 +
46773  #define PLUGIN_TO_SLOT(x, y) \
46774         if (p->y) { \
46775                 plugin **slot = ((plugin ***)(srv->plugin_slots))[x]; \
46776 @@ -384,11 +412,11 @@
46777                         slot[j] = p;\
46778                         break;\
46779                 }\
46780 -       } 
46781 -               
46782 -               
46783 -               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean); 
46784 -               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw); 
46785 +       }
46786 +
46787 +
46788 +               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean);
46789 +               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw);
46790                 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done);
46791                 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close);
46792                 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger);
46793 @@ -402,19 +430,19 @@
46794                 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup);
46795                 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults);
46796  #undef PLUGIN_TO_SLOT
46797 -               
46798 +
46799                 if (p->init) {
46800                         if (NULL == (p->data = p->init())) {
46801 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
46802 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
46803                                                 "plugin-init failed for module", p->name);
46804                                 return HANDLER_ERROR;
46805                         }
46806 -                       
46807 +
46808                         /* used for con->mode, DIRECT == 0, plugins above that */
46809                         ((plugin_data *)(p->data))->id = i + 1;
46810 -                       
46811 +
46812                         if (p->version != LIGHTTPD_VERSION_ID) {
46813 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
46814 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
46815                                                 "plugin-version doesn't match lighttpd-version for", p->name);
46816                                 return HANDLER_ERROR;
46817                         }
46818 @@ -422,29 +450,46 @@
46819                         p->data = NULL;
46820                 }
46821         }
46822 -       
46823 +
46824         return HANDLER_GO_ON;
46825  }
46826  
46827 +/**
46828 + * get the config-storage of the named plugin 
46829 + */
46830 +void *plugin_get_config(server *srv, const char *name) {
46831 +       size_t i;
46832 +
46833 +       for (i = 0; i < srv->plugins.used; i++) {
46834 +               plugin *p = ((plugin **)srv->plugins.ptr)[i];
46835 +
46836 +               if (buffer_is_equal_string(p->name, name, strlen(name))) {
46837 +                       return p->data;
46838 +               }
46839 +       }
46840 +
46841 +       return NULL;
46842 +}
46843 +
46844  void plugins_free(server *srv) {
46845         size_t i;
46846         plugins_call_cleanup(srv);
46847 -       
46848 +
46849         for (i = 0; i < srv->plugins.used; i++) {
46850                 plugin *p = ((plugin **)srv->plugins.ptr)[i];
46851 -               
46852 +
46853                 plugin_free(p);
46854         }
46855 -       
46856 +
46857         for (i = 0; srv->plugin_slots && i < PLUGIN_FUNC_SIZEOF; i++) {
46858                 plugin **slot = ((plugin ***)(srv->plugin_slots))[i];
46859 -               
46860 +
46861                 if (slot) free(slot);
46862         }
46863 -       
46864 +
46865         free(srv->plugin_slots);
46866         srv->plugin_slots = NULL;
46867 -       
46868 +
46869         free(srv->plugins.ptr);
46870         srv->plugins.ptr = NULL;
46871         srv->plugins.used = 0;
46872 --- ../lighttpd-1.4.11/src/plugin.h     2005-08-15 12:28:56.000000000 +0300
46873 +++ lighttpd-1.4.12/src/plugin.h        2006-07-16 00:26:04.000000000 +0300
46874 @@ -12,6 +12,12 @@
46875  
46876  #define INIT_FUNC(x) \
46877                 static void *x()
46878 +/*
46879 + * The PATCH_OPTION() macro is used in the patch_connection() functions
46880 + * of the modules to update the config object for the current request.
46881 + */
46882 +#define PATCH_OPTION(x) \
46883 +               p->conf.x = s->x
46884  
46885  #define FREE_FUNC          SERVER_FUNC
46886  #define TRIGGER_FUNC       SERVER_FUNC
46887 @@ -25,19 +31,19 @@
46888  #define URIHANDLER_FUNC    CONNECTION_FUNC
46889  
46890  #define PLUGIN_DATA        size_t id
46891 -                                                                                                                                               
46892 +
46893  typedef struct {
46894         size_t version;
46895 -       
46896 +
46897         buffer *name; /* name of the plugin */
46898 -       
46899 +
46900         void *(* init)                       ();
46901         handler_t (* set_defaults)           (server *srv, void *p_d);
46902         handler_t (* cleanup)                (server *srv, void *p_d);
46903                                                                                            /* is called ... */
46904         handler_t (* handle_trigger)         (server *srv, void *p_d);                     /* once a second */
46905         handler_t (* handle_sighup)          (server *srv, void *p_d);                     /* at a signup */
46906 -       
46907 +
46908         handler_t (* handle_uri_raw)         (server *srv, connection *con, void *p_d);    /* after uri_raw is set */
46909         handler_t (* handle_uri_clean)       (server *srv, connection *con, void *p_d);    /* after uri is set */
46910         handler_t (* handle_docroot)         (server *srv, connection *con, void *p_d);    /* getting the document-root */
46911 @@ -45,20 +51,22 @@
46912         handler_t (* handle_request_done)    (server *srv, connection *con, void *p_d);    /* at the end of a request */
46913         handler_t (* handle_connection_close)(server *srv, connection *con, void *p_d);    /* at the end of a connection */
46914         handler_t (* handle_joblist)         (server *srv, connection *con, void *p_d);    /* after all events are handled */
46915 -       
46916 -       
46917 -       
46918 -       handler_t (* handle_subrequest_start)(server *srv, connection *con, void *p_d);   
46919 -       
46920 -                                                                                          /* when a handler for the request 
46921 +
46922 +
46923 +
46924 +       handler_t (* handle_subrequest_start)(server *srv, connection *con, void *p_d);
46925 +
46926 +                                                                                          /* when a handler for the request
46927                                                                                             * has to be found
46928                                                                                             */
46929         handler_t (* handle_subrequest)      (server *srv, connection *con, void *p_d);    /* */
46930         handler_t (* connection_reset)       (server *srv, connection *con, void *p_d);    /* */
46931         void *data;
46932 -       
46933 +
46934         /* dlopen handle */
46935         void *lib;
46936 +
46937 +       array *required_plugins;
46938  } plugin;
46939  
46940  int plugins_load(server *srv);
46941 @@ -88,5 +96,8 @@
46942  int config_patch_connection(server *srv, connection *con, comp_key_t comp);
46943  int config_check_cond(server *srv, connection *con, data_config *dc);
46944  int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n);
46945 +int config_exec_pcre_keyvalue_buffer(connection *con, pcre_keyvalue_buffer *kvb, data_config *context, buffer *match_buf, buffer *result);
46946 +
46947 +void *plugin_get_config(server *srv, const char *name);
46948  
46949  #endif
46950 --- ../lighttpd-1.4.11/src/proc_open.c  2005-08-11 01:26:39.000000000 +0300
46951 +++ lighttpd-1.4.12/src/proc_open.c     2006-07-16 00:26:04.000000000 +0300
46952 @@ -13,13 +13,13 @@
46953  #endif
46954  
46955  
46956 -#ifdef WIN32
46957 +#ifdef _WIN32
46958  /* {{{ win32 stuff */
46959  # define SHELLENV "ComSpec"
46960  # define SECURITY_DC , SECURITY_ATTRIBUTES *security
46961  # define SECURITY_CC , security
46962  # define pipe(pair) (CreatePipe(&pair[0], &pair[1], security, 2048L) ? 0 : -1)
46963 -static inline HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig)
46964 +static HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig)
46965  {
46966         HANDLE copy, self = GetCurrentProcess();
46967  
46968 @@ -148,11 +148,14 @@
46969         STARTUPINFO si;
46970         BOOL procok;
46971         SECURITY_ATTRIBUTES security;
46972 -       const char *shell;
46973 +       const char *shell = NULL;
46974 +       const char *windir = NULL;
46975         buffer *cmdline;
46976  
46977 -       if (NULL == (shell = getenv(SHELLENV))) {
46978 -               fprintf(stderr, "env %s is required", SHELLENV);
46979 +       if (NULL == (shell = getenv(SHELLENV)) &&
46980 +                       NULL == (windir = getenv("SystemRoot")) &&
46981 +                       NULL == (windir = getenv("windir"))) {
46982 +               fprintf(stderr, "One of %s,%%SystemRoot,%%windir is required", SHELLENV);
46983                 return -1;
46984         }
46985  
46986 @@ -177,17 +180,23 @@
46987         memset(&pi, 0, sizeof(pi));
46988  
46989         cmdline = buffer_init();
46990 -       buffer_append_string(cmdline, shell);
46991 +       if (shell) {
46992 +               buffer_append_string(cmdline, shell);
46993 +       } else {
46994 +               buffer_append_string(cmdline, windir);
46995 +               buffer_append_string(cmdline, "\\system32\\cmd.exe");
46996 +       }
46997         buffer_append_string_len(cmdline, CONST_STR_LEN(" /c "));
46998         buffer_append_string(cmdline, command);
46999         procok = CreateProcess(NULL, cmdline->ptr, &security, &security, TRUE,
47000                         NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
47001 -       buffer_free(cmdline);
47002  
47003         if (FALSE == procok) {
47004 -               fprintf(stderr, "failed to CreateProcess");
47005 +               fprintf(stderr, "failed to CreateProcess: %s", cmdline->ptr);
47006 +               buffer_free(cmdline);
47007                 return -1;
47008         }
47009 +       buffer_free(cmdline);
47010  
47011         proc->child = pi.hProcess;
47012         CloseHandle(pi.hThread);
47013 @@ -226,8 +235,7 @@
47014         const char *shell;
47015  
47016         if (NULL == (shell = getenv(SHELLENV))) {
47017 -               fprintf(stderr, "env %s is required", SHELLENV);
47018 -               return -1;
47019 +               shell = "/bin/sh";
47020         }
47021  
47022         if (proc_open_pipes(proc) != 0) {
47023 @@ -262,11 +270,11 @@
47024         }
47025  }
47026  /* }}} */
47027 -#endif /* WIN32 */
47028 +#endif /* _WIN32 */
47029  
47030  /* {{{ proc_read_fd_to_buffer */
47031  static void proc_read_fd_to_buffer(int fd, buffer *b) {
47032 -       ssize_t s;
47033 +       int s; /* win32 has not ssize_t */
47034  
47035         for (;;) {
47036                 buffer_prepare_append(b, 512);
47037 --- ../lighttpd-1.4.11/src/proc_open.h  2005-08-11 01:26:39.000000000 +0300
47038 +++ lighttpd-1.4.12/src/proc_open.h     2006-07-16 00:26:04.000000000 +0300
47039 @@ -1,7 +1,7 @@
47040  
47041  #include "buffer.h"
47042  
47043 -#ifdef WIN32
47044 +#ifdef _WIN32
47045  #include <windows.h>
47046  typedef HANDLE descriptor_t;
47047  typedef HANDLE proc_pid_t;
47048 --- ../lighttpd-1.4.11/src/request.c    2006-03-05 11:58:09.000000000 +0200
47049 +++ lighttpd-1.4.12/src/request.c       2006-07-18 13:03:40.000000000 +0300
47050 @@ -10,15 +10,17 @@
47051  #include "keyvalue.h"
47052  #include "log.h"
47053  
47054 +#include "sys-strings.h"
47055 +
47056  static int request_check_hostname(server *srv, connection *con, buffer *host) {
47057         enum { DOMAINLABEL, TOPLABEL } stage = TOPLABEL;
47058         size_t i;
47059         int label_len = 0;
47060         size_t host_len;
47061         char *colon;
47062 -       int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */ 
47063 +       int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */
47064         int level = 0;
47065 -       
47066 +
47067         UNUSED(srv);
47068         UNUSED(con);
47069  
47070 @@ -32,17 +34,17 @@
47071          *       IPv6address   = "[" ... "]"
47072          *       port          = *digit
47073          */
47074 -       
47075 +
47076         /* no Host: */
47077         if (!host || host->used == 0) return 0;
47078 -       
47079 +
47080         host_len = host->used - 1;
47081 -       
47082 +
47083         /* IPv6 adress */
47084         if (host->ptr[0] == '[') {
47085                 char *c = host->ptr + 1;
47086                 int colon_cnt = 0;
47087 -               
47088 +
47089                 /* check portnumber */
47090                 for (; *c && *c != ']'; c++) {
47091                         if (*c == ':') {
47092 @@ -53,12 +55,12 @@
47093                                 return -1;
47094                         }
47095                 }
47096 -               
47097 +
47098                 /* missing ] */
47099                 if (!*c) {
47100                         return -1;
47101                 }
47102 -               
47103 +
47104                 /* check port */
47105                 if (*(c+1) == ':') {
47106                         for (c += 2; *c; c++) {
47107 @@ -69,39 +71,39 @@
47108                 }
47109                 return 0;
47110         }
47111 -       
47112 +
47113         if (NULL != (colon = memchr(host->ptr, ':', host_len))) {
47114                 char *c = colon + 1;
47115 -               
47116 +
47117                 /* check portnumber */
47118                 for (; *c; c++) {
47119                         if (!light_isdigit(*c)) return -1;
47120                 }
47121 -               
47122 +
47123                 /* remove the port from the host-len */
47124                 host_len = colon - host->ptr;
47125         }
47126 -       
47127 +
47128         /* Host is empty */
47129         if (host_len == 0) return -1;
47130 -       
47131 +
47132         /* scan from the right and skip the \0 */
47133         for (i = host_len - 1; i + 1 > 0; i--) {
47134                 const char c = host->ptr[i];
47135  
47136                 switch (stage) {
47137 -               case TOPLABEL: 
47138 +               case TOPLABEL:
47139                         if (c == '.') {
47140                                 /* only switch stage, if this is not the last character */
47141                                 if (i != host_len - 1) {
47142                                         if (label_len == 0) {
47143                                                 return -1;
47144                                         }
47145 -                                       
47146 +
47147                                         /* check the first character at right of the dot */
47148                                         if (is_ip == 0) {
47149                                                 if (!light_isalpha(host->ptr[i+1])) {
47150 -                                                       return -1; 
47151 +                                                       return -1;
47152                                                 }
47153                                         } else if (!light_isdigit(host->ptr[i+1])) {
47154                                                 is_ip = 0;
47155 @@ -111,9 +113,9 @@
47156                                                 /* just digits */
47157                                                 is_ip = 1;
47158                                         }
47159 -                                               
47160 +
47161                                         stage = DOMAINLABEL;
47162 -                                       
47163 +
47164                                         label_len = 0;
47165                                         level++;
47166                                 } else if (i == 0) {
47167 @@ -135,7 +137,7 @@
47168                                 }
47169                                 label_len++;
47170                         }
47171 -                       
47172 +
47173                         break;
47174                 case DOMAINLABEL:
47175                         if (is_ip == 1) {
47176 @@ -143,7 +145,7 @@
47177                                         if (label_len == 0) {
47178                                                 return -1;
47179                                         }
47180 -                                       
47181 +
47182                                         label_len = 0;
47183                                         level++;
47184                                 } else if (!light_isdigit(c)) {
47185 @@ -156,12 +158,12 @@
47186                                         if (label_len == 0) {
47187                                                 return -1;
47188                                         }
47189 -                                       
47190 +
47191                                         /* c is either - or alphanum here */
47192                                         if ('-' == host->ptr[i+1]) {
47193                                                 return -1;
47194                                         }
47195 -                                       
47196 +
47197                                         label_len = 0;
47198                                         level++;
47199                                 } else if (i == 0) {
47200 @@ -176,20 +178,20 @@
47201                                         label_len++;
47202                                 }
47203                         }
47204 -                       
47205 +
47206                         break;
47207                 }
47208         }
47209 -       
47210 +
47211         /* a IP has to consist of 4 parts */
47212         if (is_ip == 1 && level != 3) {
47213                 return -1;
47214         }
47215 -       
47216 +
47217         if (label_len == 0) {
47218                 return -1;
47219         }
47220 -       
47221 +
47222         return 0;
47223  }
47224  
47225 @@ -201,53 +203,53 @@
47226         char *s;
47227         size_t i;
47228         int state = 0;
47229 -       /*  
47230 -        * parse 
47231 -        * 
47232 +       /*
47233 +        * parse
47234 +        *
47235          * val1, val2, val3, val4
47236 -        * 
47237 +        *
47238          * into a array (more or less a explode() incl. striping of whitespaces
47239          */
47240 -       
47241 +
47242         if (b->used == 0) return 0;
47243 -       
47244 +
47245         s = b->ptr;
47246 -       
47247 +
47248         for (i =0; i < b->used - 1; ) {
47249                 char *start = NULL, *end = NULL;
47250                 data_string *ds;
47251 -               
47252 +
47253                 switch (state) {
47254                 case 0: /* ws */
47255 -                       
47256 +
47257                         /* skip ws */
47258                         for (; (*s == ' ' || *s == '\t') && i < b->used - 1; i++, s++);
47259 -                       
47260 -                       
47261 +
47262 +
47263                         state = 1;
47264                         break;
47265                 case 1: /* value */
47266                         start = s;
47267 -                       
47268 +
47269                         for (; *s != ',' && i < b->used - 1; i++, s++);
47270                         end = s - 1;
47271 -                       
47272 +
47273                         for (; (*end == ' ' || *end == '\t') && end > start; end--);
47274 -                       
47275 +
47276                         if (NULL == (ds = (data_string *)array_get_unused_element(vals, TYPE_STRING))) {
47277                                 ds = data_string_init();
47278                         }
47279  
47280                         buffer_copy_string_len(ds->value, start, end-start+1);
47281                         array_insert_unique(vals, (data_unset *)ds);
47282 -                       
47283 +
47284                         if (*s == ',') {
47285                                 state = 0;
47286                                 i++;
47287                                 s++;
47288                         } else {
47289                                 /* end of string */
47290 -                               
47291 +
47292                                 state = 2;
47293                         }
47294                         break;
47295 @@ -263,7 +265,7 @@
47296         if (c <= 32) return 0;
47297         if (c == 127) return 0;
47298         if (c == 255) return 0;
47299 -       
47300 +
47301         return 1;
47302  }
47303  
47304 @@ -271,28 +273,28 @@
47305         char *uri = NULL, *proto = NULL, *method = NULL, con_length_set;
47306         int is_key = 1, key_len = 0, is_ws_after_key = 0, in_folding;
47307         char *value = NULL, *key = NULL;
47308 -       
47309 +
47310         enum { HTTP_CONNECTION_UNSET, HTTP_CONNECTION_KEEPALIVE, HTTP_CONNECTION_CLOSE } keep_alive_set = HTTP_CONNECTION_UNSET;
47311 -       
47312 +
47313         int line = 0;
47314 -       
47315 +
47316         int request_line_stage = 0;
47317         size_t i, first;
47318 -       
47319 +
47320         int done = 0;
47321 -       
47322 +
47323         data_string *ds = NULL;
47324 -       
47325 -       /* 
47326 -        * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$" 
47327 -        * Option : "^([-a-zA-Z]+): (.+)$"                    
47328 +
47329 +       /*
47330 +        * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$"
47331 +        * Option : "^([-a-zA-Z]+): (.+)$"
47332          * End    : "^$"
47333          */
47334  
47335         if (con->conf.log_request_header) {
47336 -               log_error_write(srv, __FILE__, __LINE__, "sdsdSb", 
47337 -                               "fd:", con->fd, 
47338 -                               "request-len:", con->request.request->used, 
47339 +               log_error_write(srv, __FILE__, __LINE__, "sdsdSb",
47340 +                               "fd:", con->sock->fd,
47341 +                               "request-len:", con->request.request->used,
47342                                 "\n", con->request.request);
47343         }
47344  
47345 @@ -300,13 +302,13 @@
47346             con->request.request->ptr[0] == '\r' &&
47347             con->request.request->ptr[1] == '\n') {
47348                 /* we are in keep-alive and might get \r\n after a previous POST request.*/
47349 -               
47350 +
47351                 buffer_copy_string_len(con->parse_request, con->request.request->ptr + 2, con->request.request->used - 1 - 2);
47352         } else {
47353                 /* fill the local request buffer */
47354                 buffer_copy_string_buffer(con->parse_request, con->request.request);
47355         }
47356 -       
47357 +
47358         keep_alive_set = 0;
47359         con_length_set = 0;
47360  
47361 @@ -318,25 +320,25 @@
47362          * */
47363         for (i = 0, first = 0; i < con->parse_request->used && line == 0; i++) {
47364                 char *cur = con->parse_request->ptr + i;
47365 -               
47366 +
47367                 switch(*cur) {
47368 -               case '\r': 
47369 +               case '\r':
47370                         if (con->parse_request->ptr[i+1] == '\n') {
47371                                 http_method_t r;
47372                                 char *nuri = NULL;
47373                                 size_t j;
47374 -                               
47375 +
47376                                 /* \r\n -> \0\0 */
47377                                 con->parse_request->ptr[i] = '\0';
47378                                 con->parse_request->ptr[i+1] = '\0';
47379 -                               
47380 +
47381                                 buffer_copy_string_len(con->request.request_line, con->parse_request->ptr, i);
47382 -                               
47383 +
47384                                 if (request_line_stage != 2) {
47385                                         con->http_status = 400;
47386                                         con->response.keep_alive = 0;
47387                                         con->keep_alive = 0;
47388 -                                       
47389 +
47390                                         if (srv->srvconf.log_request_header_on_error) {
47391                                                 log_error_write(srv, __FILE__, __LINE__, "s", "incomplete request line -> 400");
47392                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
47393 @@ -345,36 +347,36 @@
47394                                         }
47395                                         return 0;
47396                                 }
47397 -                               
47398 +
47399                                 proto = con->parse_request->ptr + first;
47400 -                               
47401 +
47402                                 *(uri - 1) = '\0';
47403                                 *(proto - 1) = '\0';
47404 -                               
47405 +
47406                                 /* we got the first one :) */
47407                                 if (-1 == (r = get_http_method_key(method))) {
47408                                         con->http_status = 501;
47409                                         con->response.keep_alive = 0;
47410                                         con->keep_alive = 0;
47411 -                                       
47412 +
47413                                         if (srv->srvconf.log_request_header_on_error) {
47414                                                 log_error_write(srv, __FILE__, __LINE__, "s", "unknown http-method -> 501");
47415                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
47416                                                                 "request-header:\n",
47417                                                                 con->request.request);
47418                                         }
47419 -                               
47420 +
47421                                         return 0;
47422                                 }
47423 -                               
47424 +
47425                                 con->request.http_method = r;
47426 -                       
47427 -                               /* 
47428 +
47429 +                               /*
47430                                  * RFC2616 says:
47431                                  *
47432                                  * HTTP-Version   = "HTTP" "/" 1*DIGIT "." 1*DIGIT
47433                                  *
47434 -                                * */   
47435 +                                * */
47436                                 if (0 == strncmp(proto, "HTTP/", sizeof("HTTP/") - 1)) {
47437                                         char * major = proto + sizeof("HTTP/") - 1;
47438                                         char * minor = strchr(major, '.');
47439 @@ -413,10 +415,10 @@
47440                                         }
47441  
47442                                         if (major_num == 1 && minor_num == 1) {
47443 -                                               con->request.http_version = con->conf.allow_http11 ? HTTP_VERSION_1_1 : HTTP_VERSION_1_0;
47444 +                                               con->request.http_version = HTTP_VERSION_1_1;
47445                                         } else if (major_num == 1 && minor_num == 0) {
47446                                                 con->request.http_version = HTTP_VERSION_1_0;
47447 -                                       } else { 
47448 +                                       } else {
47449                                                 con->http_status = 505;
47450  
47451                                                 if (srv->srvconf.log_request_header_on_error) {
47452 @@ -439,30 +441,30 @@
47453                                         }
47454                                         return 0;
47455                                 }
47456 -                               
47457 +
47458                                 if (0 == strncmp(uri, "http://", 7) &&
47459                                     NULL != (nuri = strchr(uri + 7, '/'))) {
47460                                         /* ignore the host-part */
47461 -                                       
47462 +
47463                                         buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
47464                                 } else {
47465                                         /* everything looks good so far */
47466                                         buffer_copy_string_len(con->request.uri, uri, proto - uri - 1);
47467                                 }
47468 -                               
47469 +
47470                                 /* check uri for invalid characters */
47471                                 for (j = 0; j < con->request.uri->used - 1; j++) {
47472                                         if (!request_uri_is_valid_char(con->request.uri->ptr[j])) {
47473                                                 unsigned char buf[2];
47474                                                 con->http_status = 400;
47475                                                 con->keep_alive = 0;
47476 -                                               
47477 +
47478                                                 if (srv->srvconf.log_request_header_on_error) {
47479                                                         buf[0] = con->request.uri->ptr[j];
47480                                                         buf[1] = '\0';
47481 -                                       
47482 +
47483                                                         if (con->request.uri->ptr[j] > 32 &&
47484 -                                                           con->request.uri->ptr[j] != 127) {  
47485 +                                                           con->request.uri->ptr[j] != 127) {
47486                                                                 /* the character is printable -> print it */
47487                                                                 log_error_write(srv, __FILE__, __LINE__, "ss",
47488                                                                                 "invalid character in URI -> 400",
47489 @@ -473,20 +475,20 @@
47490                                                                                 "invalid character in URI -> 400",
47491                                                                                 con->request.uri->ptr[j]);
47492                                                         }
47493 -                                               
47494 +
47495                                                         log_error_write(srv, __FILE__, __LINE__, "Sb",
47496                                                                         "request-header:\n",
47497                                                                         con->request.request);
47498                                                 }
47499 -                                               
47500 +
47501                                                 return 0;
47502                                         }
47503                                 }
47504 -                               
47505 +
47506                                 buffer_copy_string_buffer(con->request.orig_uri, con->request.uri);
47507 -                               
47508 +
47509                                 con->http_status = 0;
47510 -                               
47511 +
47512                                 i++;
47513                                 line++;
47514                                 first = i+1;
47515 @@ -494,14 +496,14 @@
47516                         break;
47517                 case ' ':
47518                         switch(request_line_stage) {
47519 -                       case 0: 
47520 +                       case 0:
47521                                 /* GET|POST|... */
47522 -                               method = con->parse_request->ptr + first; 
47523 +                               method = con->parse_request->ptr + first;
47524                                 first = i + 1;
47525                                 break;
47526                         case 1:
47527                                 /* /foobar/... */
47528 -                               uri = con->parse_request->ptr + first; 
47529 +                               uri = con->parse_request->ptr + first;
47530                                 first = i + 1;
47531                                 break;
47532                         default:
47533 @@ -509,7 +511,7 @@
47534                                 con->http_status = 400;
47535                                 con->response.keep_alive = 0;
47536                                 con->keep_alive = 0;
47537 -                               
47538 +
47539                                 if (srv->srvconf.log_request_header_on_error) {
47540                                         log_error_write(srv, __FILE__, __LINE__, "s", "overlong request line -> 400");
47541                                         log_error_write(srv, __FILE__, __LINE__, "Sb",
47542 @@ -518,12 +520,12 @@
47543                                 }
47544                                 return 0;
47545                         }
47546 -                       
47547 +
47548                         request_line_stage++;
47549                         break;
47550                 }
47551         }
47552 -       
47553 +
47554         in_folding = 0;
47555  
47556         if (con->request.uri->used == 1) {
47557 @@ -540,30 +542,30 @@
47558                 return 0;
47559         }
47560  
47561 -       
47562 +
47563         for (; i < con->parse_request->used && !done; i++) {
47564                 char *cur = con->parse_request->ptr + i;
47565 -               
47566 +
47567                 if (is_key) {
47568                         size_t j;
47569                         int got_colon = 0;
47570 -                       
47571 +
47572                         /**
47573                          * 1*<any CHAR except CTLs or separators>
47574                          * CTLs == 0-31 + 127
47575 -                        * 
47576 +                        *
47577                          */
47578                         switch(*cur) {
47579                         case ':':
47580                                 is_key = 0;
47581 -                               
47582 +
47583                                 value = cur + 1;
47584 -                               
47585 +
47586                                 if (is_ws_after_key == 0) {
47587                                         key_len = i - first;
47588                                 }
47589                                 is_ws_after_key = 0;
47590 -                                       
47591 +
47592                                 break;
47593                         case '(':
47594                         case ')':
47595 @@ -584,8 +586,8 @@
47596                                 con->http_status = 400;
47597                                 con->keep_alive = 0;
47598                                 con->response.keep_alive = 0;
47599 -                               
47600 -                               log_error_write(srv, __FILE__, __LINE__, "sbsds", 
47601 +
47602 +                               log_error_write(srv, __FILE__, __LINE__, "sbsds",
47603                                                 "invalid character in key", con->request.request, cur, *cur, "-> 400");
47604                                 return 0;
47605                         case ' ':
47606 @@ -594,13 +596,13 @@
47607                                         is_key = 0;
47608                                         in_folding = 1;
47609                                         value = cur;
47610 -                                       
47611 +
47612                                         break;
47613                                 }
47614 -                               
47615 -                               
47616 +
47617 +
47618                                 key_len = i - first;
47619 -                               
47620 +
47621                                 /* skip every thing up to the : */
47622                                 for (j = 1; !got_colon; j++) {
47623                                         switch(con->parse_request->ptr[j + i]) {
47624 @@ -610,40 +612,40 @@
47625                                                 continue;
47626                                         case ':':
47627                                                 /* ok, done */
47628 -                                               
47629 +
47630                                                 i += j - 1;
47631                                                 got_colon = 1;
47632 -                                               
47633 +
47634                                                 break;
47635                                         default:
47636                                                 /* error */
47637 -                                               
47638 +
47639                                                 if (srv->srvconf.log_request_header_on_error) {
47640                                                         log_error_write(srv, __FILE__, __LINE__, "s", "WS character in key -> 400");
47641                                                         log_error_write(srv, __FILE__, __LINE__, "Sb",
47642                                                                 "request-header:\n",
47643                                                                 con->request.request);
47644                                                 }
47645 -                                       
47646 +
47647                                                 con->http_status = 400;
47648                                                 con->response.keep_alive = 0;
47649                                                 con->keep_alive = 0;
47650 -                                               
47651 +
47652                                                 return 0;
47653                                         }
47654                                 }
47655 -                               
47656 +
47657                                 break;
47658                         case '\r':
47659                                 if (con->parse_request->ptr[i+1] == '\n' && i == first) {
47660                                         /* End of Header */
47661                                         con->parse_request->ptr[i] = '\0';
47662                                         con->parse_request->ptr[i+1] = '\0';
47663 -                                       
47664 +
47665                                         i++;
47666 -                                       
47667 +
47668                                         done = 1;
47669 -                                       
47670 +
47671                                         break;
47672                                 } else {
47673                                         if (srv->srvconf.log_request_header_on_error) {
47674 @@ -652,7 +654,7 @@
47675                                                         "request-header:\n",
47676                                                         con->request.request);
47677                                         }
47678 -                                       
47679 +
47680                                         con->http_status = 400;
47681                                         con->keep_alive = 0;
47682                                         con->response.keep_alive = 0;
47683 @@ -693,16 +695,16 @@
47684                                 con->http_status = 400;
47685                                 con->keep_alive = 0;
47686                                 con->response.keep_alive = 0;
47687 -                               
47688 +
47689                                 if (srv->srvconf.log_request_header_on_error) {
47690 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsds", 
47691 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsds",
47692                                                 "CTL character in key", con->request.request, cur, *cur, "-> 400");
47693  
47694                                         log_error_write(srv, __FILE__, __LINE__, "Sb",
47695                                                 "request-header:\n",
47696                                                 con->request.request);
47697                                 }
47698 -                               
47699 +
47700                                 return 0;
47701                         default:
47702                                 /* ok */
47703 @@ -710,25 +712,25 @@
47704                         }
47705                 } else {
47706                         switch(*cur) {
47707 -                       case '\r': 
47708 +                       case '\r':
47709                                 if (con->parse_request->ptr[i+1] == '\n') {
47710                                         /* End of Headerline */
47711                                         con->parse_request->ptr[i] = '\0';
47712                                         con->parse_request->ptr[i+1] = '\0';
47713 -                                       
47714 +
47715                                         if (in_folding) {
47716                                                 if (!ds) {
47717                                                         /* 400 */
47718 -                                       
47719 +
47720                                                         if (srv->srvconf.log_request_header_on_error) {
47721                                                                 log_error_write(srv, __FILE__, __LINE__, "s", "WS at the start of first line -> 400");
47722 -                                                       
47723 +
47724                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
47725                                                                         "request-header:\n",
47726                                                                         con->request.request);
47727                                                         }
47728  
47729 -                                       
47730 +
47731                                                         con->http_status = 400;
47732                                                         con->keep_alive = 0;
47733                                                         con->response.keep_alive = 0;
47734 @@ -738,9 +740,9 @@
47735                                         } else {
47736                                                 int s_len;
47737                                                 key = con->parse_request->ptr + first;
47738 -                                       
47739 +
47740                                                 s_len = cur - value;
47741 -                                               
47742 +
47743                                                 if (s_len > 0) {
47744                                                         int cmp = 0;
47745                                                         if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
47746 @@ -748,86 +750,87 @@
47747                                                         }
47748                                                         buffer_copy_string_len(ds->key, key, key_len);
47749                                                         buffer_copy_string_len(ds->value, value, s_len);
47750 -                                                       
47751 -                                                       /* retreive values 
47752 -                                                        * 
47753 -                                                        * 
47754 +
47755 +                                                       /* retreive values
47756 +                                                        *
47757 +                                                        *
47758                                                          * the list of options is sorted to simplify the search
47759                                                          */
47760 -                                                       
47761 +
47762                                                         if (0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Connection")))) {
47763                                                                 array *vals;
47764                                                                 size_t vi;
47765 -                                                               
47766 +
47767                                                                 /* split on , */
47768 -                                                               
47769 +
47770                                                                 vals = srv->split_vals;
47771  
47772                                                                 array_reset(vals);
47773 -                                                               
47774 +
47775                                                                 http_request_split_value(vals, ds->value);
47776 -                                                               
47777 +
47778                                                                 for (vi = 0; vi < vals->used; vi++) {
47779                                                                         data_string *dsv = (data_string *)vals->data[vi];
47780 -                                                                       
47781 +
47782                                                                         if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("keep-alive"))) {
47783                                                                                 keep_alive_set = HTTP_CONNECTION_KEEPALIVE;
47784 -                                                                               
47785 +
47786                                                                                 break;
47787                                                                         } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("close"))) {
47788                                                                                 keep_alive_set = HTTP_CONNECTION_CLOSE;
47789 -                                                                               
47790 +
47791                                                                                 break;
47792                                                                         }
47793                                                                 }
47794 -                                                               
47795 +
47796                                                         } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) {
47797                                                                 char *err;
47798                                                                 unsigned long int r;
47799                                                                 size_t j;
47800 -                                                               
47801 +
47802                                                                 if (con_length_set) {
47803                                                                         con->http_status = 400;
47804                                                                         con->keep_alive = 0;
47805 -                                                                       
47806 +
47807                                                                         if (srv->srvconf.log_request_header_on_error) {
47808 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
47809 +                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
47810                                                                                                 "duplicate Content-Length-header -> 400");
47811                                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
47812                                                                                                 "request-header:\n",
47813                                                                                                 con->request.request);
47814                                                                         }
47815 +                                                                       ds->free((data_unset *) ds);
47816                                                                         return 0;
47817                                                                 }
47818 -                                                               
47819 +
47820                                                                 if (ds->value->used == 0) SEGFAULT();
47821 -                                                               
47822 +
47823                                                                 for (j = 0; j < ds->value->used - 1; j++) {
47824                                                                         char c = ds->value->ptr[j];
47825                                                                         if (!isdigit((unsigned char)c)) {
47826 -                                                                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
47827 +                                                                               log_error_write(srv, __FILE__, __LINE__, "sbs",
47828                                                                                                 "content-length broken:", ds->value, "-> 400");
47829 -                                                                               
47830 +
47831                                                                                 con->http_status = 400;
47832                                                                                 con->keep_alive = 0;
47833 -                                                                               
47834 +
47835                                                                                 array_insert_unique(con->request.headers, (data_unset *)ds);
47836                                                                                 return 0;
47837                                                                         }
47838                                                                 }
47839 -                                                               
47840 +
47841                                                                 r = strtoul(ds->value->ptr, &err, 10);
47842 -                                                               
47843 +
47844                                                                 if (*err == '\0') {
47845                                                                         con_length_set = 1;
47846                                                                         con->request.content_length = r;
47847                                                                 } else {
47848 -                                                                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
47849 +                                                                       log_error_write(srv, __FILE__, __LINE__, "sbs",
47850                                                                                         "content-length broken:", ds->value, "-> 400");
47851 -                                                                       
47852 +
47853                                                                         con->http_status = 400;
47854                                                                         con->keep_alive = 0;
47855 -                                                                       
47856 +
47857                                                                         array_insert_unique(con->request.headers, (data_unset *)ds);
47858                                                                         return 0;
47859                                                                 }
47860 @@ -838,23 +841,24 @@
47861                                                                 } else {
47862                                                                         con->http_status = 400;
47863                                                                         con->keep_alive = 0;
47864 -                                                                       
47865 +
47866                                                                         if (srv->srvconf.log_request_header_on_error) {
47867 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
47868 +                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
47869                                                                                                 "duplicate Content-Type-header -> 400");
47870                                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
47871                                                                                                 "request-header:\n",
47872                                                                                                 con->request.request);
47873                                                                         }
47874 +                                                                       ds->free((data_unset *) ds);
47875                                                                         return 0;
47876                                                                 }
47877                                                         } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Expect")))) {
47878 -                                                               /* HTTP 2616 8.2.3 
47879 +                                                               /* HTTP 2616 8.2.3
47880                                                                  * Expect: 100-continue
47881 -                                                                * 
47882 +                                                                *
47883                                                                  *   -> (10.1.1)  100 (read content, process request, send final status-code)
47884                                                                  *   -> (10.4.18) 417 (close)
47885 -                                                                * 
47886 +                                                                *
47887                                                                  * (not handled at all yet, we always send 417 here)
47888                                                                  *
47889                                                                  * What has to be added ?
47890 @@ -863,10 +867,10 @@
47891                                                                  *    header
47892                                                                  *
47893                                                                  */
47894 -                                                               
47895 +
47896                                                                 con->http_status = 417;
47897                                                                 con->keep_alive = 0;
47898 -                                                               
47899 +
47900                                                                 array_insert_unique(con->request.headers, (data_unset *)ds);
47901                                                                 return 0;
47902                                                         } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Host")))) {
47903 @@ -875,14 +879,15 @@
47904                                                                 } else {
47905                                                                         con->http_status = 400;
47906                                                                         con->keep_alive = 0;
47907 -                                                                       
47908 +
47909                                                                         if (srv->srvconf.log_request_header_on_error) {
47910 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
47911 +                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
47912                                                                                                 "duplicate Host-header -> 400");
47913                                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
47914                                                                                                 "request-header:\n",
47915                                                                                                 con->request.request);
47916                                                                         }
47917 +                                                                       ds->free((data_unset *) ds);
47918                                                                         return 0;
47919                                                                 }
47920                                                         } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) {
47921 @@ -897,14 +902,15 @@
47922                                                                 } else {
47923                                                                         con->http_status = 400;
47924                                                                         con->keep_alive = 0;
47925 -                                                                       
47926 +
47927                                                                         if (srv->srvconf.log_request_header_on_error) {
47928 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
47929 +                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
47930                                                                                                 "duplicate If-Modified-Since header -> 400");
47931                                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
47932                                                                                                 "request-header:\n",
47933                                                                                                 con->request.request);
47934                                                                         }
47935 +                                                                       ds->free((data_unset *) ds);
47936                                                                         return 0;
47937                                                                 }
47938                                                         } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-None-Match")))) {
47939 @@ -914,47 +920,49 @@
47940                                                                 } else {
47941                                                                         con->http_status = 400;
47942                                                                         con->keep_alive = 0;
47943 -                                                                       
47944 +
47945                                                                         if (srv->srvconf.log_request_header_on_error) {
47946 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
47947 +                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
47948                                                                                                 "duplicate If-None-Match-header -> 400");
47949                                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
47950                                                                                                 "request-header:\n",
47951                                                                                                 con->request.request);
47952                                                                         }
47953 +                                                                       ds->free((data_unset *) ds);
47954                                                                         return 0;
47955                                                                 }
47956                                                         } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Range")))) {
47957                                                                 if (!con->request.http_range) {
47958                                                                         /* bytes=.*-.* */
47959 -                                                               
47960 +
47961                                                                         if (0 == strncasecmp(ds->value->ptr, "bytes=", 6) &&
47962                                                                             NULL != strchr(ds->value->ptr+6, '-')) {
47963 -                                                                               
47964 +
47965                                                                                 /* if dup, only the first one will survive */
47966                                                                                 con->request.http_range = ds->value->ptr + 6;
47967                                                                         }
47968                                                                 } else {
47969                                                                         con->http_status = 400;
47970                                                                         con->keep_alive = 0;
47971 -                                                                       
47972 +
47973                                                                         if (srv->srvconf.log_request_header_on_error) {
47974 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
47975 +                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
47976                                                                                                 "duplicate Range-header -> 400");
47977                                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
47978                                                                                                 "request-header:\n",
47979                                                                                                 con->request.request);
47980                                                                         }
47981 +                                                                       ds->free((data_unset *) ds);
47982                                                                         return 0;
47983                                                                 }
47984                                                         }
47985 -                                                       
47986 +
47987                                                         array_insert_unique(con->request.headers, (data_unset *)ds);
47988                                                 } else {
47989                                                         /* empty header-fields are not allowed by HTTP-RFC, we just ignore them */
47990                                                 }
47991                                         }
47992 -                                       
47993 +
47994                                         i++;
47995                                         first = i+1;
47996                                         is_key = 1;
47997 @@ -963,10 +971,10 @@
47998                                         in_folding = 0;
47999                                 } else {
48000                                         if (srv->srvconf.log_request_header_on_error) {
48001 -                                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
48002 +                                               log_error_write(srv, __FILE__, __LINE__, "sbs",
48003                                                                 "CR without LF", con->request.request, "-> 400");
48004                                         }
48005 -                                       
48006 +
48007                                         con->http_status = 400;
48008                                         con->keep_alive = 0;
48009                                         con->response.keep_alive = 0;
48010 @@ -982,28 +990,28 @@
48011                         }
48012                 }
48013         }
48014 -       
48015 +
48016         con->header_len = i;
48017 -       
48018 +
48019         /* do some post-processing */
48020  
48021         if (con->request.http_version == HTTP_VERSION_1_1) {
48022                 if (keep_alive_set != HTTP_CONNECTION_CLOSE) {
48023                         /* no Connection-Header sent */
48024 -                       
48025 +
48026                         /* HTTP/1.1 -> keep-alive default TRUE */
48027                         con->keep_alive = 1;
48028                 } else {
48029                         con->keep_alive = 0;
48030                 }
48031 -               
48032 +
48033                 /* RFC 2616, 14.23 */
48034                 if (con->request.http_host == NULL ||
48035                     buffer_is_empty(con->request.http_host)) {
48036                         con->http_status = 400;
48037                         con->response.keep_alive = 0;
48038                         con->keep_alive = 0;
48039 -                       
48040 +
48041                         if (srv->srvconf.log_request_header_on_error) {
48042                                 log_error_write(srv, __FILE__, __LINE__, "s", "HTTP/1.1 but Host missing -> 400");
48043                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48044 @@ -1015,18 +1023,18 @@
48045         } else {
48046                 if (keep_alive_set == HTTP_CONNECTION_KEEPALIVE) {
48047                         /* no Connection-Header sent */
48048 -                       
48049 +
48050                         /* HTTP/1.0 -> keep-alive default FALSE  */
48051                         con->keep_alive = 1;
48052                 } else {
48053                         con->keep_alive = 0;
48054                 }
48055         }
48056 -       
48057 +
48058         /* check hostname field if it is set */
48059         if (NULL != con->request.http_host &&
48060             0 != request_check_hostname(srv, con, con->request.http_host)) {
48061 -               
48062 +
48063                 if (srv->srvconf.log_request_header_on_error) {
48064                         log_error_write(srv, __FILE__, __LINE__, "s",
48065                                         "Invalid Hostname -> 400");
48066 @@ -1038,7 +1046,7 @@
48067                 con->http_status = 400;
48068                 con->response.keep_alive = 0;
48069                 con->keep_alive = 0;
48070 -               
48071 +
48072                 return 0;
48073         }
48074  
48075 @@ -1048,7 +1056,7 @@
48076                 /* content-length is forbidden for those */
48077                 if (con_length_set && con->request.content_length != 0) {
48078                         /* content-length is missing */
48079 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
48080 +                       log_error_write(srv, __FILE__, __LINE__, "s",
48081                                         "GET/HEAD with content-length -> 400");
48082  
48083                         con->keep_alive = 0;
48084 @@ -1060,7 +1068,7 @@
48085                 /* content-length is required for them */
48086                 if (!con_length_set) {
48087                         /* content-length is missing */
48088 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
48089 +                       log_error_write(srv, __FILE__, __LINE__, "s",
48090                                         "POST-request, but content-length missing -> 411");
48091  
48092                         con->keep_alive = 0;
48093 @@ -1073,16 +1081,16 @@
48094                 /* the may have a content-length */
48095                 break;
48096         }
48097 -                       
48098 -       
48099 +
48100 +
48101         /* check if we have read post data */
48102         if (con_length_set) {
48103                 /* don't handle more the SSIZE_MAX bytes in content-length */
48104                 if (con->request.content_length > SSIZE_MAX) {
48105 -                       con->http_status = 413; 
48106 +                       con->http_status = 413;
48107                         con->keep_alive = 0;
48108  
48109 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
48110 +                       log_error_write(srv, __FILE__, __LINE__, "sds",
48111                                         "request-size too long:", con->request.content_length, "-> 413");
48112                         return 0;
48113                 }
48114 @@ -1090,25 +1098,25 @@
48115                 /* divide by 1024 as srvconf.max_request_size is in kBytes */
48116                 if (srv->srvconf.max_request_size != 0 &&
48117                     (con->request.content_length >> 10) > srv->srvconf.max_request_size) {
48118 -                       /* the request body itself is larger then 
48119 +                       /* the request body itself is larger then
48120                          * our our max_request_size
48121                          */
48122 -               
48123 +
48124                         con->http_status = 413;
48125                         con->keep_alive = 0;
48126 -               
48127 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
48128 +
48129 +                       log_error_write(srv, __FILE__, __LINE__, "sds",
48130                                         "request-size too long:", con->request.content_length, "-> 413");
48131                         return 0;
48132                 }
48133 -               
48134 -               
48135 +
48136 +
48137                 /* we have content */
48138                 if (con->request.content_length != 0) {
48139                         return 1;
48140                 }
48141         }
48142 -       
48143 +
48144         return 0;
48145  }
48146  
48147 @@ -1116,9 +1124,9 @@
48148         UNUSED(srv);
48149  
48150         if (con->request.request->used < 5) return 0;
48151 -       
48152 +
48153         if (0 == memcmp(con->request.request->ptr + con->request.request->used - 5, "\r\n\r\n", 4)) return 1;
48154         if (NULL != strstr(con->request.request->ptr, "\r\n\r\n")) return 1;
48155 -       
48156 +
48157         return 0;
48158  }
48159 --- ../lighttpd-1.4.11/src/response.c   2006-03-04 16:41:39.000000000 +0200
48160 +++ lighttpd-1.4.12/src/response.c      2006-07-16 00:26:04.000000000 +0300
48161 @@ -7,7 +7,6 @@
48162  #include <stdlib.h>
48163  #include <string.h>
48164  #include <time.h>
48165 -#include <unistd.h>
48166  #include <ctype.h>
48167  #include <assert.h>
48168  
48169 @@ -24,15 +23,17 @@
48170  #include "plugin.h"
48171  
48172  #include "sys-socket.h"
48173 +#include "sys-files.h"
48174 +#include "sys-strings.h"
48175  
48176  int http_response_write_header(server *srv, connection *con) {
48177         buffer *b;
48178         size_t i;
48179         int have_date = 0;
48180         int have_server = 0;
48181 -       
48182 +
48183         b = chunkqueue_get_prepend_buffer(con->write_queue);
48184 -       
48185 +
48186         if (con->request.http_version == HTTP_VERSION_1_1) {
48187                 BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 ");
48188         } else {
48189 @@ -41,25 +42,26 @@
48190         buffer_append_long(b, con->http_status);
48191         BUFFER_APPEND_STRING_CONST(b, " ");
48192         buffer_append_string(b, get_http_status_name(con->http_status));
48193 -       
48194 +
48195         if (con->request.http_version != HTTP_VERSION_1_1 || con->keep_alive == 0) {
48196                 BUFFER_APPEND_STRING_CONST(b, "\r\nConnection: ");
48197                 buffer_append_string(b, con->keep_alive ? "keep-alive" : "close");
48198         }
48199 -       
48200 +
48201         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
48202                 BUFFER_APPEND_STRING_CONST(b, "\r\nTransfer-Encoding: chunked");
48203         }
48204 -       
48205 -       
48206 +
48207 +
48208         /* add all headers */
48209         for (i = 0; i < con->response.headers->used; i++) {
48210                 data_string *ds;
48211 -               
48212 +
48213                 ds = (data_string *)con->response.headers->data[i];
48214 -               
48215 +
48216                 if (ds->value->used && ds->key->used &&
48217 -                   0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1)) {
48218 +                   0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1) &&
48219 +                   0 != strcasecmp(ds->key->ptr, "X-Sendfile")) {
48220                         if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Date"))) have_date = 1;
48221                         if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Server"))) have_server = 1;
48222  
48223 @@ -68,28 +70,28 @@
48224                         BUFFER_APPEND_STRING_CONST(b, ": ");
48225                         buffer_append_string_buffer(b, ds->value);
48226  #if 0
48227 -                       log_error_write(srv, __FILE__, __LINE__, "bb", 
48228 +                       log_error_write(srv, __FILE__, __LINE__, "bb",
48229                                         ds->key, ds->value);
48230  #endif
48231                 }
48232         }
48233 -       
48234 +
48235         if (!have_date) {
48236                 /* HTTP/1.1 requires a Date: header */
48237                 BUFFER_APPEND_STRING_CONST(b, "\r\nDate: ");
48238 -       
48239 +
48240                 /* cache the generated timestamp */
48241                 if (srv->cur_ts != srv->last_generated_date_ts) {
48242                         buffer_prepare_copy(srv->ts_date_str, 255);
48243 -               
48244 -                       strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1, 
48245 +
48246 +                       strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1,
48247                                  "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(srv->cur_ts)));
48248 -                        
48249 +
48250                         srv->ts_date_str->used = strlen(srv->ts_date_str->ptr) + 1;
48251 -               
48252 +
48253                         srv->last_generated_date_ts = srv->cur_ts;
48254                 }
48255 -       
48256 +
48257                 buffer_append_string_buffer(b, srv->ts_date_str);
48258         }
48259  
48260 @@ -101,16 +103,16 @@
48261                         buffer_append_string_buffer(b, con->conf.server_tag);
48262                 }
48263         }
48264 -       
48265 +
48266         BUFFER_APPEND_STRING_CONST(b, "\r\n\r\n");
48267 -       
48268 -       
48269 +
48270 +
48271         con->bytes_header = b->used - 1;
48272 -       
48273 +
48274         if (con->conf.log_response_header) {
48275                 log_error_write(srv, __FILE__, __LINE__, "sSb", "Response-Header:", "\n", b);
48276         }
48277 -       
48278 +
48279         return 0;
48280  }
48281  
48282 @@ -118,71 +120,71 @@
48283  
48284  handler_t http_response_prepare(server *srv, connection *con) {
48285         handler_t r;
48286 -       
48287 -       /* looks like someone has already done a decision */
48288 -       if (con->mode == DIRECT && 
48289 +
48290 +       /* looks like someone has already made a decision */
48291 +       if (con->mode == DIRECT &&
48292             (con->http_status != 0 && con->http_status != 200)) {
48293                 /* remove a packets in the queue */
48294                 if (con->file_finished == 0) {
48295                         chunkqueue_reset(con->write_queue);
48296                 }
48297 -               
48298 +
48299                 return HANDLER_FINISHED;
48300         }
48301 -       
48302 +
48303         /* no decision yet, build conf->filename */
48304         if (con->mode == DIRECT && con->physical.path->used == 0) {
48305                 char *qstr;
48306  
48307 -               /* we only come here when we have the parse the full request again
48308 -                * 
48309 -                * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a 
48310 +               /* we only come here when we have to parse the full request again
48311 +                *
48312 +                * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a
48313                  * problem here as mod_setenv might get called multiple times
48314                  *
48315                  * fastcgi-auth might lead to a COMEBACK too
48316                  * fastcgi again dead server too
48317                  *
48318                  * mod_compress might add headers twice too
48319 -                * 
48320 +                *
48321                  *  */
48322 -               
48323 +
48324                 if (con->conf.log_condition_handling) {
48325                         log_error_write(srv, __FILE__, __LINE__,  "s",  "run condition");
48326                 }
48327                 config_patch_connection(srv, con, COMP_SERVER_SOCKET); /* SERVERsocket */
48328 -               
48329 +
48330                 /**
48331                  * prepare strings
48332 -                * 
48333 -                * - uri.path_raw 
48334 +                *
48335 +                * - uri.path_raw
48336                  * - uri.path (secure)
48337                  * - uri.query
48338 -                * 
48339 +                *
48340                  */
48341 -               
48342 -               /** 
48343 +
48344 +               /**
48345                  * Name according to RFC 2396
48346 -                * 
48347 +                *
48348                  * - scheme
48349                  * - authority
48350                  * - path
48351                  * - query
48352 -                * 
48353 +                *
48354                  * (scheme)://(authority)(path)?(query)
48355 -                * 
48356 -                * 
48357 +                *
48358 +                *
48359                  */
48360 -       
48361 +
48362                 buffer_copy_string(con->uri.scheme, con->conf.is_ssl ? "https" : "http");
48363                 buffer_copy_string_buffer(con->uri.authority, con->request.http_host);
48364                 buffer_to_lower(con->uri.authority);
48365 -               
48366 +
48367                 config_patch_connection(srv, con, COMP_HTTP_HOST);      /* Host:        */
48368                 config_patch_connection(srv, con, COMP_HTTP_REMOTEIP);  /* Client-IP */
48369                 config_patch_connection(srv, con, COMP_HTTP_REFERER);   /* Referer:     */
48370                 config_patch_connection(srv, con, COMP_HTTP_USERAGENT); /* User-Agent:  */
48371                 config_patch_connection(srv, con, COMP_HTTP_COOKIE);    /* Cookie:  */
48372 -               
48373 +
48374                 /** extract query string from request.uri */
48375                 if (NULL != (qstr = strchr(con->request.uri->ptr, '?'))) {
48376                         buffer_copy_string    (con->uri.query, qstr + 1);
48377 @@ -200,22 +202,22 @@
48378                         log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-path     : ", con->uri.path_raw);
48379                         log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-query    : ", con->uri.query);
48380                 }
48381 -               
48382 +
48383                 /* disable keep-alive if requested */
48384 -               
48385 +
48386                 if (con->request_count > con->conf.max_keep_alive_requests) {
48387                         con->keep_alive = 0;
48388                 }
48389 -               
48390 -               
48391 +
48392 +
48393                 /**
48394 -                *  
48395 -                * call plugins 
48396 -                * 
48397 +                *
48398 +                * call plugins
48399 +                *
48400                  * - based on the raw URL
48401 -                * 
48402 +                *
48403                  */
48404 -               
48405 +
48406                 switch(r = plugins_call_handle_uri_raw(srv, con)) {
48407                 case HANDLER_GO_ON:
48408                         break;
48409 @@ -229,14 +231,14 @@
48410                         break;
48411                 }
48412  
48413 -               /* build filename 
48414 +               /* build filename
48415                  *
48416                  * - decode url-encodings  (e.g. %20 -> ' ')
48417                  * - remove path-modifiers (e.g. /../)
48418                  */
48419 -               
48420 -               
48421 -               
48422 +
48423 +
48424 +
48425                 if (con->request.http_method == HTTP_METHOD_OPTIONS &&
48426                     con->uri.path_raw->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
48427                         /* OPTIONS * ... */
48428 @@ -253,15 +255,20 @@
48429                 }
48430  
48431                 /**
48432 -                *  
48433 -                * call plugins 
48434 -                * 
48435 +                *
48436 +                * call plugins
48437 +                *
48438                  * - based on the clean URL
48439 -                * 
48440 +                *
48441                  */
48442 -               
48443 +
48444                 config_patch_connection(srv, con, COMP_HTTP_URL); /* HTTPurl */
48445 -               
48446 +
48447 +               /* do we have to downgrade to 1.0 ? */
48448 +               if (!con->conf.allow_http11) {
48449 +                       con->request.http_version = HTTP_VERSION_1_0;
48450 +               }
48451 +
48452                 switch(r = plugins_call_handle_uri_clean(srv, con)) {
48453                 case HANDLER_GO_ON:
48454                         break;
48455 @@ -274,11 +281,11 @@
48456                         log_error_write(srv, __FILE__, __LINE__, "");
48457                         break;
48458                 }
48459 -               
48460 +
48461                 if (con->request.http_method == HTTP_METHOD_OPTIONS &&
48462                     con->uri.path->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
48463 -                       /* option requests are handled directly without checking of the path */
48464 -               
48465 +                       /* option requests are handled directly without checking the path */
48466 +
48467                         response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
48468  
48469                         con->http_status = 200;
48470 @@ -288,46 +295,47 @@
48471                 }
48472  
48473                 /***
48474 -                * 
48475 -                * border 
48476 -                * 
48477 +                *
48478 +                * border
48479 +                *
48480                  * logical filename (URI) becomes a physical filename here
48481 -                * 
48482 -                * 
48483 -                * 
48484 +                *
48485 +                *
48486 +                *
48487                  */
48488 -               
48489 -               
48490 -               
48491 -               
48492 +
48493 +
48494 +
48495 +
48496                 /* 1. stat()
48497                  * ... ISREG() -> ok, go on
48498                  * ... ISDIR() -> index-file -> redirect
48499 -                * 
48500 -                * 2. pathinfo() 
48501 +                *
48502 +                * 2. pathinfo()
48503                  * ... ISREG()
48504 -                * 
48505 +                *
48506                  * 3. -> 404
48507 -                * 
48508 +                *
48509                  */
48510 -               
48511 +
48512                 /*
48513                  * SEARCH DOCUMENT ROOT
48514                  */
48515 -               
48516 +
48517                 /* set a default */
48518 -               
48519 +
48520                 buffer_copy_string_buffer(con->physical.doc_root, con->conf.document_root);
48521                 buffer_copy_string_buffer(con->physical.rel_path, con->uri.path);
48522 -               
48523 -#if defined(__WIN32) || defined(__CYGWIN__)
48524 -               /* strip dots from the end and spaces
48525 +
48526 +               filename_unix2local(con->physical.rel_path);
48527 +#if defined(_WIN32) || defined(__CYGWIN__)
48528 +               /* strip dots and spaces from the end
48529                  *
48530                  * windows/dos handle those filenames as the same file
48531                  *
48532                  * foo == foo. == foo..... == "foo...   " == "foo..  ./"
48533                  *
48534 -                * This will affect in some cases PATHINFO
48535 +                * This will affect PATHINFO in some cases
48536                  *
48537                  * on native windows we could prepend the filename with \\?\ to circumvent
48538                  * this behaviour. I have no idea how to push this through cygwin
48539 @@ -377,36 +385,41 @@
48540                         log_error_write(srv, __FILE__, __LINE__, "");
48541                         break;
48542                 }
48543 -               
48544 -               /* MacOS X and Windows can't distiguish between upper and lower-case 
48545 -                * 
48546 -                * convert to lower-case
48547 +
48548 +               /* The default Mac OS X and Windows filesystems can't distiguish between
48549 +                * upper- and lowercase, so convert to lowercase
48550                  */
48551                 if (con->conf.force_lowercase_filenames) {
48552                         buffer_to_lower(con->physical.rel_path);
48553                 }
48554  
48555 -               /* the docroot plugins might set the servername, if they don't we take http-host */
48556 +               /* the docroot plugins might set the servername; if they don't we take http-host */
48557                 if (buffer_is_empty(con->server_name)) {
48558                         buffer_copy_string_buffer(con->server_name, con->uri.authority);
48559                 }
48560 -               
48561 -               /** 
48562 -                * create physical filename 
48563 +
48564 +               /**
48565 +                * create physical filename
48566                  * -> physical.path = docroot + rel_path
48567 -                * 
48568 +                *
48569                  */
48570 -               
48571 +
48572                 buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
48573 -               BUFFER_APPEND_SLASH(con->physical.path);
48574 +               PATHNAME_APPEND_SLASH(con->physical.path);
48575                 buffer_copy_string_buffer(con->physical.basedir, con->physical.path);
48576                 if (con->physical.rel_path->used &&
48577 -                   con->physical.rel_path->ptr[0] == '/') {
48578 +                   con->physical.rel_path->ptr[0] == DIR_SEPERATOR) {
48579                         buffer_append_string_len(con->physical.path, con->physical.rel_path->ptr + 1, con->physical.rel_path->used - 2);
48580                 } else {
48581                         buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
48582                 }
48583  
48584 +        /* win32: directories can't have a trailing slash */
48585 +        if (con->physical.path->ptr[con->physical.path->used - 2] == DIR_SEPERATOR) {
48586 +            con->physical.path->ptr[con->physical.path->used - 2] = '\0';
48587 +            con->physical.path->used--;
48588 +        }
48589 +
48590                 if (con->conf.log_request_handling) {
48591                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- after doc_root");
48592                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
48593 @@ -426,7 +439,7 @@
48594                         log_error_write(srv, __FILE__, __LINE__, "");
48595                         break;
48596                 }
48597 -               
48598 +
48599                 if (con->conf.log_request_handling) {
48600                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- logical -> physical");
48601                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
48602 @@ -434,38 +447,38 @@
48603                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
48604                 }
48605         }
48606 -       
48607 -       /* 
48608 -        * Noone catched away the file from normal path of execution yet (like mod_access)
48609 -        * 
48610 +
48611 +       /*
48612 +        * No one took the file away from the normal path of execution yet (like mod_access)
48613 +        *
48614          * Go on and check of the file exists at all
48615          */
48616 -       
48617 +
48618         if (con->mode == DIRECT) {
48619                 char *slash = NULL;
48620                 char *pathinfo = NULL;
48621                 int found = 0;
48622                 stat_cache_entry *sce = NULL;
48623 -               
48624 +
48625                 if (con->conf.log_request_handling) {
48626                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling physical path");
48627                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
48628                 }
48629 -               
48630 +
48631                 if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
48632                         /* file exists */
48633 -                       
48634 +
48635                         if (con->conf.log_request_handling) {
48636                                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- file found");
48637                                 log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
48638                         }
48639 -                       
48640 +
48641                         if (S_ISDIR(sce->st.st_mode)) {
48642 -                               if (con->physical.path->ptr[con->physical.path->used - 2] != '/') {
48643 +                               if (con->uri.path->ptr[con->uri.path->used - 2] != '/') {
48644                                         /* redirect to .../ */
48645 -                                       
48646 +
48647                                         http_response_redirect_to_directory(srv, con);
48648 -                                       
48649 +
48650                                         return HANDLER_FINISHED;
48651                                 }
48652                         } else if (!S_ISREG(sce->st.st_mode)) {
48653 @@ -477,12 +490,12 @@
48654                         switch (errno) {
48655                         case EACCES:
48656                                 con->http_status = 403;
48657 -       
48658 +
48659                                 if (con->conf.log_request_handling) {
48660                                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- access denied");
48661                                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
48662                                 }
48663 -                       
48664 +
48665                                 buffer_reset(con->physical.path);
48666                                 return HANDLER_FINISHED;
48667                         case ENOENT:
48668 @@ -499,77 +512,77 @@
48669                                 /* PATH_INFO ! :) */
48670                                 break;
48671                         default:
48672 -                               /* we have no idea what happend. let's tell the user so. */
48673 +                               /* we have no idea what happened, so tell the user. */
48674                                 con->http_status = 500;
48675                                 buffer_reset(con->physical.path);
48676 -                               
48677 +
48678                                 log_error_write(srv, __FILE__, __LINE__, "ssbsb",
48679                                                 "file not found ... or so: ", strerror(errno),
48680                                                 con->uri.path,
48681                                                 "->", con->physical.path);
48682 -                               
48683 +
48684                                 return HANDLER_FINISHED;
48685                         }
48686 -                       
48687 +
48688                         /* not found, perhaps PATHINFO */
48689 -                       
48690 +
48691                         buffer_copy_string_buffer(srv->tmp_buf, con->physical.path);
48692 -                       
48693 +
48694                         do {
48695                                 struct stat st;
48696 -                               
48697 +
48698                                 if (slash) {
48699                                         buffer_copy_string_len(con->physical.path, srv->tmp_buf->ptr, slash - srv->tmp_buf->ptr);
48700                                 } else {
48701                                         buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
48702                                 }
48703 -                               
48704 +
48705                                 if (0 == stat(con->physical.path->ptr, &(st)) &&
48706                                     S_ISREG(st.st_mode)) {
48707                                         found = 1;
48708                                         break;
48709                                 }
48710 -                               
48711 +
48712                                 if (pathinfo != NULL) {
48713                                         *pathinfo = '\0';
48714                                 }
48715                                 slash = strrchr(srv->tmp_buf->ptr, '/');
48716 -                               
48717 +
48718                                 if (pathinfo != NULL) {
48719                                         /* restore '/' */
48720                                         *pathinfo = '/';
48721                                 }
48722 -                               
48723 +
48724                                 if (slash) pathinfo = slash;
48725                         } while ((found == 0) && (slash != NULL) && (slash - srv->tmp_buf->ptr > con->physical.basedir->used - 2));
48726 -                       
48727 +
48728                         if (found == 0) {
48729 -                               /* no it really doesn't exists */
48730 +                               /* no, it really doesn't exists */
48731                                 con->http_status = 404;
48732 -                               
48733 +
48734                                 if (con->conf.log_file_not_found) {
48735                                         log_error_write(srv, __FILE__, __LINE__, "sbsb",
48736                                                         "file not found:", con->uri.path,
48737                                                         "->", con->physical.path);
48738                                 }
48739 -                               
48740 +
48741                                 buffer_reset(con->physical.path);
48742 -                               
48743 +
48744                                 return HANDLER_FINISHED;
48745                         }
48746 -                       
48747 +
48748                         /* we have a PATHINFO */
48749                         if (pathinfo) {
48750                                 buffer_copy_string(con->request.pathinfo, pathinfo);
48751 -                               
48752 +
48753                                 /*
48754                                  * shorten uri.path
48755                                  */
48756 -                               
48757 +
48758                                 con->uri.path->used -= strlen(pathinfo);
48759                                 con->uri.path->ptr[con->uri.path->used - 1] = '\0';
48760                         }
48761 -                       
48762 +
48763                         if (con->conf.log_request_handling) {
48764                                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- after pathinfo check");
48765                                 log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
48766 @@ -577,12 +590,12 @@
48767                                 log_error_write(srv, __FILE__, __LINE__,  "sb", "Pathinfo     :", con->request.pathinfo);
48768                         }
48769                 }
48770 -               
48771 +
48772                 if (con->conf.log_request_handling) {
48773                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling subrequest");
48774                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
48775                 }
48776 -               
48777 +
48778                 /* call the handlers */
48779                 switch(r = plugins_call_handle_subrequest_start(srv, con)) {
48780                 case HANDLER_GO_ON:
48781 @@ -593,32 +606,32 @@
48782                         if (con->conf.log_request_handling) {
48783                                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- subrequest finished");
48784                         }
48785 -                       
48786 -                       /* something strange happend */
48787 +
48788 +                       /* something strange happened */
48789                         return r;
48790                 }
48791 -               
48792 -               /* if we are still here, no one wanted the file, status 403 is ok I think */
48793 -               
48794 +
48795 +               /* if we are still here, no one wanted the file; status 403 is ok I think */
48796 +
48797                 if (con->mode == DIRECT) {
48798                         con->http_status = 403;
48799 -                       
48800 +
48801                         return HANDLER_FINISHED;
48802                 }
48803 -               
48804 +
48805         }
48806 -       
48807 +
48808         switch(r = plugins_call_handle_subrequest(srv, con)) {
48809         case HANDLER_GO_ON:
48810 -               /* request was not handled, looks like we are done */
48811 +               /* request was not handled; looks like we are done */
48812                 return HANDLER_FINISHED;
48813         case HANDLER_FINISHED:
48814                 /* request is finished */
48815         default:
48816 -               /* something strange happend */
48817 +               /* something strange happened */
48818                 return r;
48819         }
48820 -       
48821 +
48822         /* can't happen */
48823         return HANDLER_COMEBACK;
48824  }
48825 --- ../lighttpd-1.4.11/src/server.c     2006-03-04 19:12:17.000000000 +0200
48826 +++ lighttpd-1.4.12/src/server.c        2006-07-18 13:03:40.000000000 +0300
48827 @@ -1,11 +1,9 @@
48828  #include <sys/types.h>
48829 -#include <sys/time.h>
48830  #include <sys/stat.h>
48831  
48832  #include <string.h>
48833  #include <errno.h>
48834  #include <fcntl.h>
48835 -#include <unistd.h>
48836  #include <stdlib.h>
48837  #include <time.h>
48838  #include <signal.h>
48839 @@ -29,9 +27,14 @@
48840  #include "plugin.h"
48841  #include "joblist.h"
48842  #include "network_backends.h"
48843 -
48844 +#ifdef _WIN32
48845 +/* use local getopt implementation */
48846 +# undef HAVE_GETOPT_H
48847 +#endif
48848  #ifdef HAVE_GETOPT_H
48849  #include <getopt.h>
48850 +#else
48851 +#include "getopt.h"
48852  #endif
48853  
48854  #ifdef HAVE_VALGRIND_VALGRIND_H
48855 @@ -60,8 +63,17 @@
48856  /* #define USE_ALARM */
48857  #endif
48858  
48859 +#ifdef _WIN32
48860 +#undef HAVE_SIGNAL
48861 +#endif
48862 +
48863 +#include "sys-files.h"
48864 +#include "sys-process.h"
48865 +#include "sys-socket.h"
48866 +
48867  static volatile sig_atomic_t srv_shutdown = 0;
48868  static volatile sig_atomic_t graceful_shutdown = 0;
48869 +static volatile sig_atomic_t graceful_restart = 0;
48870  static volatile sig_atomic_t handle_sig_alarm = 1;
48871  static volatile sig_atomic_t handle_sig_hup = 0;
48872  
48873 @@ -72,9 +84,9 @@
48874  
48875         switch (sig) {
48876         case SIGTERM: srv_shutdown = 1; break;
48877 -       case SIGINT: 
48878 +       case SIGINT:
48879              if (graceful_shutdown) srv_shutdown = 1;
48880 -            else graceful_shutdown = 1; 
48881 +            else graceful_shutdown = 1;
48882  
48883              break;
48884         case SIGALRM: handle_sig_alarm = 1; break;
48885 @@ -86,9 +98,9 @@
48886  static void signal_handler(int sig) {
48887         switch (sig) {
48888         case SIGTERM: srv_shutdown = 1; break;
48889 -       case SIGINT: 
48890 +       case SIGINT:
48891              if (graceful_shutdown) srv_shutdown = 1;
48892 -            else graceful_shutdown = 1; 
48893 +            else graceful_shutdown = 1;
48894  
48895              break;
48896         case SIGALRM: handle_sig_alarm = 1; break;
48897 @@ -110,35 +122,35 @@
48898         signal(SIGTSTP, SIG_IGN);
48899  #endif
48900         if (0 != fork()) exit(0);
48901 -       
48902 +
48903         if (-1 == setsid()) exit(0);
48904  
48905         signal(SIGHUP, SIG_IGN);
48906  
48907         if (0 != fork()) exit(0);
48908 -       
48909 +
48910         if (0 != chdir("/")) exit(0);
48911  }
48912  #endif
48913  
48914  static server *server_init(void) {
48915         int i;
48916 -       
48917 +
48918         server *srv = calloc(1, sizeof(*srv));
48919         assert(srv);
48920 +    srv->max_fds = 1024;
48921  #define CLEAN(x) \
48922         srv->x = buffer_init();
48923 -       
48924 +
48925         CLEAN(response_header);
48926         CLEAN(parse_full_path);
48927         CLEAN(ts_debug_str);
48928         CLEAN(ts_date_str);
48929 -       CLEAN(errorlog_buf);
48930         CLEAN(response_range);
48931         CLEAN(tmp_buf);
48932         srv->empty_string = buffer_init_string("");
48933         CLEAN(cond_check_buf);
48934 -       
48935 +
48936         CLEAN(srvconf.errorlog_file);
48937         CLEAN(srvconf.groupname);
48938         CLEAN(srvconf.username);
48939 @@ -146,68 +158,63 @@
48940         CLEAN(srvconf.bindhost);
48941         CLEAN(srvconf.event_handler);
48942         CLEAN(srvconf.pid_file);
48943 -       
48944 +
48945         CLEAN(tmp_chunk_len);
48946  #undef CLEAN
48947 -       
48948 +
48949  #define CLEAN(x) \
48950         srv->x = array_init();
48951 -       
48952 +
48953         CLEAN(config_context);
48954         CLEAN(config_touched);
48955         CLEAN(status);
48956  #undef CLEAN
48957 -       
48958 +
48959         for (i = 0; i < FILE_CACHE_MAX; i++) {
48960                 srv->mtime_cache[i].str = buffer_init();
48961         }
48962 -       
48963 +
48964         srv->cur_ts = time(NULL);
48965         srv->startup_ts = srv->cur_ts;
48966 -       
48967 +
48968         srv->conns = calloc(1, sizeof(*srv->conns));
48969         assert(srv->conns);
48970 -       
48971 +
48972         srv->joblist = calloc(1, sizeof(*srv->joblist));
48973         assert(srv->joblist);
48974 -       
48975 +
48976         srv->fdwaitqueue = calloc(1, sizeof(*srv->fdwaitqueue));
48977         assert(srv->fdwaitqueue);
48978 -       
48979 +
48980         srv->srvconf.modules = array_init();
48981         srv->srvconf.modules_dir = buffer_init_string(LIBRARY_DIR);
48982         srv->srvconf.network_backend = buffer_init();
48983         srv->srvconf.upload_tempdirs = array_init();
48984 -       
48985 -       /* use syslog */
48986 -       srv->errorlog_fd = -1;
48987 -       srv->errorlog_mode = ERRORLOG_STDERR;
48988  
48989         srv->split_vals = array_init();
48990 -       
48991 +
48992         return srv;
48993  }
48994  
48995  static void server_free(server *srv) {
48996         size_t i;
48997 -       
48998 +
48999         for (i = 0; i < FILE_CACHE_MAX; i++) {
49000                 buffer_free(srv->mtime_cache[i].str);
49001         }
49002 -       
49003 +
49004  #define CLEAN(x) \
49005         buffer_free(srv->x);
49006 -       
49007 +
49008         CLEAN(response_header);
49009         CLEAN(parse_full_path);
49010         CLEAN(ts_debug_str);
49011         CLEAN(ts_date_str);
49012 -       CLEAN(errorlog_buf);
49013         CLEAN(response_range);
49014         CLEAN(tmp_buf);
49015         CLEAN(empty_string);
49016         CLEAN(cond_check_buf);
49017 -       
49018 +
49019         CLEAN(srvconf.errorlog_file);
49020         CLEAN(srvconf.groupname);
49021         CLEAN(srvconf.username);
49022 @@ -217,7 +224,7 @@
49023         CLEAN(srvconf.pid_file);
49024         CLEAN(srvconf.modules_dir);
49025         CLEAN(srvconf.network_backend);
49026 -       
49027 +
49028         CLEAN(tmp_chunk_len);
49029  #undef CLEAN
49030  
49031 @@ -225,15 +232,15 @@
49032         fdevent_unregister(srv->ev, srv->fd);
49033  #endif
49034         fdevent_free(srv->ev);
49035 -       
49036 +
49037         free(srv->conns);
49038 -       
49039 +
49040         if (srv->config_storage) {
49041                 for (i = 0; i < srv->config_context->used; i++) {
49042                         specific_config *s = srv->config_storage[i];
49043  
49044                         if (!s) continue;
49045 -                       
49046 +
49047                         buffer_free(s->document_root);
49048                         buffer_free(s->server_name);
49049                         buffer_free(s->server_tag);
49050 @@ -242,32 +249,32 @@
49051                         buffer_free(s->error_handler);
49052                         buffer_free(s->errorfile_prefix);
49053                         array_free(s->mimetypes);
49054 -                       
49055 +
49056                         free(s);
49057                 }
49058                 free(srv->config_storage);
49059                 srv->config_storage = NULL;
49060         }
49061 -       
49062 +
49063  #define CLEAN(x) \
49064         array_free(srv->x);
49065 -       
49066 +
49067         CLEAN(config_context);
49068         CLEAN(config_touched);
49069         CLEAN(status);
49070         CLEAN(srvconf.upload_tempdirs);
49071  #undef CLEAN
49072 -       
49073 +
49074         joblist_free(srv, srv->joblist);
49075         fdwaitqueue_free(srv, srv->fdwaitqueue);
49076 -       
49077 +
49078         if (srv->stat_cache) {
49079                 stat_cache_free(srv->stat_cache);
49080         }
49081  
49082         array_free(srv->srvconf.modules);
49083         array_free(srv->split_vals);
49084 -       
49085 +
49086         free(srv);
49087  }
49088  
49089 @@ -281,14 +288,12 @@
49090  " - a light and fast webserver\n" \
49091  "Build-Date: " __DATE__ " " __TIME__ "\n";
49092  ;
49093 -#undef TEXT_SSL        
49094 +#undef TEXT_SSL
49095         write(STDOUT_FILENO, b, strlen(b));
49096  }
49097  
49098  static void show_features (void) {
49099 -  show_version();
49100 -  printf("\nEvent Handlers:\n\n%s",
49101 -
49102 +  const char *s = ""
49103  #ifdef USE_SELECT
49104        "\t+ select (generic)\n"
49105  #else
49106 @@ -355,11 +360,6 @@
49107  #else
49108        "\t- crypt support\n"
49109  #endif
49110 -#ifdef USE_PAM
49111 -      "\t+ PAM support\n"
49112 -#else
49113 -      "\t- PAM support\n"
49114 -#endif
49115  #ifdef USE_OPENSSL
49116        "\t+ SSL Support\n"
49117  #else
49118 @@ -371,9 +371,9 @@
49119        "\t- PCRE support\n"
49120  #endif
49121  #ifdef HAVE_MYSQL
49122 -      "\t+ mySQL support\n"
49123 +      "\t+ MySQL support\n"
49124  #else
49125 -      "\t- mySQL support\n"
49126 +      "\t- MySQL support\n"
49127  #endif
49128  #if defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER)
49129        "\t+ LDAP support\n"
49130 @@ -410,8 +410,11 @@
49131  #else
49132        "\t- GDBM support\n"
49133  #endif
49134 -      "\n"
49135 -      );
49136 +      "\n";
49137 +
49138 +  show_version();
49139 +
49140 +  printf("\nEvent Handlers:\n\n%s", s);
49141  }
49142  
49143  static void show_help (void) {
49144 @@ -433,277 +436,644 @@
49145  " -h         show this help\n" \
49146  "\n"
49147  ;
49148 -#undef TEXT_SSL        
49149 +#undef TEXT_SSL
49150  #undef TEXT_IPV6
49151         write(STDOUT_FILENO, b, strlen(b));
49152  }
49153  
49154 -int main (int argc, char **argv) {
49155 -       server *srv = NULL;
49156 -       int print_config = 0;
49157 -       int test_config = 0;
49158 -       int i_am_root;
49159 -       int o;
49160 -       int num_childs = 0;
49161 -       int pid_fd = -1, fd;
49162 -       size_t i;
49163 -#ifdef HAVE_SIGACTION
49164 -       struct sigaction act;
49165 -#endif
49166 -#ifdef HAVE_GETRLIMIT
49167 -       struct rlimit rlim;
49168 -#endif
49169 -       
49170 -#ifdef USE_ALARM
49171 -       struct itimerval interval;
49172 -       
49173 -       interval.it_interval.tv_sec = 1;
49174 -       interval.it_interval.tv_usec = 0;
49175 -       interval.it_value.tv_sec = 1;
49176 -       interval.it_value.tv_usec = 0;
49177 -#endif
49178 -       
49179 -       
49180 -       /* for nice %b handling in strfime() */
49181 -       setlocale(LC_TIME, "C");
49182 -       
49183 -       if (NULL == (srv = server_init())) {
49184 -               fprintf(stderr, "did this really happen?\n");
49185 -               return -1;
49186 -       }
49187 -       
49188 -       /* init structs done */
49189 -       
49190 -       srv->srvconf.port = 0;
49191 -#ifdef HAVE_GETUID
49192 -       i_am_root = (getuid() == 0);
49193 -#else
49194 -       i_am_root = 0;
49195 -#endif
49196 -       srv->srvconf.dont_daemonize = 0;
49197 -       
49198 -       while(-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) {
49199 -               switch(o) {
49200 -               case 'f': 
49201 -                       if (config_read(srv, optarg)) { 
49202 -                               server_free(srv);
49203 -                               return -1;
49204 -                       }
49205 -                       break;
49206 -               case 'm':
49207 -                       buffer_copy_string(srv->srvconf.modules_dir, optarg);
49208 -                       break;
49209 -               case 'p': print_config = 1; break;
49210 -               case 't': test_config = 1; break;
49211 -               case 'D': srv->srvconf.dont_daemonize = 1; break;
49212 -               case 'v': show_version(); return 0;
49213 -               case 'V': show_features(); return 0;          
49214 -               case 'h': show_help(); return 0;
49215 -               default: 
49216 -                       show_help();
49217 -                       server_free(srv);
49218 -                       return -1;
49219 -               }
49220 -       }
49221 -       
49222 -       if (!srv->config_storage) {
49223 -               log_error_write(srv, __FILE__, __LINE__, "s",
49224 -                               "No configuration available. Try using -f option.");
49225 -               
49226 -               server_free(srv);
49227 -               return -1;
49228 -       }
49229 -       
49230 -       if (print_config) {
49231 -               data_unset *dc = srv->config_context->data[0];
49232 -               if (dc) {
49233 -                       dc->print(dc, 0);
49234 -                       fprintf(stderr, "\n");
49235 -               } else {
49236 -                       /* shouldn't happend */
49237 -                       fprintf(stderr, "global config not found\n");
49238 -               }
49239 -       }
49240 +int lighty_mainloop(server *srv) {
49241 +       fdevent_revents *revents = fdevent_revents_init();
49242  
49243 -       if (test_config) {
49244 -               printf("Syntax OK\n");
49245 -       }
49246 +       /* main-loop */
49247 +       while (!srv_shutdown) {
49248 +               int n;
49249 +               size_t ndx;
49250 +               time_t min_ts;
49251  
49252 -       if (test_config || print_config) {
49253 -               server_free(srv);
49254 -               return 0;
49255 -       }
49256 -       
49257 -       /* close stdin and stdout, as they are not needed */
49258 -       /* move stdin to /dev/null */
49259 -       if (-1 != (fd = open("/dev/null", O_RDONLY))) {
49260 -               close(STDIN_FILENO);
49261 -               dup2(fd, STDIN_FILENO);
49262 -               close(fd);
49263 -       }
49264 -       
49265 -       /* move stdout to /dev/null */
49266 -       if (-1 != (fd = open("/dev/null", O_WRONLY))) {
49267 -               close(STDOUT_FILENO);
49268 -               dup2(fd, STDOUT_FILENO);
49269 -               close(fd);
49270 -       }
49271 -       
49272 -       if (0 != config_set_defaults(srv)) {
49273 -               log_error_write(srv, __FILE__, __LINE__, "s", 
49274 -                               "setting default values failed");
49275 -               server_free(srv);
49276 -               return -1;
49277 -       }
49278 -       
49279 -       /* UID handling */
49280 -#ifdef HAVE_GETUID
49281 -       if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
49282 -               /* we are setuid-root */
49283 -               
49284 -               log_error_write(srv, __FILE__, __LINE__, "s", 
49285 -                               "Are you nuts ? Don't apply a SUID bit to this binary");
49286 -               
49287 -               server_free(srv);
49288 -               return -1;
49289 -       }
49290 -#endif
49291 -       
49292 -       /* check document-root */
49293 -       if (srv->config_storage[0]->document_root->used <= 1) {
49294 -               log_error_write(srv, __FILE__, __LINE__, "s", 
49295 -                               "document-root is not set\n");
49296 -               
49297 -               server_free(srv);
49298 -               
49299 -               return -1;
49300 -       }
49301 -       
49302 -       if (plugins_load(srv)) {
49303 -               log_error_write(srv, __FILE__, __LINE__, "s",
49304 -                               "loading plugins finally failed");
49305 -               
49306 -               plugins_free(srv);
49307 -               server_free(srv);
49308 -               
49309 -               return -1;
49310 -       }
49311 -       
49312 -       /* open pid file BEFORE chroot */
49313 -       if (srv->srvconf.pid_file->used) {
49314 -               if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
49315 -                       struct stat st;
49316 -                       if (errno != EEXIST) {
49317 -                               log_error_write(srv, __FILE__, __LINE__, "sbs",
49318 -                                       "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49319 -                               return -1;
49320 -                       }
49321 -                       
49322 -                       if (0 != stat(srv->srvconf.pid_file->ptr, &st)) {
49323 -                               log_error_write(srv, __FILE__, __LINE__, "sbs",
49324 -                                               "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49325 -                       }
49326 -                       
49327 -                       if (!S_ISREG(st.st_mode)) {
49328 -                               log_error_write(srv, __FILE__, __LINE__, "sb",
49329 -                                               "pid-file exists and isn't regular file:", srv->srvconf.pid_file);
49330 -                               return -1;
49331 -                       }
49332 -                       
49333 -                       if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
49334 -                               log_error_write(srv, __FILE__, __LINE__, "sbs",
49335 -                                               "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49336 -                               return -1;
49337 +               if (handle_sig_hup) {
49338 +                       handler_t r;
49339 +
49340 +                       /* reset notification */
49341 +                       handle_sig_hup = 0;
49342 +
49343 +#if 0
49344 +                               pid_t pid;
49345 +
49346 +                       /* send the old process into a graceful-shutdown and start a
49347 +                        * new process right away
49348 +                        *
49349 +                        * BUGS:
49350 +                        * - if webserver is running on port < 1024 (e.g. 80, 433)
49351 +                        *   we don't have the permissions to bind to that port anymore
49352 +                        *
49353 +                        *
49354 +                        *  */
49355 +                       if (0 == (pid = fork())) {
49356 +                               execve(argv[0], argv, envp);
49357 +
49358 +                               exit(-1);
49359 +                       } else if (pid == -1) {
49360 +
49361 +                       } else {
49362 +                               /* parent */
49363 +
49364 +                               graceful_shutdown = 1; /* shutdown without killing running connections */
49365 +                               graceful_restart = 1;  /* don't delete pid file */
49366                         }
49367 -               }
49368 -       }
49369 +#else
49370 +                       /* cycle logfiles */
49371  
49372 -       if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
49373 -               /* select limits itself
49374 -                *
49375 -                * as it is a hard limit and will lead to a segfault we add some safety
49376 -                * */
49377 -               srv->max_fds = FD_SETSIZE - 200;
49378 -       } else {
49379 -               srv->max_fds = 4096;
49380 -       }
49381 +                       switch(r = plugins_call_handle_sighup(srv)) {
49382 +                       case HANDLER_GO_ON:
49383 +                               break;
49384 +                       default:
49385 +                               log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r);
49386 +                               break;
49387 +                       }
49388  
49389 -       if (i_am_root) {
49390 -               struct group *grp = NULL;
49391 -               struct passwd *pwd = NULL;
49392 -               int use_rlimit = 1;
49393 +                       if (-1 == log_error_cycle()) {
49394 +                               log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying");
49395  
49396 -#ifdef HAVE_VALGRIND_VALGRIND_H
49397 -               if (RUNNING_ON_VALGRIND) use_rlimit = 0;
49398 -#endif
49399 -               
49400 -#ifdef HAVE_GETRLIMIT
49401 -               if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) {
49402 -                       log_error_write(srv, __FILE__, __LINE__,
49403 -                                       "ss", "couldn't get 'max filedescriptors'",
49404 -                                       strerror(errno));
49405 -                       return -1;
49406 -               }
49407 -               
49408 -               if (use_rlimit && srv->srvconf.max_fds) {
49409 -                       /* set rlimits */
49410 -                       
49411 -                       rlim.rlim_cur = srv->srvconf.max_fds;
49412 -                       rlim.rlim_max = srv->srvconf.max_fds;
49413 -                       
49414 -                       if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) {
49415 -                               log_error_write(srv, __FILE__, __LINE__,
49416 -                                               "ss", "couldn't set 'max filedescriptors'",
49417 -                                               strerror(errno));
49418                                 return -1;
49419                         }
49420 +#endif
49421                 }
49422  
49423 -               /* #372: solaris need some fds extra for devpoll */     
49424 -               if (rlim.rlim_cur > 10) rlim.rlim_cur -= 10;
49425 +               if (handle_sig_alarm) {
49426 +                       /* a new second */
49427  
49428 -               if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
49429 -                       srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200;
49430 -               } else {
49431 -                       srv->max_fds = rlim.rlim_cur;
49432 -               }
49433 +#ifdef USE_ALARM
49434 +                       /* reset notification */
49435 +                       handle_sig_alarm = 0;
49436 +#endif
49437  
49438 -               /* set core file rlimit, if enable_cores is set */
49439 -               if (use_rlimit && srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) {
49440 -                       rlim.rlim_cur = rlim.rlim_max;
49441 +                       /* get current time */
49442 +                       min_ts = time(NULL);
49443 +
49444 +                       if (min_ts != srv->cur_ts) {
49445 +                               int cs = 0;
49446 +                               connections *conns = srv->conns;
49447 +                               handler_t r;
49448 +
49449 +                               switch(r = plugins_call_handle_trigger(srv)) {
49450 +                               case HANDLER_GO_ON:
49451 +                                       break;
49452 +                               case HANDLER_ERROR:
49453 +                                       log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed");
49454 +                                       break;
49455 +                               default:
49456 +                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
49457 +                                       break;
49458 +                               }
49459 +
49460 +                               /* trigger waitpid */
49461 +                               srv->cur_ts = min_ts;
49462 +
49463 +                               /* cleanup stat-cache */
49464 +                               stat_cache_trigger_cleanup(srv);
49465 +                               /**
49466 +                                * check all connections for timeouts
49467 +                                *
49468 +                                */
49469 +                               for (ndx = 0; ndx < conns->used; ndx++) {
49470 +                                       int changed = 0;
49471 +                                       connection *con;
49472 +                                       int t_diff;
49473 +
49474 +                                       con = conns->ptr[ndx];
49475 +
49476 +                                       if (con->state == CON_STATE_READ ||
49477 +                                           con->state == CON_STATE_READ_POST) {
49478 +                                               if (con->request_count == 1) {
49479 +                                                       if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
49480 +                                                               /* time - out */
49481 +#if 0
49482 +                                                               log_error_write(srv, __FILE__, __LINE__, "sd",
49483 +                                                                               "connection closed - read-timeout:", con->fd);
49484 +#endif
49485 +                                                               connection_set_state(srv, con, CON_STATE_ERROR);
49486 +                                                               changed = 1;
49487 +                                                       }
49488 +                                               } else {
49489 +                                                       if (srv->cur_ts - con->read_idle_ts > con->conf.max_keep_alive_idle) {
49490 +                                                               /* time - out */
49491 +#if 0
49492 +                                                               log_error_write(srv, __FILE__, __LINE__, "sd",
49493 +                                                                               "connection closed - read-timeout:", con->fd);
49494 +#endif
49495 +                                                               connection_set_state(srv, con, CON_STATE_ERROR);
49496 +                                                               changed = 1;
49497 +                                                       }
49498 +                                               }
49499 +                                       }
49500 +
49501 +                                       if ((con->state == CON_STATE_WRITE) &&
49502 +                                           (con->write_request_ts != 0)) {
49503 +#if 0
49504 +                                               if (srv->cur_ts - con->write_request_ts > 60) {
49505 +                                                       log_error_write(srv, __FILE__, __LINE__, "sdd",
49506 +                                                                       "connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts);
49507 +                                               }
49508 +#endif
49509 +
49510 +                                               if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) {
49511 +                                                       /* time - out */
49512 +#if 1
49513 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbsosds",
49514 +                                                                       "NOTE: a request for",
49515 +                                                                       con->request.uri,
49516 +                                                                       "timed out after writing",
49517 +                                                                       con->bytes_written,
49518 +                                                                       "bytes. We waited",
49519 +                                                                       (int)con->conf.max_write_idle,
49520 +                                                                       "seconds. If this a problem increase server.max-write-idle");
49521 +#endif
49522 +                                                       connection_set_state(srv, con, CON_STATE_ERROR);
49523 +                                                       changed = 1;
49524 +                                               }
49525 +                                       }
49526 +                                       /* we don't like div by zero */
49527 +                                       if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1;
49528 +
49529 +                                       if (con->traffic_limit_reached &&
49530 +                                           (con->conf.kbytes_per_second == 0 ||
49531 +                                            ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) {
49532 +                                               /* enable connection again */
49533 +                                               con->traffic_limit_reached = 0;
49534 +
49535 +                                               changed = 1;
49536 +                                       }
49537 +
49538 +                                       if (changed) {
49539 +                                               connection_state_machine(srv, con);
49540 +                                       }
49541 +                                       con->bytes_written_cur_second = 0;
49542 +                                       *(con->conf.global_bytes_per_second_cnt_ptr) = 0;
49543 +
49544 +#if 0
49545 +                                       if (cs == 0) {
49546 +                                               fprintf(stderr, "connection-state: ");
49547 +                                               cs = 1;
49548 +                                       }
49549 +
49550 +                                       fprintf(stderr, "c[%d,%d]: %s ",
49551 +                                               con->fd,
49552 +                                               con->fcgi.fd,
49553 +                                               connection_get_state(con->state));
49554 +#endif
49555 +                               }
49556 +
49557 +                               if (cs == 1) fprintf(stderr, "\n");
49558 +                       }
49559 +               }
49560 +
49561 +               if (srv->sockets_disabled) {
49562 +                       /* our server sockets are disabled, why ? */
49563 +
49564 +                       if ((srv->cur_fds + srv->want_fds < srv->max_fds * 0.8) && /* we have enough unused fds */
49565 +                           (srv->conns->used < srv->max_conns * 0.9) &&
49566 +                           (0 == graceful_shutdown)) {
49567 +                               size_t i;
49568 +
49569 +                               for (i = 0; i < srv->srv_sockets.used; i++) {
49570 +                                       server_socket *srv_socket = srv->srv_sockets.ptr[i];
49571 +                                       fdevent_event_add(srv->ev, srv_socket->sock, FDEVENT_IN);
49572 +                               }
49573 +
49574 +                               log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again");
49575 +
49576 +                               srv->sockets_disabled = 0;
49577 +                       }
49578 +               } else {
49579 +                       if ((srv->cur_fds + srv->want_fds > srv->max_fds * 0.9) || /* out of fds */
49580 +                           (srv->conns->used > srv->max_conns) || /* out of connections */
49581 +                           (graceful_shutdown)) { /* graceful_shutdown */
49582 +                               size_t i;
49583 +
49584 +                               /* disable server-fds */
49585 +
49586 +                               for (i = 0; i < srv->srv_sockets.used; i++) {
49587 +                                       server_socket *srv_socket = srv->srv_sockets.ptr[i];
49588 +                                       fdevent_event_del(srv->ev, srv_socket->sock);
49589 +
49590 +                                       if (graceful_shutdown) {
49591 +                                               /* we don't want this socket anymore,
49592 +                                                *
49593 +                                                * closing it right away will make it possible for
49594 +                                                * the next lighttpd to take over (graceful restart)
49595 +                                                *  */
49596 +
49597 +                                               fdevent_unregister(srv->ev, srv_socket->sock);
49598 +                                               closesocket(srv_socket->sock->fd);
49599 +                                               srv_socket->sock->fd = -1;
49600 +
49601 +                                               /* network_close() will cleanup after us */
49602 +                                       }
49603 +                               }
49604 +
49605 +                               if (graceful_shutdown) {
49606 +                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started");
49607 +                               } else if (srv->conns->used > srv->max_conns) {
49608 +                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached");
49609 +                               } else {
49610 +                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds");
49611 +                               }
49612 +
49613 +                               srv->sockets_disabled = 1;
49614 +                       }
49615 +               }
49616 +
49617 +               if (graceful_shutdown && srv->conns->used == 0) {
49618 +                       /* we are in graceful shutdown phase and all connections are closed
49619 +                        * we are ready to terminate without harming anyone */
49620 +                       srv_shutdown = 1;
49621 +               }
49622 +
49623 +               /* we still have some fds to share */
49624 +               if (srv->want_fds) {
49625 +                       /* check the fdwaitqueue for waiting fds */
49626 +                       int free_fds = srv->max_fds - srv->cur_fds - 16;
49627 +                       connection *con;
49628 +
49629 +                       for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) {
49630 +                               connection_state_machine(srv, con);
49631 +
49632 +                               srv->want_fds--;
49633 +                       }
49634 +               }
49635 +
49636 +               if ((n = fdevent_poll(srv->ev, 1000)) > 0) {
49637 +                       /* n is the number of events */
49638 +                       size_t i;
49639 +                       fdevent_get_revents(srv->ev, n, revents);
49640 +
49641 +                       /* handle client connections first
49642 +                        * 
49643 +                        * this is a bit of a hack, but we have to make sure than we handle 
49644 +                        * close-events before the connection is reused for a keep-alive 
49645 +                        * request
49646 +                        *
49647 +                        * this is mostly an issue for mod_proxy_core, but you never know
49648 +                        *
49649 +                        */
49650 +
49651 +                       for (i = 0; i < revents->used; i++) {
49652 +                               fdevent_revent *revent = revents->ptr[i];
49653 +                               handler_t r;
49654 +
49655 +                               /* skip server-fds */
49656 +                               if (revent->handler == network_server_handle_fdevent) continue;
49657 +
49658 +                               switch (r = (*(revent->handler))(srv, revent->context, revent->revents)) {
49659 +                               case HANDLER_FINISHED:
49660 +                               case HANDLER_GO_ON:
49661 +                               case HANDLER_WAIT_FOR_EVENT:
49662 +                               case HANDLER_WAIT_FOR_FD:
49663 +                                       break;
49664 +                               case HANDLER_ERROR:
49665 +                                       /* should never happen */
49666 +                                       SEGFAULT();
49667 +                                       break;
49668 +                               default:
49669 +                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
49670 +                                       break;
49671 +                               }
49672 +                       } 
49673 +
49674 +                       for (i = 0; i < revents->used; i++) {
49675 +                               fdevent_revent *revent = revents->ptr[i];
49676 +                               handler_t r;
49677 +
49678 +                               /* server fds only */
49679 +                               if (revent->handler != network_server_handle_fdevent) continue;
49680 +
49681 +                               switch (r = (*(revent->handler))(srv, revent->context, revent->revents)) {
49682 +                               case HANDLER_FINISHED:
49683 +                               case HANDLER_GO_ON:
49684 +                               case HANDLER_WAIT_FOR_EVENT:
49685 +                               case HANDLER_WAIT_FOR_FD:
49686 +                                       break;
49687 +                               case HANDLER_ERROR:
49688 +                                       /* should never happen */
49689 +                                       SEGFAULT();
49690 +                                       break;
49691 +                               default:
49692 +                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
49693 +                                       break;
49694 +                               }
49695 +                       } 
49696 +
49697 +               } else if (n < 0 && errno != EINTR) {
49698 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
49699 +                                       "fdevent_poll failed:",
49700 +                                       strerror(errno));
49701 +               }
49702 +
49703 +               for (ndx = 0; ndx < srv->joblist->used; ndx++) {
49704 +                       connection *con = srv->joblist->ptr[ndx];
49705 +                       handler_t r;
49706 +
49707 +                       connection_state_machine(srv, con);
49708 +
49709 +                       switch(r = plugins_call_handle_joblist(srv, con)) {
49710 +                       case HANDLER_FINISHED:
49711 +                       case HANDLER_GO_ON:
49712 +                               break;
49713 +                       default:
49714 +                               log_error_write(srv, __FILE__, __LINE__, "d", r);
49715 +                               break;
49716 +                       }
49717 +
49718 +                       con->in_joblist = 0;
49719 +               }
49720 +
49721 +               srv->joblist->used = 0;
49722 +       }
49723 +
49724 +       fdevent_revents_free(revents);
49725 +
49726 +       return 0;
49727 +}
49728 +
49729 +
49730 +int main (int argc, char **argv, char **envp) {
49731 +       server *srv = NULL;
49732 +       int print_config = 0;
49733 +       int test_config = 0;
49734 +       int i_am_root;
49735 +       int o;
49736 +       int num_childs = 0;
49737 +       int pid_fd = -1, fd;
49738 +       size_t i;
49739 +#ifdef _WIN32
49740 +       char *optarg = NULL;
49741 +#endif
49742 +
49743 +#ifdef HAVE_SIGACTION
49744 +       struct sigaction act;
49745 +#endif
49746 +#ifdef HAVE_GETRLIMIT
49747 +       struct rlimit rlim;
49748 +#endif
49749 +
49750 +#ifdef USE_ALARM
49751 +       struct itimerval interval;
49752 +
49753 +       interval.it_interval.tv_sec = 1;
49754 +       interval.it_interval.tv_usec = 0;
49755 +       interval.it_value.tv_sec = 1;
49756 +       interval.it_value.tv_usec = 0;
49757 +#endif
49758 +
49759 +       log_init();
49760 +
49761 +       /* for nice %b handling in strfime() */
49762 +       setlocale(LC_TIME, "C");
49763 +
49764 +       if (NULL == (srv = server_init())) {
49765 +               fprintf(stderr, "did this really happen?\n");
49766 +               return -1;
49767 +       }
49768 +
49769 +       /* init structs done */
49770 +
49771 +       srv->srvconf.port = 0;
49772 +#ifdef HAVE_GETUID
49773 +       i_am_root = (getuid() == 0);
49774 +#else
49775 +       i_am_root = 0;
49776 +#endif
49777 +       srv->srvconf.dont_daemonize = 0;
49778 +
49779 +       while(-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) {
49780 +               switch(o) {
49781 +               case 'f':
49782 +#ifdef _WIN32
49783 +                       /* evil HACK for windows, optarg is not set */
49784 +                       optarg = argv[optind-1];
49785 +#endif
49786 +                       if (config_read(srv, optarg)) {
49787 +                               server_free(srv);
49788 +                               return -1;
49789 +                       }
49790 +
49791 +                       break;
49792 +               case 'm':
49793 +                       buffer_copy_string(srv->srvconf.modules_dir, optarg);
49794 +                       break;
49795 +               case 'p': print_config = 1; break;
49796 +               case 't': test_config = 1; break;
49797 +               case 'D': srv->srvconf.dont_daemonize = 1; break;
49798 +               case 'v': show_version(); return 0;
49799 +               case 'V': show_features(); return 0;
49800 +               case 'h': show_help(); return 0;
49801 +               default:
49802 +                       show_help();
49803 +                       server_free(srv);
49804 +                       return -1;
49805 +               }
49806 +       }
49807 +
49808 +       if (!srv->config_storage) {
49809 +               log_error_write(srv, __FILE__, __LINE__, "s",
49810 +                               "No configuration available. Try using -f option.");
49811 +
49812 +               server_free(srv);
49813 +               return -1;
49814 +       }
49815 +
49816 +       if (print_config) {
49817 +               data_unset *dc = srv->config_context->data[0];
49818 +               if (dc) {
49819 +                       dc->print(dc, 0);
49820 +                       fprintf(stderr, "\n");
49821 +               } else {
49822 +                       /* shouldn't happend */
49823 +                       fprintf(stderr, "global config not found\n");
49824 +               }
49825 +       }
49826 +
49827 +       if (test_config) {
49828 +               printf("Syntax OK\n");
49829 +       }
49830 +
49831 +       if (test_config || print_config) {
49832 +               server_free(srv);
49833 +               return 0;
49834 +       }
49835 +
49836 +       /* close stdin and stdout, as they are not needed */
49837 +       /* move stdin to /dev/null */
49838 +       if (-1 != (fd = open("/dev/null", O_RDONLY))) {
49839 +               close(STDIN_FILENO);
49840 +               dup2(fd, STDIN_FILENO);
49841 +               close(fd);
49842 +       }
49843 +
49844 +       /* move stdout to /dev/null */
49845 +       if (-1 != (fd = open("/dev/null", O_WRONLY))) {
49846 +               close(STDOUT_FILENO);
49847 +               dup2(fd, STDOUT_FILENO);
49848 +               close(fd);
49849 +       }
49850 +
49851 +       if (0 != config_set_defaults(srv)) {
49852 +               log_error_write(srv, __FILE__, __LINE__, "s",
49853 +                               "setting default values failed");
49854 +               server_free(srv);
49855 +               return -1;
49856 +       }
49857 +
49858 +       /* UID handling */
49859 +#ifdef HAVE_GETUID
49860 +       if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
49861 +               /* we are setuid-root */
49862 +
49863 +               log_error_write(srv, __FILE__, __LINE__, "s",
49864 +                               "Are you nuts ? Don't apply a SUID bit to this binary");
49865 +
49866 +               server_free(srv);
49867 +               return -1;
49868 +       }
49869 +#endif
49870 +
49871 +       /* check document-root */
49872 +       if (srv->config_storage[0]->document_root->used <= 1) {
49873 +               log_error_write(srv, __FILE__, __LINE__, "s",
49874 +                               "document-root is not set\n");
49875 +
49876 +               server_free(srv);
49877 +
49878 +               return -1;
49879 +       }
49880 +
49881 +       if (plugins_load(srv)) {
49882 +               log_error_write(srv, __FILE__, __LINE__, "s",
49883 +                               "loading plugins finally failed");
49884 +
49885 +               plugins_free(srv);
49886 +               server_free(srv);
49887 +
49888 +               return -1;
49889 +       }
49890 +
49891 +#ifndef _WIN32
49892 +       /* open pid file BEFORE chroot */
49893 +       if (srv->srvconf.pid_file->used) {
49894 +               if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
49895 +                       struct stat st;
49896 +                       if (errno != EEXIST) {
49897 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
49898 +                                       "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49899 +                               return -1;
49900 +                       }
49901 +
49902 +                       if (0 != stat(srv->srvconf.pid_file->ptr, &st)) {
49903 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
49904 +                                               "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49905 +                       }
49906 +
49907 +                       if (!S_ISREG(st.st_mode)) {
49908 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
49909 +                                               "pid-file exists and isn't regular file:", srv->srvconf.pid_file);
49910 +                               return -1;
49911 +                       }
49912 +
49913 +                       if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
49914 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
49915 +                                               "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49916 +                               return -1;
49917 +                       }
49918 +               }
49919 +       }
49920 +#endif
49921 +       if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
49922 +               /* select limits itself
49923 +                *
49924 +                * as it is a hard limit and will lead to a segfault we add some safety
49925 +                * */
49926 +        fprintf(stderr, "%s.%d: max parallel connections: %d\r\n", __FILE__, __LINE__, FD_SETSIZE);
49927 +               srv->max_fds = FD_SETSIZE - 4;
49928 +       } else {
49929 +               srv->max_fds = 4096;
49930 +       }
49931 +
49932 +       if (i_am_root) {
49933 +               struct group *grp = NULL;
49934 +               struct passwd *pwd = NULL;
49935 +               int use_rlimit = 1;
49936 +
49937 +#ifdef HAVE_VALGRIND_VALGRIND_H
49938 +               if (RUNNING_ON_VALGRIND) use_rlimit = 0;
49939 +#endif
49940 +
49941 +#ifdef HAVE_GETRLIMIT
49942 +               if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) {
49943 +                       log_error_write(srv, __FILE__, __LINE__,
49944 +                                       "ss", "couldn't get 'max filedescriptors'",
49945 +                                       strerror(errno));
49946 +                       return -1;
49947 +               }
49948 +
49949 +               if (use_rlimit && srv->srvconf.max_fds) {
49950 +                       /* set rlimits */
49951 +
49952 +                       rlim.rlim_cur = srv->srvconf.max_fds;
49953 +                       rlim.rlim_max = srv->srvconf.max_fds;
49954 +
49955 +                       if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) {
49956 +                               log_error_write(srv, __FILE__, __LINE__,
49957 +                                               "ss", "couldn't set 'max filedescriptors'",
49958 +                                               strerror(errno));
49959 +                               return -1;
49960 +                       }
49961 +               }
49962 +
49963 +               /* #372: solaris need some fds extra for devpoll */
49964 +               if (rlim.rlim_cur > 10) rlim.rlim_cur -= 10;
49965 +
49966 +               if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
49967 +                       srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200;
49968 +               } else {
49969 +                       srv->max_fds = rlim.rlim_cur;
49970 +               }
49971 +
49972 +               /* set core file rlimit, if enable_cores is set */
49973 +               if (use_rlimit && srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) {
49974 +                       rlim.rlim_cur = rlim.rlim_max;
49975                         setrlimit(RLIMIT_CORE, &rlim);
49976                 }
49977  #endif
49978                 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
49979                         /* don't raise the limit above FD_SET_SIZE */
49980                         if (srv->max_fds > FD_SETSIZE - 200) {
49981 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
49982 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
49983                                                 "can't raise max filedescriptors above",  FD_SETSIZE - 200,
49984                                                 "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds.");
49985                                 return -1;
49986                         }
49987                 }
49988  
49989 -               
49990 +
49991  #ifdef HAVE_PWD_H
49992                 /* set user and group */
49993                 if (srv->srvconf.username->used) {
49994                         if (NULL == (pwd = getpwnam(srv->srvconf.username->ptr))) {
49995 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
49996 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
49997                                                 "can't find username", srv->srvconf.username);
49998                                 return -1;
49999                         }
50000 -                       
50001 +
50002                         if (pwd->pw_uid == 0) {
50003                                 log_error_write(srv, __FILE__, __LINE__, "s",
50004                                                 "I will not set uid to 0\n");
50005                                 return -1;
50006                         }
50007                 }
50008 -               
50009 +
50010                 if (srv->srvconf.groupname->used) {
50011                         if (NULL == (grp = getgrnam(srv->srvconf.groupname->ptr))) {
50012 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
50013 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
50014                                         "can't find groupname", srv->srvconf.groupname);
50015                                 return -1;
50016                         }
50017 @@ -713,15 +1083,15 @@
50018                                 return -1;
50019                         }
50020                 }
50021 -#endif         
50022 +#endif
50023                 /* we need root-perms for port < 1024 */
50024                 if (0 != network_init(srv)) {
50025                         plugins_free(srv);
50026                         server_free(srv);
50027 -                       
50028 +
50029                         return -1;
50030                 }
50031 -#ifdef HAVE_CHROOT     
50032 +#ifdef HAVE_CHROOT
50033                 if (srv->srvconf.changeroot->used) {
50034                         tzset();
50035  
50036 @@ -761,7 +1131,7 @@
50037                 }
50038  
50039                 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50040 -                       srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200;
50041 +                       srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 4 ? rlim.rlim_cur : FD_SETSIZE - 4;
50042                 } else {
50043                         srv->max_fds = rlim.rlim_cur;
50044                 }
50045 @@ -775,18 +1145,18 @@
50046  #endif
50047                 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50048                         /* don't raise the limit above FD_SET_SIZE */
50049 -                       if (srv->max_fds > FD_SETSIZE - 200) {
50050 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
50051 -                                               "can't raise max filedescriptors above",  FD_SETSIZE - 200,
50052 +                       if (srv->max_fds > FD_SETSIZE - 4) {
50053 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
50054 +                                               "can't raise max filedescriptors above",  FD_SETSIZE - 4,
50055                                                 "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds.");
50056                                 return -1;
50057                         }
50058                 }
50059 -               
50060 +
50061                 if (0 != network_init(srv)) {
50062                         plugins_free(srv);
50063                         server_free(srv);
50064 -                       
50065 +
50066                         return -1;
50067                 }
50068         }
50069 @@ -802,25 +1172,27 @@
50070                 /* or use the default */
50071                 srv->max_conns = srv->max_fds;
50072         }
50073 -       
50074 +
50075         if (HANDLER_GO_ON != plugins_call_init(srv)) {
50076                 log_error_write(srv, __FILE__, __LINE__, "s", "Initialization of plugins failed. Going down.");
50077 -               
50078 +
50079                 plugins_free(srv);
50080                 network_close(srv);
50081                 server_free(srv);
50082 -               
50083 +
50084                 return -1;
50085         }
50086  
50087 -#ifdef HAVE_FORK       
50088 +#ifdef HAVE_FORK
50089         /* network is up, let's deamonize ourself */
50090         if (srv->srvconf.dont_daemonize == 0) daemonize();
50091  #endif
50092  
50093 +#ifdef HAVE_PWD_H
50094         srv->gid = getgid();
50095         srv->uid = getuid();
50096 -       
50097 +#endif
50098 +
50099         /* write pid file */
50100         if (pid_fd != -1) {
50101                 buffer_copy_long(srv->tmp_buf, getpid());
50102 @@ -829,17 +1201,17 @@
50103                 close(pid_fd);
50104                 pid_fd = -1;
50105         }
50106 -       
50107 +
50108         if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) {
50109                 log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down.");
50110 -               
50111 +
50112                 plugins_free(srv);
50113                 network_close(srv);
50114                 server_free(srv);
50115 -               
50116 +
50117                 return -1;
50118         }
50119 -       
50120 +
50121         /* dump unused config-keys */
50122         for (i = 0; i < srv->config_context->used; i++) {
50123                 array *config = ((data_config *)srv->config_context->data[i])->value;
50124 @@ -847,43 +1219,42 @@
50125  
50126                 for (j = 0; config && j < config->used; j++) {
50127                         data_unset *du = config->data[j];
50128 -                       
50129 +
50130                         /* all var.* is known as user defined variable */
50131                         if (strncmp(du->key->ptr, "var.", sizeof("var.") - 1) == 0) {
50132                                 continue;
50133                         }
50134  
50135                         if (NULL == array_get_element(srv->config_touched, du->key->ptr)) {
50136 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
50137 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
50138                                                 "WARNING: unknown config-key:",
50139                                                 du->key,
50140                                                 "(ignored)");
50141                         }
50142                 }
50143         }
50144 -       
50145 +
50146         if (srv->config_deprecated) {
50147 -               log_error_write(srv, __FILE__, __LINE__, "s", 
50148 +               log_error_write(srv, __FILE__, __LINE__, "s",
50149                                 "Configuration contains deprecated keys. Going down.");
50150 -               
50151 +
50152                 plugins_free(srv);
50153                 network_close(srv);
50154                 server_free(srv);
50155 -               
50156 +
50157                 return -1;
50158         }
50159 -       
50160 -       if (-1 == log_error_open(srv)) {
50161 -               log_error_write(srv, __FILE__, __LINE__, "s", 
50162 +
50163 +       if (-1 == log_error_open(srv->srvconf.errorlog_file, srv->srvconf.errorlog_use_syslog)) {
50164 +               log_error_write(srv, __FILE__, __LINE__, "s",
50165                                 "opening errorlog failed, dying");
50166 -               
50167 +
50168                 plugins_free(srv);
50169                 network_close(srv);
50170                 server_free(srv);
50171                 return -1;
50172         }
50173 -       
50174 -       
50175 +
50176  #ifdef HAVE_SIGACTION
50177         memset(&act, 0, sizeof(act));
50178         act.sa_handler = SIG_IGN;
50179 @@ -903,7 +1274,7 @@
50180         sigaction(SIGHUP,  &act, NULL);
50181         sigaction(SIGALRM, &act, NULL);
50182         sigaction(SIGCHLD, &act, NULL);
50183 -       
50184 +
50185  #elif defined(HAVE_SIGNAL)
50186         /* ignore the SIGPIPE from sendfile() */
50187         signal(SIGPIPE, SIG_IGN);
50188 @@ -914,20 +1285,20 @@
50189         signal(SIGCHLD,  signal_handler);
50190         signal(SIGINT,  signal_handler);
50191  #endif
50192 -       
50193 +
50194  #ifdef USE_ALARM
50195         signal(SIGALRM, signal_handler);
50196 -       
50197 +
50198         /* setup periodic timer (1 second) */
50199         if (setitimer(ITIMER_REAL, &interval, NULL)) {
50200                 log_error_write(srv, __FILE__, __LINE__, "s", "setting timer failed");
50201                 return -1;
50202         }
50203 -       
50204 +
50205         getitimer(ITIMER_REAL, &interval);
50206  #endif
50207  
50208 -#ifdef HAVE_FORK       
50209 +#ifdef HAVE_FORK
50210         /* start watcher and workers */
50211         num_childs = srv->srvconf.max_worker;
50212         if (num_childs > 0) {
50213 @@ -957,13 +1328,13 @@
50214         }
50215  #endif
50216  
50217 -       if (NULL == (srv->ev = fdevent_init(srv->max_fds + 1, srv->event_handler))) {
50218 +       if (NULL == (srv->ev = fdevent_init(/*srv->max_fds + 1*/ 4096, srv->event_handler))) {
50219                 log_error_write(srv, __FILE__, __LINE__,
50220                                 "s", "fdevent_init failed");
50221                 return -1;
50222         }
50223 -       /* 
50224 -        * kqueue() is called here, select resets its internals, 
50225 +       /*
50226 +        * kqueue() is called here, select resets its internals,
50227          * all server sockets get their handlers
50228          *
50229          * */
50230 @@ -971,7 +1342,7 @@
50231                 plugins_free(srv);
50232                 network_close(srv);
50233                 server_free(srv);
50234 -               
50235 +
50236                 return -1;
50237         }
50238  
50239 @@ -986,17 +1357,17 @@
50240         /* setup FAM */
50241         if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) {
50242                 if (0 != FAMOpen2(srv->stat_cache->fam, "lighttpd")) {
50243 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
50244 +                       log_error_write(srv, __FILE__, __LINE__, "s",
50245                                          "could not open a fam connection, dieing.");
50246                         return -1;
50247                 }
50248  #ifdef HAVE_FAMNOEXISTS
50249                 FAMNoExists(srv->stat_cache->fam);
50250  #endif
50251 +               srv->stat_cache->sock->fd = FAMCONNECTION_GETFD(srv->stat_cache->fam);
50252  
50253 -               srv->stat_cache->fam_fcce_ndx = -1;
50254 -               fdevent_register(srv->ev, FAMCONNECTION_GETFD(srv->stat_cache->fam), stat_cache_handle_fdevent, NULL);
50255 -               fdevent_event_add(srv->ev, &(srv->stat_cache->fam_fcce_ndx), FAMCONNECTION_GETFD(srv->stat_cache->fam), FDEVENT_IN);
50256 +               fdevent_register(srv->ev, srv->stat_cache->sock, stat_cache_handle_fdevent, NULL);
50257 +               fdevent_event_add(srv->ev, srv->stat_cache->sock, FDEVENT_IN);
50258         }
50259  #endif
50260  
50261 @@ -1007,330 +1378,34 @@
50262  
50263         for (i = 0; i < srv->srv_sockets.used; i++) {
50264                 server_socket *srv_socket = srv->srv_sockets.ptr[i];
50265 -               if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->fd)) {
50266 +               if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->sock)) {
50267                         log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno));
50268                         return -1;
50269                 }
50270         }
50271  
50272 -       /* main-loop */
50273 -       while (!srv_shutdown) {
50274 -               int n;
50275 -               size_t ndx;
50276 -               time_t min_ts;
50277 -               
50278 -               if (handle_sig_hup) {
50279 -                       handler_t r;
50280 -                       
50281 -                       /* reset notification */
50282 -                       handle_sig_hup = 0;
50283 -                       
50284 -                       
50285 -                       /* cycle logfiles */
50286 -                       
50287 -                       switch(r = plugins_call_handle_sighup(srv)) {
50288 -                       case HANDLER_GO_ON:
50289 -                               break;
50290 -                       default:
50291 -                               log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r);
50292 -                               break;
50293 -                       }
50294 -                       
50295 -                       if (-1 == log_error_cycle(srv)) {
50296 -                               log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying");
50297 -                               
50298 -                               return -1;
50299 -                       }
50300 -               }
50301 -               
50302 -               if (handle_sig_alarm) {
50303 -                       /* a new second */
50304 -                       
50305 -#ifdef USE_ALARM
50306 -                       /* reset notification */
50307 -                       handle_sig_alarm = 0;
50308 -#endif
50309 -                       
50310 -                       /* get current time */
50311 -                       min_ts = time(NULL);
50312 -                       
50313 -                       if (min_ts != srv->cur_ts) {
50314 -                               int cs = 0;
50315 -                               connections *conns = srv->conns;
50316 -                               handler_t r;
50317 -                               
50318 -                               switch(r = plugins_call_handle_trigger(srv)) {
50319 -                               case HANDLER_GO_ON:
50320 -                                       break;
50321 -                               case HANDLER_ERROR:
50322 -                                       log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed");
50323 -                                       break;
50324 -                               default:
50325 -                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
50326 -                                       break;
50327 -                               }
50328 -                               
50329 -                               /* trigger waitpid */
50330 -                               srv->cur_ts = min_ts;
50331 -                       
50332 -                               /* cleanup stat-cache */        
50333 -                               stat_cache_trigger_cleanup(srv);
50334 -                               /**
50335 -                                * check all connections for timeouts 
50336 -                                * 
50337 -                                */
50338 -                               for (ndx = 0; ndx < conns->used; ndx++) {
50339 -                                       int changed = 0;
50340 -                                       connection *con;
50341 -                                       int t_diff;
50342 -                                       
50343 -                                       con = conns->ptr[ndx];
50344 -
50345 -                                       if (con->state == CON_STATE_READ ||
50346 -                                           con->state == CON_STATE_READ_POST) {
50347 -                                               if (con->request_count == 1) {
50348 -                                                       if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
50349 -                                                               /* time - out */
50350 -#if 0
50351 -                                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
50352 -                                                                               "connection closed - read-timeout:", con->fd);
50353 -#endif
50354 -                                                               connection_set_state(srv, con, CON_STATE_ERROR);
50355 -                                                               changed = 1;
50356 -                                                       }
50357 -                                               } else {
50358 -                                                       if (srv->cur_ts - con->read_idle_ts > con->conf.max_keep_alive_idle) {
50359 -                                                               /* time - out */
50360 -#if 0
50361 -                                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
50362 -                                                                               "connection closed - read-timeout:", con->fd);
50363 -#endif
50364 -                                                               connection_set_state(srv, con, CON_STATE_ERROR);
50365 -                                                               changed = 1;
50366 -                                                       }
50367 -                                               }
50368 -                                       }
50369 -                                       
50370 -                                       if ((con->state == CON_STATE_WRITE) &&
50371 -                                           (con->write_request_ts != 0)) { 
50372 -#if 0
50373 -                                               if (srv->cur_ts - con->write_request_ts > 60) {
50374 -                                                       log_error_write(srv, __FILE__, __LINE__, "sdd", 
50375 -                                                                       "connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts);
50376 -                                               }
50377 -#endif
50378 -                                               
50379 -                                               if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) {
50380 -                                                       /* time - out */
50381 -#if 1
50382 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbsosds", 
50383 -                                                                       "NOTE: a request for",
50384 -                                                                       con->request.uri,
50385 -                                                                       "timed out after writing",
50386 -                                                                       con->bytes_written,
50387 -                                                                       "bytes. We waited",
50388 -                                                                       (int)con->conf.max_write_idle,
50389 -                                                                       "seconds. If this a problem increase server.max-write-idle");
50390 -#endif
50391 -                                                       connection_set_state(srv, con, CON_STATE_ERROR);
50392 -                                                       changed = 1;
50393 -                                               }
50394 -                                       }
50395 -                                       /* we don't like div by zero */
50396 -                                       if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1;
50397 -       
50398 -                                       if (con->traffic_limit_reached && 
50399 -                                           (con->conf.kbytes_per_second == 0 || 
50400 -                                            ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) {
50401 -                                               /* enable connection again */
50402 -                                               con->traffic_limit_reached = 0;
50403 -                                               
50404 -                                               changed = 1;
50405 -                                       }
50406 -                                       
50407 -                                       if (changed) {
50408 -                                               connection_state_machine(srv, con);
50409 -                                       }
50410 -                                       con->bytes_written_cur_second = 0;
50411 -                                       *(con->conf.global_bytes_per_second_cnt_ptr) = 0;
50412 -                                       
50413 -#if 0
50414 -                                       if (cs == 0) {
50415 -                                               fprintf(stderr, "connection-state: ");
50416 -                                               cs = 1;
50417 -                                       }
50418 -                                       
50419 -                                       fprintf(stderr, "c[%d,%d]: %s ",
50420 -                                               con->fd,
50421 -                                               con->fcgi.fd,
50422 -                                               connection_get_state(con->state));
50423 -#endif
50424 -                               }
50425 -                               
50426 -                               if (cs == 1) fprintf(stderr, "\n");
50427 -                       }
50428 -               }
50429 -
50430 -               if (srv->sockets_disabled) {
50431 -                       /* our server sockets are disabled, why ? */
50432 -
50433 -                       if ((srv->cur_fds + srv->want_fds < srv->max_fds * 0.8) && /* we have enough unused fds */
50434 -                           (srv->conns->used < srv->max_conns * 0.9) &&
50435 -                           (0 == graceful_shutdown)) {
50436 -                               for (i = 0; i < srv->srv_sockets.used; i++) {
50437 -                                       server_socket *srv_socket = srv->srv_sockets.ptr[i];
50438 -                                       fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
50439 -                               }
50440 -                       
50441 -                               log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again");
50442 -                       
50443 -                               srv->sockets_disabled = 0;
50444 -                       }
50445 -               } else {
50446 -                       if ((srv->cur_fds + srv->want_fds > srv->max_fds * 0.9) || /* out of fds */
50447 -                           (srv->conns->used > srv->max_conns) || /* out of connections */
50448 -                           (graceful_shutdown)) { /* graceful_shutdown */ 
50449 -
50450 -                               /* disable server-fds */
50451 -                       
50452 -                               for (i = 0; i < srv->srv_sockets.used; i++) {
50453 -                                       server_socket *srv_socket = srv->srv_sockets.ptr[i];
50454 -                                       fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
50455 -
50456 -                                       if (graceful_shutdown) {
50457 -                                               /* we don't want this socket anymore,
50458 -                                                *
50459 -                                                * closing it right away will make it possible for
50460 -                                                * the next lighttpd to take over (graceful restart)
50461 -                                                *  */
50462 -
50463 -                                               fdevent_unregister(srv->ev, srv_socket->fd);
50464 -                                               close(srv_socket->fd);
50465 -                                               srv_socket->fd = -1;
50466 -
50467 -                                               /* network_close() will cleanup after us */
50468 -                                       }
50469 -                               }
50470 -               
50471 -                               if (graceful_shutdown) {
50472 -                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started");
50473 -                               } else if (srv->conns->used > srv->max_conns) {
50474 -                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached");
50475 -                               } else {
50476 -                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds");
50477 -                               }
50478 -                       
50479 -                               srv->sockets_disabled = 1;
50480 -                       }
50481 -               }
50482 -
50483 -               if (graceful_shutdown && srv->conns->used == 0) {
50484 -                       /* we are in graceful shutdown phase and all connections are closed
50485 -                        * we are ready to terminate without harming anyone */
50486 -                       srv_shutdown = 1;
50487 -               }
50488 -               
50489 -               /* we still have some fds to share */
50490 -               if (srv->want_fds) { 
50491 -                       /* check the fdwaitqueue for waiting fds */
50492 -                       int free_fds = srv->max_fds - srv->cur_fds - 16;
50493 -                       connection *con;
50494 -                       
50495 -                       for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) {
50496 -                               connection_state_machine(srv, con);
50497 -                               
50498 -                               srv->want_fds--;
50499 -                       }
50500 -               }
50501 +       lighty_mainloop(srv);
50502  
50503 -               if ((n = fdevent_poll(srv->ev, 1000)) > 0) {
50504 -                       /* n is the number of events */
50505 -                       int revents;
50506 -                       int fd_ndx;
50507 -#if 0
50508 -                       if (n > 0) {
50509 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
50510 -                                               "polls:", n);
50511 -                       }
50512 -#endif                 
50513 -                       fd_ndx = -1;
50514 -                       do {
50515 -                               fdevent_handler handler;
50516 -                               void *context;
50517 -                               handler_t r;
50518 -                               
50519 -                               fd_ndx  = fdevent_event_next_fdndx (srv->ev, fd_ndx);
50520 -                               revents = fdevent_event_get_revent (srv->ev, fd_ndx);
50521 -                               fd      = fdevent_event_get_fd     (srv->ev, fd_ndx);
50522 -                               handler = fdevent_get_handler(srv->ev, fd);
50523 -                               context = fdevent_get_context(srv->ev, fd);
50524 -                               
50525 -                               /* connection_handle_fdevent needs a joblist_append */
50526 -#if 0
50527 -                               log_error_write(srv, __FILE__, __LINE__, "sdd", 
50528 -                                               "event for", fd, revents);
50529 -#endif                         
50530 -                               switch (r = (*handler)(srv, context, revents)) {
50531 -                               case HANDLER_FINISHED:
50532 -                               case HANDLER_GO_ON:
50533 -                               case HANDLER_WAIT_FOR_EVENT:
50534 -                               case HANDLER_WAIT_FOR_FD:
50535 -                                       break;
50536 -                               case HANDLER_ERROR:
50537 -                                       /* should never happen */
50538 -                                       SEGFAULT();
50539 -                                       break;
50540 -                               default:
50541 -                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
50542 -                                       break;
50543 -                               }
50544 -                       } while (--n > 0);
50545 -               } else if (n < 0 && errno != EINTR) {
50546 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
50547 -                                       "fdevent_poll failed:", 
50548 -                                       strerror(errno));
50549 -               }
50550 -               
50551 -               for (ndx = 0; ndx < srv->joblist->used; ndx++) {
50552 -                       connection *con = srv->joblist->ptr[ndx];
50553 -                       handler_t r;
50554 -                       
50555 -                       connection_state_machine(srv, con);
50556 -                       
50557 -                       switch(r = plugins_call_handle_joblist(srv, con)) {
50558 -                       case HANDLER_FINISHED:
50559 -                       case HANDLER_GO_ON:
50560 -                               break;
50561 -                       default:
50562 -                               log_error_write(srv, __FILE__, __LINE__, "d", r);
50563 -                               break;
50564 -                       }
50565 -                       
50566 -                       con->in_joblist = 0;
50567 -               }
50568 -               
50569 -               srv->joblist->used = 0;
50570 -       }
50571 -       
50572 -       if (srv->srvconf.pid_file->used &&
50573 +       if (0 == graceful_restart &&
50574 +           srv->srvconf.pid_file->used &&
50575             srv->srvconf.changeroot->used == 0) {
50576                 if (0 != unlink(srv->srvconf.pid_file->ptr)) {
50577                         if (errno != EACCES && errno != EPERM) {
50578 -                               log_error_write(srv, __FILE__, __LINE__, "sbds", 
50579 -                                               "unlink failed for:", 
50580 +                               log_error_write(srv, __FILE__, __LINE__, "sbds",
50581 +                                               "unlink failed for:",
50582                                                 srv->srvconf.pid_file,
50583                                                 errno,
50584                                                 strerror(errno));
50585                         }
50586                 }
50587         }
50588 -       
50589 +
50590         /* clean-up */
50591 -       log_error_close(srv);
50592         network_close(srv);
50593         connections_free(srv);
50594         plugins_free(srv);
50595         server_free(srv);
50596 -       
50597 +       log_free();
50598 +
50599         return 0;
50600  }
50601 --- ../lighttpd-1.4.11/src/settings.h   2005-08-11 01:26:41.000000000 +0300
50602 +++ lighttpd-1.4.12/src/settings.h      2006-07-16 00:26:04.000000000 +0300
50603 @@ -9,24 +9,24 @@
50604  /**
50605   * max size of a buffer which will just be reset
50606   * to ->used = 0 instead of really freeing the buffer
50607 - * 
50608 + *
50609   * 64kB (no real reason, just a guess)
50610   */
50611  #define BUFFER_MAX_REUSE_SIZE  (4 * 1024)
50612  
50613  /**
50614   * max size of the HTTP request header
50615 - * 
50616 + *
50617   * 32k should be enough for everything (just a guess)
50618 - * 
50619 + *
50620   */
50621  #define MAX_HTTP_REQUEST_HEADER  (32 * 1024)
50622  
50623 -typedef enum { HANDLER_UNSET, 
50624 -               HANDLER_GO_ON, 
50625 +typedef enum { HANDLER_UNSET,
50626 +               HANDLER_GO_ON,
50627                 HANDLER_FINISHED,
50628 -               HANDLER_COMEBACK, 
50629 -               HANDLER_WAIT_FOR_EVENT, 
50630 +               HANDLER_COMEBACK,
50631 +               HANDLER_WAIT_FOR_EVENT,
50632                 HANDLER_ERROR,
50633                 HANDLER_WAIT_FOR_FD
50634  } handler_t;
50635 --- ../lighttpd-1.4.11/src/spawn-fcgi.c 2006-03-07 14:18:10.000000000 +0200
50636 +++ lighttpd-1.4.12/src/spawn-fcgi.c    2006-07-16 00:26:04.000000000 +0300
50637 @@ -1,19 +1,16 @@
50638  #include <sys/types.h>
50639 -#include <sys/time.h>
50640  #include <sys/stat.h>
50641  
50642  #include <stdlib.h>
50643  #include <string.h>
50644  #include <errno.h>
50645  #include <stdio.h>
50646 -#include <unistd.h>
50647  #include <fcntl.h>
50648 -
50649 +#include <time.h>
50650  #ifdef HAVE_CONFIG_H
50651  #include "config.h"
50652  #endif
50653  
50654 -
50655  #ifdef HAVE_PWD_H
50656  #include <grp.h>
50657  #include <pwd.h>
50658 @@ -30,6 +27,7 @@
50659  #endif
50660  
50661  #include "sys-socket.h"
50662 +#include "sys-files.h"
50663  
50664  #ifdef HAVE_SYS_WAIT_H
50665  #include <sys/wait.h>
50666 @@ -45,28 +43,28 @@
50667         int fcgi_fd;
50668         int socket_type, status;
50669         struct timeval tv = { 0, 100 * 1000 };
50670 -       
50671 +
50672         struct sockaddr_un fcgi_addr_un;
50673         struct sockaddr_in fcgi_addr_in;
50674         struct sockaddr *fcgi_addr;
50675 -       
50676 +
50677         socklen_t servlen;
50678 -       
50679 +
50680         if (child_count < 2) {
50681                 child_count = 5;
50682         }
50683 -       
50684 +
50685         if (child_count > 256) {
50686                 child_count = 256;
50687         }
50688 -       
50689 -       
50690 +
50691 +
50692         if (unixsocket) {
50693                 memset(&fcgi_addr, 0, sizeof(fcgi_addr));
50694 -               
50695 +
50696                 fcgi_addr_un.sun_family = AF_UNIX;
50697                 strcpy(fcgi_addr_un.sun_path, unixsocket);
50698 -               
50699 +
50700  #ifdef SUN_LEN
50701                 servlen = SUN_LEN(&fcgi_addr_un);
50702  #else
50703 @@ -84,50 +82,50 @@
50704                  }
50705                 fcgi_addr_in.sin_port = htons(port);
50706                 servlen = sizeof(fcgi_addr_in);
50707 -               
50708 +
50709                 socket_type = AF_INET;
50710                 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
50711         }
50712 -       
50713 +
50714         if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
50715 -               fprintf(stderr, "%s.%d\n", 
50716 +               fprintf(stderr, "%s.%d\n",
50717                         __FILE__, __LINE__);
50718                 return -1;
50719         }
50720 -       
50721 +
50722         if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
50723                 /* server is not up, spawn in  */
50724                 pid_t child;
50725                 int val;
50726 -               
50727 +
50728                 if (unixsocket) unlink(unixsocket);
50729 -               
50730 +
50731                 close(fcgi_fd);
50732 -               
50733 +
50734                 /* reopen socket */
50735                 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
50736 -                       fprintf(stderr, "%s.%d\n", 
50737 +                       fprintf(stderr, "%s.%d\n",
50738                                 __FILE__, __LINE__);
50739                         return -1;
50740                 }
50741  
50742                 val = 1;
50743                 if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
50744 -                       fprintf(stderr, "%s.%d\n", 
50745 +                       fprintf(stderr, "%s.%d\n",
50746                                 __FILE__, __LINE__);
50747                         return -1;
50748                 }
50749  
50750                 /* create socket */
50751                 if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
50752 -                       fprintf(stderr, "%s.%d: bind failed: %s\n", 
50753 +                       fprintf(stderr, "%s.%d: bind failed: %s\n",
50754                                 __FILE__, __LINE__,
50755                                 strerror(errno));
50756                         return -1;
50757                 }
50758 -               
50759 +
50760                 if (-1 == listen(fcgi_fd, 1024)) {
50761 -                       fprintf(stderr, "%s.%d: fd = -1\n", 
50762 +                       fprintf(stderr, "%s.%d: fd = -1\n",
50763                                 __FILE__, __LINE__);
50764                         return -1;
50765                 }
50766 @@ -137,42 +135,45 @@
50767                 } else {
50768                         child = 0;
50769                 }
50770 -               
50771 +
50772                 switch (child) {
50773                 case 0: {
50774                         char cgi_childs[64];
50775                         char *b;
50776 -                       
50777 +
50778                         int i = 0;
50779 -                       
50780 +
50781 +                       /* loose control terminal */
50782 +                       setsid();
50783 +
50784                         /* is save as we limit to 256 childs */
50785                         sprintf(cgi_childs, "PHP_FCGI_CHILDREN=%d", child_count);
50786 -                       
50787 +
50788                         if(fcgi_fd != FCGI_LISTENSOCK_FILENO) {
50789                                 close(FCGI_LISTENSOCK_FILENO);
50790                                 dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
50791                                 close(fcgi_fd);
50792                         }
50793 -                       
50794 +
50795                         /* we don't need the client socket */
50796                         for (i = 3; i < 256; i++) {
50797                                 close(i);
50798                         }
50799 -                       
50800 +
50801                         /* create environment */
50802 -                       
50803 +
50804                         putenv(cgi_childs);
50805 -                       
50806 +
50807                         /* fork and replace shell */
50808                         b = malloc(strlen("exec ") + strlen(appPath) + 1);
50809                         strcpy(b, "exec ");
50810                         strcat(b, appPath);
50811 -                       
50812 +
50813                         /* exec the cgi */
50814                         execl("/bin/sh", "sh", "-c", b, NULL);
50815 -                       
50816 +
50817                         exit(errno);
50818 -                       
50819 +
50820                         break;
50821                 }
50822                 case -1:
50823 @@ -180,47 +181,47 @@
50824                         break;
50825                 default:
50826                         /* father */
50827 -                       
50828 +
50829                         /* wait */
50830                         select(0, NULL, NULL, NULL, &tv);
50831 -                       
50832 +
50833                         switch (waitpid(child, &status, WNOHANG)) {
50834                         case 0:
50835 -                               fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n", 
50836 +                               fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n",
50837                                         __FILE__, __LINE__,
50838                                         child);
50839 -                               
50840 +
50841                                 /* write pid file */
50842                                 if (pid_fd != -1) {
50843                                         /* assume a 32bit pid_t */
50844                                         char pidbuf[12];
50845 -                                       
50846 +
50847                                         snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child);
50848 -                                       
50849 +
50850                                         write(pid_fd, pidbuf, strlen(pidbuf));
50851                                         close(pid_fd);
50852                                         pid_fd = -1;
50853                                 }
50854 -                               
50855 +
50856                                 break;
50857                         case -1:
50858                                 break;
50859                         default:
50860                                 if (WIFEXITED(status)) {
50861 -                                       fprintf(stderr, "%s.%d: child exited with: %d, %s\n", 
50862 +                                       fprintf(stderr, "%s.%d: child exited with: %d, %s\n",
50863                                                 __FILE__, __LINE__,
50864                                                 WEXITSTATUS(status), strerror(WEXITSTATUS(status)));
50865                                 } else if (WIFSIGNALED(status)) {
50866 -                                       fprintf(stderr, "%s.%d: child signaled: %d\n", 
50867 +                                       fprintf(stderr, "%s.%d: child signaled: %d\n",
50868                                                 __FILE__, __LINE__,
50869                                                 WTERMSIG(status));
50870                                 } else {
50871 -                                       fprintf(stderr, "%s.%d: child died somehow: %d\n", 
50872 +                                       fprintf(stderr, "%s.%d: child died somehow: %d\n",
50873                                                 __FILE__, __LINE__,
50874                                                 status);
50875                                 }
50876                         }
50877 -                               
50878 +
50879                         break;
50880                 }
50881         } else {
50882 @@ -228,16 +229,16 @@
50883                         __FILE__, __LINE__);
50884                 return -1;
50885         }
50886 -       
50887 +
50888         close(fcgi_fd);
50889 -       
50890 +
50891         return 0;
50892  }
50893  
50894  
50895  void show_version () {
50896         char *b = "spawn-fcgi" "-" PACKAGE_VERSION \
50897 -" - spawns fastcgi processes\n" 
50898 +" - spawns fastcgi processes\n"
50899  ;
50900         write(1, b, strlen(b));
50901  }
50902 @@ -265,7 +266,7 @@
50903  
50904  
50905  int main(int argc, char **argv) {
50906 -       char *fcgi_app = NULL, *changeroot = NULL, *username = NULL, 
50907 +       char *fcgi_app = NULL, *changeroot = NULL, *username = NULL,
50908                 *groupname = NULL, *unixsocket = NULL, *pid_file = NULL,
50909                  *addr = NULL;
50910         unsigned short port = 0;
50911 @@ -273,9 +274,9 @@
50912         int i_am_root, o;
50913         int pid_fd = -1;
50914         int nofork = 0;
50915 -       
50916 +
50917         i_am_root = (getuid() == 0);
50918 -       
50919 +
50920         while(-1 != (o = getopt(argc, argv, "c:f:g:hna:p:u:vC:s:P:"))) {
50921                 switch(o) {
50922                 case 'f': fcgi_app = optarg; break;
50923 @@ -290,137 +291,137 @@
50924                 case 'P': pid_file = optarg; /* PID file */ break;
50925                 case 'v': show_version(); return 0;
50926                 case 'h': show_help(); return 0;
50927 -               default: 
50928 +               default:
50929                         show_help();
50930                         return -1;
50931                 }
50932         }
50933 -       
50934 +
50935         if (fcgi_app == NULL || (port == 0 && unixsocket == NULL)) {
50936                 show_help();
50937                 return -1;
50938         }
50939 -           
50940 +
50941         if (unixsocket && port) {
50942 -               fprintf(stderr, "%s.%d: %s\n", 
50943 +               fprintf(stderr, "%s.%d: %s\n",
50944                         __FILE__, __LINE__,
50945                         "either a unix domain socket or a tcp-port, but not both\n");
50946 -               
50947 +
50948                 return -1;
50949         }
50950 -       
50951 +
50952         if (unixsocket && strlen(unixsocket) > UNIX_PATH_MAX - 1) {
50953 -               fprintf(stderr, "%s.%d: %s\n", 
50954 +               fprintf(stderr, "%s.%d: %s\n",
50955                         __FILE__, __LINE__,
50956                         "path of the unix socket is too long\n");
50957 -               
50958 +
50959                 return -1;
50960         }
50961  
50962         /* UID handling */
50963         if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
50964                 /* we are setuid-root */
50965 -               
50966 -               fprintf(stderr, "%s.%d: %s\n", 
50967 +
50968 +               fprintf(stderr, "%s.%d: %s\n",
50969                         __FILE__, __LINE__,
50970                         "Are you nuts ? Don't apply a SUID bit to this binary\n");
50971 -               
50972 +
50973                 return -1;
50974         }
50975 -       
50976 -       if (pid_file && 
50977 +
50978 +       if (pid_file &&
50979             (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)))) {
50980                 struct stat st;
50981                 if (errno != EEXIST) {
50982 -                       fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n", 
50983 +                       fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
50984                                 __FILE__, __LINE__,
50985                                 pid_file, strerror(errno));
50986 -                       
50987 +
50988                         return -1;
50989                 }
50990 -               
50991 +
50992                 /* ok, file exists */
50993 -               
50994 +
50995                 if (0 != stat(pid_file, &st)) {
50996 -                       fprintf(stderr, "%s.%d: stating pid-file '%s' failed: %s\n", 
50997 +                       fprintf(stderr, "%s.%d: stating pid-file '%s' failed: %s\n",
50998                                 __FILE__, __LINE__,
50999                                 pid_file, strerror(errno));
51000 -                       
51001 +
51002                         return -1;
51003                 }
51004 -               
51005 +
51006                 /* is it a regular file ? */
51007 -               
51008 +
51009                 if (!S_ISREG(st.st_mode)) {
51010 -                       fprintf(stderr, "%s.%d: pid-file exists and isn't regular file: '%s'\n", 
51011 +                       fprintf(stderr, "%s.%d: pid-file exists and isn't regular file: '%s'\n",
51012                                 __FILE__, __LINE__,
51013                                 pid_file);
51014 -                       
51015 +
51016                         return -1;
51017                 }
51018 -               
51019 +
51020                 if (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
51021 -                       fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n", 
51022 +                       fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
51023                                 __FILE__, __LINE__,
51024                                 pid_file, strerror(errno));
51025 -                       
51026 +
51027                         return -1;
51028                 }
51029         }
51030 -       
51031 +
51032         if (i_am_root) {
51033                 struct group *grp = NULL;
51034                 struct passwd *pwd = NULL;
51035 -               
51036 +
51037                 /* set user and group */
51038 -               
51039 +
51040                 if (username) {
51041                         if (NULL == (pwd = getpwnam(username))) {
51042 -                               fprintf(stderr, "%s.%d: %s, %s\n", 
51043 +                               fprintf(stderr, "%s.%d: %s, %s\n",
51044                                         __FILE__, __LINE__,
51045                                         "can't find username", username);
51046                                 return -1;
51047                         }
51048 -                       
51049 +
51050                         if (pwd->pw_uid == 0) {
51051 -                               fprintf(stderr, "%s.%d: %s\n", 
51052 +                               fprintf(stderr, "%s.%d: %s\n",
51053                                         __FILE__, __LINE__,
51054                                         "I will not set uid to 0\n");
51055                                 return -1;
51056                         }
51057                 }
51058 -               
51059 +
51060                 if (groupname) {
51061                         if (NULL == (grp = getgrnam(groupname))) {
51062 -                               fprintf(stderr, "%s.%d: %s %s\n", 
51063 +                               fprintf(stderr, "%s.%d: %s %s\n",
51064                                         __FILE__, __LINE__,
51065 -                                       "can't find groupname", 
51066 +                                       "can't find groupname",
51067                                         groupname);
51068                                 return -1;
51069                         }
51070                         if (grp->gr_gid == 0) {
51071 -                               fprintf(stderr, "%s.%d: %s\n", 
51072 +                               fprintf(stderr, "%s.%d: %s\n",
51073                                         __FILE__, __LINE__,
51074                                         "I will not set gid to 0\n");
51075                                 return -1;
51076                         }
51077                 }
51078 -               
51079 +
51080                 if (changeroot) {
51081                         if (-1 == chroot(changeroot)) {
51082 -                               fprintf(stderr, "%s.%d: %s %s\n", 
51083 +                               fprintf(stderr, "%s.%d: %s %s\n",
51084                                         __FILE__, __LINE__,
51085                                         "chroot failed: ", strerror(errno));
51086                                 return -1;
51087                         }
51088                         if (-1 == chdir("/")) {
51089 -                               fprintf(stderr, "%s.%d: %s %s\n", 
51090 +                               fprintf(stderr, "%s.%d: %s %s\n",
51091                                         __FILE__, __LINE__,
51092                                         "chdir failed: ", strerror(errno));
51093                                 return -1;
51094                         }
51095                 }
51096 -               
51097 +
51098                 /* drop root privs */
51099                 if (groupname) {
51100                         setgid(grp->gr_gid);
51101 @@ -428,7 +429,7 @@
51102                 }
51103                 if (username) setuid(pwd->pw_uid);
51104         }
51105 -       
51106 +
51107         return fcgi_spawn_connection(fcgi_app, addr, port, unixsocket, child_count, pid_fd, nofork);
51108  }
51109  #else
51110 --- ../lighttpd-1.4.11/src/splaytree.c  2005-09-12 21:51:28.000000000 +0300
51111 +++ lighttpd-1.4.12/src/splaytree.c     2006-07-16 00:26:03.000000000 +0300
51112 @@ -56,19 +56,19 @@
51113  
51114  #define node_size splaytree_size
51115  
51116 -/* Splay using the key i (which may or may not be in the tree.) 
51117 - * The starting root is t, and the tree used is defined by rat 
51118 +/* Splay using the key i (which may or may not be in the tree.)
51119 + * The starting root is t, and the tree used is defined by rat
51120   * size fields are maintained */
51121  splay_tree * splaytree_splay (splay_tree *t, int i) {
51122      splay_tree N, *l, *r, *y;
51123      int comp, root_size, l_size, r_size;
51124 -    
51125 +
51126      if (t == NULL) return t;
51127      N.left = N.right = NULL;
51128      l = r = &N;
51129      root_size = node_size(t);
51130      l_size = r_size = 0;
51131
51132 +
51133      for (;;) {
51134          comp = compare(i, t->key);
51135          if (comp < 0) {
51136 @@ -120,7 +120,7 @@
51137          y->size = r_size;
51138          r_size -= 1+node_size(y->right);
51139      }
51140
51141 +
51142      l->right = t->left;                                /* assemble */
51143      r->left = t->right;
51144      t->left = N.right;
51145 --- ../lighttpd-1.4.11/src/splaytree.h  2005-09-12 21:51:13.000000000 +0300
51146 +++ lighttpd-1.4.12/src/splaytree.h     2006-07-16 00:26:03.000000000 +0300
51147 @@ -19,6 +19,6 @@
51148  /* This macro returns the size of a node.  Unlike "x->size",     */
51149  /* it works even if x=NULL.  The test could be avoided by using  */
51150  /* a special version of NULL which was a real node with size 0.  */
51151
51152 +
51153  
51154  #endif
51155 --- ../lighttpd-1.4.11/src/stat_cache.c 2005-11-22 15:23:51.000000000 +0200
51156 +++ lighttpd-1.4.12/src/stat_cache.c    2006-07-18 13:03:40.000000000 +0300
51157 @@ -6,7 +6,6 @@
51158  #include <stdlib.h>
51159  #include <string.h>
51160  #include <errno.h>
51161 -#include <unistd.h>
51162  #include <stdio.h>
51163  #include <fcntl.h>
51164  #include <assert.h>
51165 @@ -25,19 +24,8 @@
51166  #endif
51167  
51168  #include "sys-mmap.h"
51169 -
51170 -/* NetBSD 1.3.x needs it */
51171 -#ifndef MAP_FAILED
51172 -# define MAP_FAILED -1
51173 -#endif
51174 -
51175 -#ifndef O_LARGEFILE
51176 -# define O_LARGEFILE 0
51177 -#endif
51178 -
51179 -#ifndef HAVE_LSTAT
51180 -#define lstat stat
51181 -#endif
51182 +#include "sys-files.h"
51183 +#include "sys-strings.h"
51184  
51185  #if 0
51186  /* enables debug code for testing if all nodes in the stat-cache as accessable */
51187 @@ -52,8 +40,8 @@
51188   *
51189   * if we get a change-event from FAM, we increment the version in the FAM->dir mapping
51190   *
51191 - * if the stat()-cache is queried we check if the version id for the directory is the 
51192 - * same and return immediatly. 
51193 + * if the stat()-cache is queried we check if the version id for the directory is the
51194 + * same and return immediatly.
51195   *
51196   *
51197   * What we need:
51198 @@ -62,17 +50,17 @@
51199   * - for each FAMRequest we have to find the version in the directory cache (index as userdata)
51200   *
51201   * stat <<-> directory <-> FAMRequest
51202 - * 
51203 - * if file is deleted, directory is dirty, file is rechecked ... 
51204 + *
51205 + * if file is deleted, directory is dirty, file is rechecked ...
51206   * if directory is deleted, directory mapping is removed
51207 - *  
51208 + *
51209   * */
51210  
51211  #ifdef HAVE_FAM_H
51212  typedef struct {
51213         FAMRequest *req;
51214         FAMConnection *fc;
51215 -       
51216 +
51217         buffer *name;
51218  
51219         int version;
51220 @@ -83,16 +71,16 @@
51221   * - we need a hash
51222   * - the hash-key is used as sorting criteria for a tree
51223   * - a splay-tree is used as we can use the caching effect of it
51224 - */ 
51225 + */
51226  
51227  /* we want to cleanup the stat-cache every few seconds, let's say 10
51228   *
51229   * - remove entries which are outdated since 30s
51230   * - remove entries which are fresh but havn't been used since 60s
51231   * - if we don't have a stat-cache entry for a directory, release it from the monitor
51232 - */ 
51233 + */
51234  
51235 -#ifdef DEBUG_STAT_CACHE        
51236 +#ifdef DEBUG_STAT_CACHE
51237  typedef struct {
51238         int *ptr;
51239  
51240 @@ -105,15 +93,16 @@
51241  
51242  stat_cache *stat_cache_init(void) {
51243         stat_cache *fc = NULL;
51244 -       
51245 +
51246         fc = calloc(1, sizeof(*fc));
51247 -       
51248 +
51249         fc->dir_name = buffer_init();
51250  #ifdef HAVE_FAM_H
51251         fc->fam = calloc(1, sizeof(*fc->fam));
51252 +       fc->sock = iosocket_init();
51253  #endif
51254  
51255 -#ifdef DEBUG_STAT_CACHE        
51256 +#ifdef DEBUG_STAT_CACHE
51257         ctrl.size = 0;
51258  #endif
51259  
51260 @@ -122,24 +111,24 @@
51261  
51262  static stat_cache_entry * stat_cache_entry_init(void) {
51263         stat_cache_entry *sce = NULL;
51264 -       
51265 +
51266         sce = calloc(1, sizeof(*sce));
51267 -       
51268 +
51269         sce->name = buffer_init();
51270         sce->etag = buffer_init();
51271         sce->content_type = buffer_init();
51272 -       
51273 +
51274         return sce;
51275  }
51276  
51277  static void stat_cache_entry_free(void *data) {
51278         stat_cache_entry *sce = data;
51279         if (!sce) return;
51280 -       
51281 +
51282         buffer_free(sce->etag);
51283         buffer_free(sce->name);
51284         buffer_free(sce->content_type);
51285 -       
51286 +
51287         free(sce);
51288  }
51289  
51290 @@ -148,22 +137,22 @@
51291         fam_dir_entry *fam_dir = NULL;
51292  
51293         fam_dir = calloc(1, sizeof(*fam_dir));
51294 -       
51295 +
51296         fam_dir->name = buffer_init();
51297 -       
51298 +
51299         return fam_dir;
51300  }
51301  
51302  static void fam_dir_entry_free(void *data) {
51303         fam_dir_entry *fam_dir = data;
51304 -       
51305 +
51306         if (!fam_dir) return;
51307 -       
51308 +
51309         FAMCancelMonitor(fam_dir->fc, fam_dir->req);
51310 -       
51311 +
51312         buffer_free(fam_dir->name);
51313         free(fam_dir->req);
51314 -       
51315 +
51316         free(fam_dir);
51317  }
51318  #endif
51319 @@ -174,7 +163,7 @@
51320                 splay_tree *node = sc->files;
51321  
51322                 osize = sc->files->size;
51323 -                       
51324 +
51325                 stat_cache_entry_free(node->data);
51326                 sc->files = splaytree_delete(sc->files, node->key);
51327  
51328 @@ -187,12 +176,12 @@
51329         while (sc->dirs) {
51330                 int osize;
51331                 splay_tree *node = sc->dirs;
51332 -               
51333 +
51334                 osize = sc->dirs->size;
51335  
51336                 fam_dir_entry_free(node->data);
51337                 sc->dirs = splaytree_delete(sc->dirs, node->key);
51338 -               
51339 +
51340                 if (osize == 1) {
51341                         assert(NULL == sc->dirs);
51342                 } else {
51343 @@ -202,6 +191,7 @@
51344  
51345         if (sc->fam) {
51346                 FAMClose(sc->fam);
51347 +               iosocket_free(sc->sock);
51348                 free(sc->fam);
51349         }
51350  #endif
51351 @@ -212,7 +202,7 @@
51352  static int stat_cache_attr_get(buffer *buf, char *name) {
51353         int attrlen;
51354         int ret;
51355 -       
51356 +
51357         attrlen = 1024;
51358         buffer_prepare_copy(buf, attrlen);
51359         attrlen--;
51360 @@ -251,15 +241,15 @@
51361             sc->fam) {
51362  
51363                 events = FAMPending(sc->fam);
51364 -       
51365 +
51366                 for (i = 0; i < events; i++) {
51367                         FAMEvent fe;
51368                         fam_dir_entry *fam_dir;
51369                         splay_tree *node;
51370                         int ndx;
51371 -               
51372 +
51373                         FAMNextEvent(sc->fam, &fe);
51374 -       
51375 +
51376                         /* handle event */
51377  
51378                         switch(fe.code) {
51379 @@ -280,7 +270,7 @@
51380  
51381                                 sc->dirs = splaytree_splay(sc->dirs, ndx);
51382                                 node = sc->dirs;
51383 -                       
51384 +
51385                                 if (node && (node->key == ndx)) {
51386                                         int osize = splaytree_size(sc->dirs);
51387  
51388 @@ -298,17 +288,15 @@
51389  
51390         if (revent & FDEVENT_HUP) {
51391                 /* fam closed the connection */
51392 -               srv->stat_cache->fam_fcce_ndx = -1;
51393 -
51394 -               fdevent_event_del(srv->ev, &(sc->fam_fcce_ndx), FAMCONNECTION_GETFD(sc->fam));
51395 -               fdevent_unregister(srv->ev, FAMCONNECTION_GETFD(sc->fam));
51396 +               fdevent_event_del(srv->ev, sc->sock);
51397 +               fdevent_unregister(srv->ev, sc->sock);
51398  
51399                 FAMClose(sc->fam);
51400                 free(sc->fam);
51401  
51402                 sc->fam = NULL;
51403         }
51404 -       
51405 +
51406         return HANDLER_GO_ON;
51407  }
51408  
51409 @@ -332,7 +320,7 @@
51410   *
51411   *
51412   *
51413 - * returns: 
51414 + * returns:
51415   *  - HANDLER_FINISHED on cache-miss (don't forget to reopen the file)
51416   *  - HANDLER_ERROR on stat() failed -> see errno for problem
51417   */
51418 @@ -348,16 +336,16 @@
51419         struct stat st;
51420         size_t k;
51421         int fd;
51422 -#ifdef DEBUG_STAT_CACHE        
51423 +#ifdef DEBUG_STAT_CACHE
51424         size_t i;
51425  #endif
51426  
51427         int file_ndx;
51428         splay_tree *file_node = NULL;
51429  
51430 -       *ret_sce = NULL; 
51431 +       *ret_sce = NULL;
51432  
51433 -       /* 
51434 +       /*
51435          * check if the directory for this file has changed
51436          */
51437  
51438 @@ -366,23 +354,23 @@
51439         file_ndx = hashme(name);
51440         sc->files = splaytree_splay(sc->files, file_ndx);
51441  
51442 -#ifdef DEBUG_STAT_CACHE        
51443 +#ifdef DEBUG_STAT_CACHE
51444         for (i = 0; i < ctrl.used; i++) {
51445                 if (ctrl.ptr[i] == file_ndx) break;
51446         }
51447  #endif
51448  
51449         if (sc->files && (sc->files->key == file_ndx)) {
51450 -#ifdef DEBUG_STAT_CACHE        
51451 +#ifdef DEBUG_STAT_CACHE
51452                 /* it was in the cache */
51453                 assert(i < ctrl.used);
51454  #endif
51455 -               
51456 -               /* we have seen this file already and 
51457 +
51458 +               /* we have seen this file already and
51459                  * don't stat() it again in the same second */
51460  
51461                 file_node = sc->files;
51462 -               
51463 +
51464                 sce = file_node->data;
51465  
51466                 /* check if the name is the same, we might have a collision */
51467 @@ -390,7 +378,7 @@
51468                 if (buffer_is_equal(name, sce->name)) {
51469                         if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_SIMPLE) {
51470                                 if (sce->stat_ts == srv->cur_ts) {
51471 -                                       *ret_sce = sce; 
51472 +                                       *ret_sce = sce;
51473                                         return HANDLER_GO_ON;
51474                                 }
51475                         }
51476 @@ -400,15 +388,15 @@
51477                          * file_node is used by the FAM check below to see if we know this file
51478                          * and if we can save a stat().
51479                          *
51480 -                        * BUT, the sce is not reset here as the entry into the cache is ok, we 
51481 +                        * BUT, the sce is not reset here as the entry into the cache is ok, we
51482                          * it is just not pointing to our requested file.
51483 -                        * 
51484 +                        *
51485                          *  */
51486  
51487                         file_node = NULL;
51488                 }
51489         } else {
51490 -#ifdef DEBUG_STAT_CACHE        
51491 +#ifdef DEBUG_STAT_CACHE
51492                 if (i != ctrl.used) {
51493                         fprintf(stderr, "%s.%d: %08x was already inserted but not found in cache, %s\n", __FILE__, __LINE__, file_ndx, name->ptr);
51494                 }
51495 @@ -424,23 +412,23 @@
51496                 }
51497  
51498                 dir_ndx = hashme(sc->dir_name);
51499 -               
51500 +
51501                 sc->dirs = splaytree_splay(sc->dirs, dir_ndx);
51502 -               
51503 +
51504                 if (sc->dirs && (sc->dirs->key == dir_ndx)) {
51505                         dir_node = sc->dirs;
51506                 }
51507 -               
51508 +
51509                 if (dir_node && file_node) {
51510                         /* we found a file */
51511 -                       
51512 +
51513                         sce = file_node->data;
51514                         fam_dir = dir_node->data;
51515 -                       
51516 +
51517                         if (fam_dir->version == sce->dir_version) {
51518                                 /* the stat()-cache entry is still ok */
51519 -                               
51520 -                               *ret_sce = sce; 
51521 +
51522 +                               *ret_sce = sce;
51523                                 return HANDLER_GO_ON;
51524                         }
51525                 }
51526 @@ -448,7 +436,7 @@
51527  #endif
51528  
51529         /*
51530 -        * *lol* 
51531 +        * *lol*
51532          * - open() + fstat() on a named-pipe results in a (intended) hang.
51533          * - stat() if regualar file + open() to see if we can read from it is better
51534          *
51535 @@ -469,16 +457,16 @@
51536  
51537         if (NULL == sce) {
51538                 int osize = 0;
51539 -                      
51540 +
51541                 if (sc->files) {
51542                         osize = sc->files->size;
51543                 }
51544  
51545                 sce = stat_cache_entry_init();
51546                 buffer_copy_string_buffer(sce->name, name);
51547 -               
51548 -               sc->files = splaytree_insert(sc->files, file_ndx, sce); 
51549 -#ifdef DEBUG_STAT_CACHE        
51550 +
51551 +               sc->files = splaytree_insert(sc->files, file_ndx, sce);
51552 +#ifdef DEBUG_STAT_CACHE
51553                 if (ctrl.size == 0) {
51554                         ctrl.size = 16;
51555                         ctrl.used = 0;
51556 @@ -499,29 +487,29 @@
51557         sce->st = st;
51558         sce->stat_ts = srv->cur_ts;
51559  
51560 -       /* catch the obvious symlinks 
51561 +       /* catch the obvious symlinks
51562          *
51563          * this is not a secure check as we still have a race-condition between
51564 -        * the stat() and the open. We can only solve this by 
51565 +        * the stat() and the open. We can only solve this by
51566          * 1. open() the file
51567          * 2. fstat() the fd
51568          *
51569          * and keeping the file open for the rest of the time. But this can
51570          * only be done at network level.
51571 -        * 
51572 +        *
51573          * */
51574         if (S_ISLNK(st.st_mode) && !con->conf.follow_symlink) {
51575                 return HANDLER_ERROR;
51576         }
51577  
51578 -       if (S_ISREG(st.st_mode)) {      
51579 +       if (S_ISREG(st.st_mode)) {
51580                 /* determine mimetype */
51581                 buffer_reset(sce->content_type);
51582 -               
51583 +
51584                 for (k = 0; k < con->conf.mimetypes->used; k++) {
51585                         data_string *ds = (data_string *)con->conf.mimetypes->data[k];
51586                         buffer *type = ds->key;
51587 -               
51588 +
51589                         if (type->used == 0) continue;
51590  
51591                         /* check if the right side is the same */
51592 @@ -538,8 +526,10 @@
51593                         stat_cache_attr_get(sce->content_type, name->ptr);
51594                 }
51595  #endif
51596 +       } else if (S_ISDIR(st.st_mode)) {
51597 +               etag_create(sce->etag, &(sce->st));
51598         }
51599 -               
51600 +
51601  #ifdef HAVE_FAM_H
51602         if (sc->fam &&
51603             (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM)) {
51604 @@ -549,19 +539,19 @@
51605                         fam_dir->fc = sc->fam;
51606  
51607                         buffer_copy_string_buffer(fam_dir->name, sc->dir_name);
51608 -                       
51609 +
51610                         fam_dir->version = 1;
51611 -                       
51612 +
51613                         fam_dir->req = calloc(1, sizeof(FAMRequest));
51614 -                       
51615 -                       if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr, 
51616 +
51617 +                       if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr,
51618                                                      fam_dir->req, fam_dir)) {
51619 -                               
51620 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
51621 -                                               "monitoring dir failed:", 
51622 -                                               fam_dir->name, 
51623 +
51624 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
51625 +                                               "monitoring dir failed:",
51626 +                                               fam_dir->name,
51627                                                 FamErrlist[FAMErrno]);
51628 -                               
51629 +
51630                                 fam_dir_entry_free(fam_dir);
51631                         } else {
51632                                 int osize = 0;
51633 @@ -570,7 +560,7 @@
51634                                         osize = sc->dirs->size;
51635                                 }
51636  
51637 -                               sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir); 
51638 +                               sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir);
51639                                 assert(sc->dirs);
51640                                 assert(sc->dirs->data == fam_dir);
51641                                 assert(osize == (sc->dirs->size - 1));
51642 @@ -578,9 +568,9 @@
51643                 } else {
51644                         fam_dir = dir_node->data;
51645                 }
51646 -               
51647 +
51648                 /* bind the fam_fc to the stat() cache entry */
51649 -                       
51650 +
51651                 if (fam_dir) {
51652                         sce->dir_version = fam_dir->version;
51653                         sce->dir_ndx     = dir_ndx;
51654 @@ -594,11 +584,11 @@
51655  }
51656  
51657  /**
51658 - * remove stat() from cache which havn't been stat()ed for 
51659 + * remove stat() from cache which havn't been stat()ed for
51660   * more than 10 seconds
51661 - * 
51662   *
51663 - * walk though the stat-cache, collect the ids which are too old 
51664 + *
51665 + * walk though the stat-cache, collect the ids which are too old
51666   * and remove them in a second loop
51667   */
51668  
51669 @@ -639,9 +629,9 @@
51670                 sc->files = splaytree_splay(sc->files, ndx);
51671  
51672                 node = sc->files;
51673 -               
51674 +
51675                 if (node && (node->key == ndx)) {
51676 -#ifdef DEBUG_STAT_CACHE        
51677 +#ifdef DEBUG_STAT_CACHE
51678                         size_t j;
51679                         int osize = splaytree_size(sc->files);
51680                         stat_cache_entry *sce = node->data;
51681 @@ -649,7 +639,7 @@
51682                         stat_cache_entry_free(node->data);
51683                         sc->files = splaytree_delete(sc->files, ndx);
51684  
51685 -#ifdef DEBUG_STAT_CACHE        
51686 +#ifdef DEBUG_STAT_CACHE
51687                         for (j = 0; j < ctrl.used; j++) {
51688                                 if (ctrl.ptr[j] == ndx) {
51689                                         ctrl.ptr[j] = ctrl.ptr[--ctrl.used];
51690 --- ../lighttpd-1.4.11/src/stream.c     2005-09-23 21:50:15.000000000 +0300
51691 +++ lighttpd-1.4.12/src/stream.c        2006-07-16 00:26:04.000000000 +0300
51692 @@ -1,7 +1,6 @@
51693  #include <sys/types.h>
51694  #include <sys/stat.h>
51695  
51696 -#include <unistd.h> 
51697  #include <fcntl.h>
51698  
51699  #include "stream.h"
51700 @@ -10,6 +9,7 @@
51701  #endif
51702  
51703  #include "sys-mmap.h"
51704 +#include "sys-files.h"
51705  
51706  #ifndef O_BINARY
51707  # define O_BINARY 0
51708 @@ -19,39 +19,39 @@
51709         struct stat st;
51710  #ifdef HAVE_MMAP
51711         int fd;
51712 -#elif defined __WIN32
51713 +#elif defined _WIN32
51714         HANDLE *fh, *mh;
51715         void *p;
51716  #endif
51717  
51718         f->start = NULL;
51719 -       
51720 +
51721         if (-1 == stat(fn->ptr, &st)) {
51722                 return -1;
51723         }
51724 -       
51725 +
51726         f->size = st.st_size;
51727  
51728  #ifdef HAVE_MMAP
51729         if (-1 == (fd = open(fn->ptr, O_RDONLY | O_BINARY))) {
51730                 return -1;
51731         }
51732 -       
51733 +
51734         f->start = mmap(0, f->size, PROT_READ, MAP_SHARED, fd, 0);
51735 -       
51736 +
51737         close(fd);
51738 -       
51739 +
51740         if (MAP_FAILED == f->start) {
51741                 return -1;
51742         }
51743  
51744 -#elif defined __WIN32
51745 -       fh = CreateFile(fn->ptr, 
51746 -                       GENERIC_READ, 
51747 -                       FILE_SHARE_READ, 
51748 -                       NULL, 
51749 -                       OPEN_EXISTING, 
51750 -                       FILE_ATTRIBUTE_READONLY, 
51751 +#elif defined _WIN32
51752 +       fh = CreateFile(fn->ptr,
51753 +                       GENERIC_READ,
51754 +                       FILE_SHARE_READ,
51755 +                       NULL,
51756 +                       OPEN_EXISTING,
51757 +                       FILE_ATTRIBUTE_READONLY,
51758                         NULL);
51759  
51760         if (!fh) return -1;
51761 @@ -66,7 +66,7 @@
51762         if (!mh) {
51763                 LPVOID lpMsgBuf;
51764                 FormatMessage(
51765 -                       FORMAT_MESSAGE_ALLOCATE_BUFFER | 
51766 +                       FORMAT_MESSAGE_ALLOCATE_BUFFER |
51767                         FORMAT_MESSAGE_FROM_SYSTEM,
51768                         NULL,
51769                         GetLastError(),
51770 @@ -76,7 +76,7 @@
51771  
51772                 return -1;
51773         }
51774 -       
51775 +
51776         p = MapViewOfFile(mh,
51777                         FILE_MAP_READ,
51778                         0,
51779 @@ -87,9 +87,9 @@
51780  
51781         f->start = p;
51782  #else
51783 -# error no mmap found  
51784 +# error no mmap found
51785  #endif
51786 -       
51787 +
51788         return 0;
51789  }
51790  
51791 --- ../lighttpd-1.4.11/src/sys-files.h  1970-01-01 03:00:00.000000000 +0300
51792 +++ lighttpd-1.4.12/src/sys-files.h     2006-07-16 00:26:04.000000000 +0300
51793 @@ -0,0 +1,67 @@
51794 +#ifndef _SYS_FILES_H_
51795 +#define _SYS_FILES_H_
51796 +
51797 +#define DIR_SEPERATOR_UNIX '/'
51798 +#define DIR_SEPERATOR_WIN '\\'
51799 +
51800 +#ifdef _WIN32
51801 +#include <windows.h>
51802 +#include <io.h>     /* open */
51803 +#include <direct.h> /* chdir */
51804 +
51805 +#include "buffer.h"
51806 +
51807 +#define DIR_SEPERATOR DIR_SEPERATOR_WIN
51808 +
51809 +#define __S_ISTYPE(mode, mask)  (((mode) & _S_IFMT) == (mask))
51810 +
51811 +#define S_ISDIR(mode)    __S_ISTYPE((mode), _S_IFDIR)
51812 +#define S_ISCHR(mode)    __S_ISTYPE((mode), _S_IFCHR)
51813 +#define S_ISBLK(mode)    __S_ISTYPE((mode), _S_IFBLK)
51814 +#define S_ISREG(mode)    __S_ISTYPE((mode), _S_IFREG)
51815 +/* we don't support symlinks */
51816 +#define S_ISLNK(mode)    0
51817 +
51818 +#define lstat stat
51819 +#define mkstemp mktemp
51820 +#define mkdir(x, y) mkdir(x)
51821 +
51822 +struct dirent {
51823 +    const char *d_name;
51824 +};
51825 +
51826 +typedef struct {
51827 +    HANDLE h;
51828 +    WIN32_FIND_DATA finddata;
51829 +    struct dirent dent;
51830 +} DIR;
51831 +
51832 +DIR *opendir(const char *dn);
51833 +struct dirent *readdir(DIR *d);
51834 +void closedir(DIR *d);
51835 +
51836 +buffer *filename_unix2local(buffer *b);
51837 +buffer *pathname_unix2local(buffer *b);
51838 +
51839 +#else
51840 +#include <unistd.h>
51841 +#include <dirent.h>
51842 +
51843 +#define DIR_SEPERATOR DIR_SEPERATOR_UNIX
51844 +
51845 +#define filename_unix2local(x) (x)
51846 +#define pathname_unix2local(x) (x)
51847 +#endif
51848 +
51849 +#define PATHNAME_APPEND_SLASH(x) \
51850 +       if (x->used > 1 && x->ptr[x->used - 2] != DIR_SEPERATOR) { \
51851 +        char sl[2] = { DIR_SEPERATOR, 0 }; \
51852 +        BUFFER_APPEND_STRING_CONST(x, sl); \
51853 +    }
51854 +
51855 +#ifndef O_LARGEFILE
51856 +# define O_LARGEFILE 0
51857 +#endif
51858 +
51859 +#endif
51860 +
51861 --- ../lighttpd-1.4.11/src/sys-mmap.h   2005-08-11 01:26:34.000000000 +0300
51862 +++ lighttpd-1.4.12/src/sys-mmap.h      2006-07-16 00:26:04.000000000 +0300
51863 @@ -1,7 +1,7 @@
51864  #ifndef WIN32_MMAP_H
51865  #define WIN32_MMAP_H
51866  
51867 -#ifdef __WIN32
51868 +#ifdef _WIN32
51869  
51870  #define MAP_FAILED -1
51871  #define PROT_SHARED 0
51872 --- ../lighttpd-1.4.11/src/sys-process.h        1970-01-01 03:00:00.000000000 +0300
51873 +++ lighttpd-1.4.12/src/sys-process.h   2006-07-16 00:26:04.000000000 +0300
51874 @@ -0,0 +1,17 @@
51875 +#ifndef _SYS_PROCESS_H_
51876 +#define _SYS_PROCESS_H_
51877 +
51878 +#ifdef _WIN32
51879 +#include <process.h>
51880 +#define pid_t int
51881 +/* win32 has no fork() */
51882 +#define kill(x, y)
51883 +#define getpid() 0
51884 +
51885 +#else
51886 +#include <sys/wait.h>
51887 +#include <unistd.h>
51888 +#endif
51889 +
51890 +#endif
51891 +
51892 --- ../lighttpd-1.4.11/src/sys-socket.h 2005-08-11 01:26:39.000000000 +0300
51893 +++ lighttpd-1.4.12/src/sys-socket.h    2006-07-18 13:03:40.000000000 +0300
51894 @@ -1,15 +1,26 @@
51895  #ifndef WIN32_SOCKET_H
51896  #define WIN32_SOCKET_H
51897  
51898 -#ifdef __WIN32
51899 +#ifdef _WIN32
51900  
51901  #include <winsock2.h>
51902  
51903  #define ECONNRESET WSAECONNRESET
51904  #define EINPROGRESS WSAEINPROGRESS
51905  #define EALREADY WSAEALREADY
51906 +#define ENOTCONN WSAENOTCONN
51907 +#define EWOULDBLOCK WSAEWOULDBLOCK
51908  #define ioctl ioctlsocket
51909  #define hstrerror(x) ""
51910 +#define STDIN_FILENO 0
51911 +#define STDOUT_FILENO 1
51912 +#define STDERR_FILENO 2
51913 +#define ssize_t int
51914 +
51915 +int inet_aton(const char *cp, struct in_addr *inp);
51916 +#define HAVE_INET_ADDR
51917 +#undef HAVE_INET_ATON
51918 +
51919  #else
51920  #include <sys/socket.h>
51921  #include <sys/ioctl.h>
51922 @@ -18,7 +29,25 @@
51923  #include <sys/un.h>
51924  #include <arpa/inet.h>
51925  
51926 +#ifndef SUN_LEN
51927 +#define SUN_LEN(su) \
51928 +        (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
51929 +#endif
51930 +
51931 +#define closesocket(x) close(x)
51932 +
51933  #include <netdb.h>
51934 +#endif /* !_WIN32 */
51935 +
51936 +typedef union {
51937 +#ifdef HAVE_IPV6
51938 +       struct sockaddr_in6 ipv6;
51939 +#endif
51940 +       struct sockaddr_in ipv4;
51941 +#ifdef HAVE_SYS_UN_H
51942 +       struct sockaddr_un un;
51943  #endif
51944 +       struct sockaddr plain;
51945 +} sock_addr;
51946  
51947  #endif
51948 --- ../lighttpd-1.4.11/src/sys-strings.h        1970-01-01 03:00:00.000000000 +0300
51949 +++ lighttpd-1.4.12/src/sys-strings.h   2006-07-16 00:26:03.000000000 +0300
51950 @@ -0,0 +1,11 @@
51951 +#ifndef _SYS_STRINGS_H_
51952 +#define _SYS_STRINGS_H_
51953 +
51954 +#ifdef _WIN32
51955 +#define strcasecmp stricmp
51956 +#define strncasecmp strnicmp
51957 +#define strtoll(p, e, b) _strtoi64(p, e, b)
51958 +#endif
51959 +
51960 +#endif
51961 +
51962 --- ../lighttpd-1.4.11/tests/LightyTest.pm      2006-01-14 20:32:31.000000000 +0200
51963 +++ lighttpd-1.4.12/tests/LightyTest.pm 2006-07-18 13:03:40.000000000 +0300
51964 @@ -87,14 +87,16 @@
51965         # pre-process configfile if necessary
51966         #
51967  
51968 -       unlink($self->{TESTDIR}."/tmp/cfg.file");
51969 -       system("cat ".$self->{SRCDIR}."/".$self->{CONFIGFILE}.' | perl -pe "s#\@SRCDIR\@#'.$self->{BASEDIR}.'/tests/#" > '.$self->{TESTDIR}.'/tmp/cfg.file');
51970 +       $ENV{'SRCDIR'} = $self->{BASEDIR}.'/tests';
51971 +       $ENV{'PORT'} = $self->{PORT};
51972  
51973         unlink($self->{LIGHTTPD_PIDFILE});
51974 -       if (1) {
51975 -               system($self->{LIGHTTPD_PATH}." -f ".$self->{TESTDIR}."/tmp/cfg.file -m ".$self->{MODULES_PATH});
51976 +       if (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'strace') {
51977 +               system("strace -tt -s 512 -o strace ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH}." &");
51978 +       } elsif (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'valgrind') {
51979 +               system("valgrind --tool=memcheck --show-reachable=yes --leak-check=yes --logfile=valgrind ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH}." &");
51980         } else {
51981 -               system("valgrind --tool=memcheck --show-reachable=yes --leak-check=yes --logfile=foo ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{TESTDIR}."/tmp/cfg.file -m ".$self->{MODULES_PATH}." &");
51982 +               system($self->{LIGHTTPD_PATH}." -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH});
51983         }
51984  
51985         select(undef, undef, undef, 0.1);
51986 @@ -184,7 +186,7 @@
51987                                         (my $h = $1) =~ tr/[A-Z]/[a-z]/;
51988  
51989                                         if (defined $resp_hdr{$h}) {
51990 -                                               diag(sprintf("header %s is duplicated: %s and %s\n",
51991 +                                               diag(sprintf("header '%s' is duplicated: '%s' and '%s'\n",
51992                                                              $h, $resp_hdr{$h}, $2));
51993                                         } else {
51994                                                 $resp_hdr{$h} = $2;
51995 @@ -196,6 +198,9 @@
51996                         }
51997                 }
51998  
51999 +               $t->{etag} = $resp_hdr{'etag'};
52000 +               $t->{date} = $resp_hdr{'date'};
52001 +
52002                 # check length
52003                 if (defined $resp_hdr{"content-length"}) {
52004                         $resp_body = substr($lines, 0, $resp_hdr{"content-length"});
52005 --- ../lighttpd-1.4.11/tests/Makefile.am        2005-09-16 15:48:40.000000000 +0300
52006 +++ lighttpd-1.4.12/tests/Makefile.am   2006-07-16 00:26:05.000000000 +0300
52007 @@ -39,10 +39,18 @@
52008        mod-redirect.t \
52009        mod-userdir.t \
52010        mod-rewrite.t \
52011 +      mod-proxy.t \
52012        request.t \
52013        mod-ssi.t \
52014        LightyTest.pm \
52015 -      mod-setenv.t 
52016 +      mod-setenv.t \
52017 +      lowercase.t \
52018 +      lowercase.conf \
52019 +      proxy.conf \
52020 +      cachable.t \
52021 +      default.conf \
52022 +      proxy-backend-1.conf \
52023 +      proxy-backend-2.conf 
52024  
52025  
52026  TESTS_ENVIRONMENT=$(srcdir)/wrapper.sh $(srcdir) $(top_builddir) 
52027 --- ../lighttpd-1.4.11/tests/bug-06.conf        2005-08-27 17:44:19.000000000 +0300
52028 +++ lighttpd-1.4.12/tests/bug-06.conf   2006-07-16 00:26:04.000000000 +0300
52029 @@ -1,5 +1,5 @@
52030 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52031 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52032 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52033 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52034  
52035  ## bind to port (default: 80)
52036  server.port                 = 2048
52037 @@ -8,7 +8,7 @@
52038  
52039  ## bind to localhost (default: all interfaces)
52040  server.bind                = "localhost"
52041 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52042 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52043  server.name                = "www.example.org"
52044  server.tag                 = "Apache 1.3.29"
52045  
52046 @@ -59,7 +59,7 @@
52047  ######################## MODULE CONFIG ############################
52048  
52049  
52050 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52051 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52052  
52053  mimetype.assign             = ( ".png"  => "image/png", 
52054                                  ".jpg"  => "image/jpeg",
52055 @@ -77,7 +77,7 @@
52056                                 ".c"    => "text/plain",
52057                                 ".conf" => "text/plain" )
52058  
52059 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52060 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52061  compress.filetype           = ("text/plain", "text/html")
52062  
52063  setenv.add-environment      = ( "TRAC_ENV" => "foo")
52064 @@ -90,7 +90,7 @@
52065                                     "host" => "127.0.0.1",
52066                                     "port" => 1026,
52067  #                                  "mode" => "authorizer",
52068 -#                                  "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
52069 +#                                  "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
52070                                   )
52071                                 )
52072                               )
52073 @@ -106,7 +106,7 @@
52074  ssl.pemfile                 = "server.pem"
52075  
52076  auth.backend                = "plain"
52077 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52078 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52079  auth.backend.plain.groupfile = "lighttpd.group"
52080  
52081  auth.backend.ldap.hostname  = "localhost"
52082 @@ -149,15 +149,15 @@
52083  status.config-url           = "/server-config"
52084  
52085  simple-vhost.document-root  = "pages"
52086 -simple-vhost.server-root    = "@SRCDIR@/tmp/lighttpd/servers/"
52087 +simple-vhost.server-root    = env.SRCDIR + "/tmp/lighttpd/servers/"
52088  simple-vhost.default-host   = "www.example.org"
52089  
52090  $HTTP["host"] == "vvv.example.org" {
52091 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52092 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52093  }
52094  
52095  $HTTP["host"] == "zzz.example.org" {
52096 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52097 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52098    server.name = "zzz.example.org"
52099  }
52100  
52101 --- ../lighttpd-1.4.11/tests/bug-12.conf        2005-08-27 17:44:19.000000000 +0300
52102 +++ lighttpd-1.4.12/tests/bug-12.conf   2006-07-16 00:26:04.000000000 +0300
52103 @@ -1,5 +1,5 @@
52104 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52105 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52106 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52107 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52108  
52109  ## bind to port (default: 80)
52110  server.port                 = 2048
52111 @@ -8,7 +8,7 @@
52112  
52113  ## bind to localhost (default: all interfaces)
52114  server.bind                = "localhost"
52115 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52116 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52117  server.name                = "www.example.org"
52118  server.tag                 = "Apache 1.3.29"
52119  
52120 @@ -61,7 +61,7 @@
52121  ######################## MODULE CONFIG ############################
52122  
52123  
52124 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52125 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52126  
52127  mimetype.assign             = ( ".png"  => "image/png", 
52128                                  ".jpg"  => "image/jpeg",
52129 @@ -79,7 +79,7 @@
52130                                 ".c"    => "text/plain",
52131                                 ".conf" => "text/plain" )
52132  
52133 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52134 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52135  compress.filetype           = ("text/plain", "text/html")
52136  
52137  setenv.add-environment      = ( "TRAC_ENV" => "foo")
52138 @@ -92,7 +92,7 @@
52139                                     "host" => "127.0.0.1",
52140                                     "port" => 1026,
52141  #                                  "mode" => "authorizer",
52142 -#                                  "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
52143 +#                                  "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
52144                                   )
52145                                 )
52146                               )
52147 @@ -108,7 +108,7 @@
52148  ssl.pemfile                 = "server.pem"
52149  
52150  auth.backend                = "plain"
52151 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52152 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52153  auth.backend.plain.groupfile = "lighttpd.group"
52154  
52155  auth.backend.ldap.hostname  = "localhost"
52156 @@ -151,15 +151,15 @@
52157  status.config-url           = "/server-config"
52158  
52159  simple-vhost.document-root  = "pages"
52160 -simple-vhost.server-root    = "@SRCDIR@/tmp/lighttpd/servers/"
52161 +simple-vhost.server-root    = env.SRCDIR + "/tmp/lighttpd/servers/"
52162  simple-vhost.default-host   = "www.example.org"
52163  
52164  $HTTP["host"] == "vvv.example.org" {
52165 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52166 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52167  }
52168  
52169  $HTTP["host"] == "zzz.example.org" {
52170 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52171 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52172    server.name = "zzz.example.org"
52173  }
52174  
52175 --- ../lighttpd-1.4.11/tests/cachable.t 1970-01-01 03:00:00.000000000 +0300
52176 +++ lighttpd-1.4.12/tests/cachable.t    2006-07-18 13:03:40.000000000 +0300
52177 @@ -0,0 +1,112 @@
52178 +#!/usr/bin/env perl
52179 +BEGIN {
52180 +    # add current source dir to the include-path
52181 +    # we need this for make distcheck
52182 +   (my $srcdir = $0) =~ s#/[^/]+$#/#;
52183 +   unshift @INC, $srcdir;
52184 +}
52185 +
52186 +use strict;
52187 +use IO::Socket;
52188 +use Test::More tests => 12;
52189 +use LightyTest;
52190 +
52191 +my $tf = LightyTest->new();
52192 +my $t;
52193 +
52194 +$tf->{CONFIGFILE} = 'lighttpd.conf';
52195 +    
52196 +ok($tf->start_proc == 0, "Starting lighttpd") or die();
52197 +
52198 +## check if If-Modified-Since, If-None-Match works
52199 +
52200 +$t->{REQUEST}  = ( <<EOF
52201 +GET / HTTP/1.0
52202 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT
52203 +EOF
52204 + );
52205 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52206 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-Modified-Since');
52207 +
52208 +$t->{REQUEST}  = ( <<EOF
52209 +GET / HTTP/1.0
52210 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
52211 +EOF
52212 + );
52213 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+Last-Modified' => ''} ];
52214 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-Modified-Since, comment');
52215 +
52216 +my $now = $t->{date};
52217 +
52218 +$t->{REQUEST}  = ( <<EOF
52219 +GET / HTTP/1.0
52220 +If-Modified-Since: $now
52221 +EOF
52222 + );
52223 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52224 +ok($tf->handle_http($t) == 0, 'Conditional GET - new If-Modified-Since');
52225 +
52226 +$t->{REQUEST}  = ( <<EOF
52227 +GET / HTTP/1.0
52228 +If-Modified-Since: $now; foo
52229 +EOF
52230 + );
52231 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52232 +ok($tf->handle_http($t) == 0, 'Conditional GET - new If-Modified-Since, comment');
52233 +
52234 +$t->{REQUEST}  = ( <<EOF
52235 +GET / HTTP/1.0
52236 +If-None-Match: foo
52237 +EOF
52238 + );
52239 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+ETag' => ''} ];
52240 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-None-Match');
52241 +
52242 +my $etag = $t->{etag};
52243 +
52244 +$t->{REQUEST}  = ( <<EOF
52245 +GET / HTTP/1.0
52246 +If-None-Match: $etag
52247 +EOF
52248 + );
52249 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52250 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-None-Match');
52251 +
52252 +$t->{REQUEST}  = ( <<EOF
52253 +GET / HTTP/1.0
52254 +If-None-Match: $etag
52255 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
52256 +EOF
52257 + );
52258 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52259 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + old Last-Modified');
52260 +
52261 +$t->{REQUEST}  = ( <<EOF
52262 +GET / HTTP/1.0
52263 +If-None-Match: $etag
52264 +If-Modified-Since: $now; foo
52265 +EOF
52266 + );
52267 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52268 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag, Last-Modified + comment');
52269 +
52270 +$t->{REQUEST}  = ( <<EOF
52271 +GET / HTTP/1.0
52272 +If-None-Match: Foo
52273 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
52274 +EOF
52275 + );
52276 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52277 +ok($tf->handle_http($t) == 0, 'Conditional GET - old ETAG + old Last-Modified');
52278 +
52279 +$t->{REQUEST}  = ( <<EOF
52280 +GET / HTTP/1.0
52281 +If-None-Match: $etag
52282 +If-Modified-Since: $now foo
52283 +EOF
52284 + );
52285 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 412 } ];
52286 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + Last-Modified + overlong timestamp');
52287 +
52288 +ok($tf->stop_proc == 0, "Stopping lighttpd");
52289 +
52290 --- ../lighttpd-1.4.11/tests/condition.conf     2005-08-27 17:44:19.000000000 +0300
52291 +++ lighttpd-1.4.12/tests/condition.conf        2006-07-16 00:26:05.000000000 +0300
52292 @@ -2,15 +2,15 @@
52293  debug.log-request-handling = "enable"
52294  debug.log-condition-handling = "enable"
52295  
52296 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52297 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52298 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52299 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52300  
52301  ## bind to port (default: 80)
52302  server.port                 = 2048
52303  
52304  ## bind to localhost (default: all interfaces)
52305  server.bind                = "localhost"
52306 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52307 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52308  server.name                = "www.example.org"
52309  server.tag                 = "Apache 1.3.29"
52310  
52311 @@ -22,25 +22,25 @@
52312  ######################## MODULE CONFIG ############################
52313  
52314  
52315 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52316 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52317  
52318  mimetype.assign             = ( ".html" => "text/html" )
52319  
52320  url.redirect = ("^" => "/default")
52321  
52322  $HTTP["host"] == "www.example.org" {
52323 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52324 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52325    server.name = "www.example.org"
52326    url.redirect = ("^" => "/match_1")
52327  }
52328  else $HTTP["host"] == "test1.example.org" {
52329 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52330 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52331    server.name = "test1.example.org"
52332    url.redirect = ("^" => "/match_2")
52333  }
52334  # comments
52335  else $HTTP["host"] == "test2.example.org" {
52336 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52337 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52338    server.name = "test2.example.org"
52339    url.redirect = ("^" => "/match_3")
52340  }
52341 @@ -48,7 +48,7 @@
52342          # comments
52343  
52344  else $HTTP["host"] == "test3.example.org" {
52345 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52346 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52347    server.name = "test3.example.org"
52348    url.redirect = ("^" => "/match_4")
52349  
52350 --- ../lighttpd-1.4.11/tests/core-keepalive.t   2005-11-17 15:54:19.000000000 +0200
52351 +++ lighttpd-1.4.12/tests/core-keepalive.t      2006-07-16 00:26:05.000000000 +0300
52352 @@ -40,7 +40,7 @@
52353  
52354  GET /12345.txt HTTP/1.0
52355  Host: 123.example.org
52356 -Connection: keep-alive
52357 +Connection: close
52358  EOF
52359   );
52360  $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } , { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52361 --- ../lighttpd-1.4.11/tests/default.conf       1970-01-01 03:00:00.000000000 +0300
52362 +++ lighttpd-1.4.12/tests/default.conf  2006-07-16 00:26:05.000000000 +0300
52363 @@ -0,0 +1,111 @@
52364 +server.name                = "www.example.org"
52365 +
52366 +## bind to port (default: 80)
52367 +server.port                 = env.PORT
52368 +
52369 +
52370 +server.dir-listing          = "enable"
52371 +
52372 +#server.event-handler        = "linux-sysepoll"
52373 +#server.event-handler        = "linux-rtsig"
52374 +
52375 +server.modules              = ( 
52376 +                               "mod_rewrite",
52377 +                               "mod_setenv",
52378 +                               "mod_access", 
52379 +                               "mod_auth",
52380 +                               "mod_status", 
52381 +                               "mod_expire",
52382 +                               "mod_simple_vhost",
52383 +                               "mod_redirect", 
52384 +                               "mod_secdownload",
52385 +                               "mod_ssi",
52386 +                               "mod_fastcgi",
52387 +                               "mod_proxy",
52388 +                               "mod_cgi",
52389 +                               "mod_compress",
52390 +                               "mod_userdir",
52391 +                               "mod_accesslog" ) 
52392 +
52393 +server.indexfiles           = ( "index.php", "index.html", 
52394 +                                "index.htm", "default.htm" )
52395 +
52396 +ssi.extension = ( ".shtml" )
52397 +
52398 +######################## MODULE CONFIG ############################
52399 +
52400 +
52401 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52402 +server.errorlog             = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52403 +
52404 +mimetype.assign             = ( ".png"  => "image/png", 
52405 +                                ".jpg"  => "image/jpeg",
52406 +                                ".jpeg" => "image/jpeg",
52407 +                                ".gif"  => "image/gif",
52408 +                                ".html" => "text/html",
52409 +                                ".htm"  => "text/html",
52410 +                                ".pdf"  => "application/pdf",
52411 +                                ".swf"  => "application/x-shockwave-flash",
52412 +                                ".spl"  => "application/futuresplash",
52413 +                                ".txt"  => "text/plain",
52414 +                                ".tar.gz" =>   "application/x-tgz",
52415 +                                ".tgz"  => "application/x-tgz",
52416 +                                ".gz"   => "application/x-gzip",
52417 +                               ".c"    => "text/plain",
52418 +                               ".conf" => "text/plain" )
52419 +
52420 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52421 +compress.filetype           = ("text/plain", "text/html")
52422 +
52423 +setenv.add-environment      = ( "TRAC_ENV" => "tracenv", "SETENV" => "setenv")
52424 +
52425 +cgi.assign                  = ( ".pl"  => "/usr/bin/perl",
52426 +                                ".cgi" => "/usr/bin/perl",
52427 +                               ".py"  => "/usr/bin/python" )
52428 +                       
52429 +userdir.include-user = ( "jan" )
52430 +userdir.path = "/"
52431 +
52432 +ssl.engine                  = "disable"
52433 +ssl.pemfile                 = "server.pem"
52434 +
52435 +auth.backend                = "plain"
52436 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52437 +auth.backend.htpasswd.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.htpasswd"
52438 +auth.backend.plain.groupfile = "lighttpd.group"
52439 +
52440 +auth.backend.ldap.hostname  = "localhost"
52441 +auth.backend.ldap.base-dn   = "dc=my-domain,dc=com"
52442 +auth.backend.ldap.filter    = "(uid=$)"
52443 +
52444 +auth.require                = ( "/server-status" => 
52445 +                                ( 
52446 +                                 "method"  => "digest",
52447 +                                 "realm"   => "download archiv",
52448 +                                 "require" => "valid-user"
52449 +                               ),
52450 +                               "/auth.php" => 
52451 +                                ( 
52452 +                                 "method"  => "basic",
52453 +                                 "realm"   => "download archiv",
52454 +                                 "require" => "user=jan"
52455 +                               ),
52456 +                               "/server-config" => 
52457 +                                ( 
52458 +                                 "method"  => "basic",
52459 +                                 "realm"   => "download archiv",
52460 +                                 "require" => "valid-user"
52461 +                               )
52462 +                              )
52463 +
52464 +url.access-deny             = ( "~", ".inc")
52465 +
52466 +url.redirect                = ( "^/redirect/$" => "http://localhost:2048/" )
52467 +
52468 +url.rewrite                = ( "^/rewrite/foo($|\?.+)" => "/indexfile/rewrite.php$1",
52469 +                               "^/rewrite/bar(?:$|\?(.+))" => "/indexfile/rewrite.php?bar&$1" )
52470 +
52471 +#### status module
52472 +status.status-url           = "/server-status"
52473 +status.config-url           = "/server-config"
52474 +
52475 --- ../lighttpd-1.4.11/tests/docroot/www/dummydir/.svn/entries  2006-03-09 19:21:49.000000000 +0200
52476 +++ lighttpd-1.4.12/tests/docroot/www/dummydir/.svn/entries     2006-07-18 13:03:40.000000000 +0300
52477 @@ -9,5 +9,6 @@
52478     last-author="jan"
52479     kind="dir"
52480     uuid="152afb58-edef-0310-8abb-c4023f1b3aa9"
52481 -   revision="1040"/>
52482 +   repos="svn://svn.lighttpd.net/lighttpd"
52483 +   revision="1199"/>
52484  </wc-entries>
52485 --- ../lighttpd-1.4.11/tests/fastcgi-10.conf    2005-08-31 23:36:34.000000000 +0300
52486 +++ lighttpd-1.4.12/tests/fastcgi-10.conf       2006-07-16 00:26:04.000000000 +0300
52487 @@ -1,12 +1,12 @@
52488 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52489 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52490 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52491 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52492  
52493  ## bind to port (default: 80)
52494  server.port                 = 2048
52495  
52496  ## bind to localhost (default: all interfaces)
52497  server.bind                = "localhost"
52498 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52499 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52500  server.name                = "www.example.org"
52501  server.tag                 = "Apache 1.3.29"
52502  
52503 @@ -44,7 +44,7 @@
52504  ######################## MODULE CONFIG ############################
52505  
52506  
52507 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52508 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52509  
52510  mimetype.assign             = ( ".png"  => "image/png", 
52511                                  ".jpg"  => "image/jpeg",
52512 @@ -62,7 +62,7 @@
52513                                 ".c"    => "text/plain",
52514                                 ".conf" => "text/plain" )
52515  
52516 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52517 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52518  compress.filetype           = ("text/plain", "text/html")
52519  
52520  fastcgi.debug               = 0
52521 @@ -85,7 +85,7 @@
52522  ssl.pemfile                 = "server.pem"
52523  
52524  auth.backend                = "plain"
52525 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52526 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52527  auth.backend.plain.groupfile = "lighttpd.group"
52528  
52529  auth.backend.ldap.hostname  = "localhost"
52530 @@ -128,11 +128,11 @@
52531  status.config-url           = "/server-config"
52532  
52533  $HTTP["host"] == "vvv.example.org" {
52534 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52535 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52536  }
52537  
52538  $HTTP["host"] == "zzz.example.org" {
52539 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52540 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52541    server.name = "zzz.example.org"
52542  }
52543  
52544 --- ../lighttpd-1.4.11/tests/fastcgi-13.conf    2006-01-03 12:38:17.000000000 +0200
52545 +++ lighttpd-1.4.12/tests/fastcgi-13.conf       2006-07-18 13:03:40.000000000 +0300
52546 @@ -1,5 +1,5 @@
52547 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52548 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52549 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52550 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52551  
52552  debug.log-request-header   = "enable"
52553  debug.log-response-header  = "enable"
52554 @@ -10,7 +10,7 @@
52555  
52556  ## bind to localhost (default: all interfaces)
52557  server.bind                = "localhost"
52558 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52559 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52560  server.name                = "www.example.org"
52561  server.tag                 = "Apache 1.3.29"
52562  
52563 @@ -59,7 +59,7 @@
52564  ######################## MODULE CONFIG ############################
52565  
52566  
52567 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52568 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52569  
52570  mimetype.assign             = ( ".png"  => "image/png", 
52571                                  ".jpg"  => "image/jpeg",
52572 @@ -77,7 +77,7 @@
52573                                 ".c"    => "text/plain",
52574                                 ".conf" => "text/plain" )
52575  
52576 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52577 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52578  compress.filetype           = ("text/plain", "text/html")
52579  
52580  fastcgi.debug               = 0
52581 @@ -85,7 +85,7 @@
52582                                    "grisu" => ( 
52583                                     "host" => "127.0.0.1",
52584                                     "port" => 1048,
52585 -                                   "bin-path" => "/home/jan/Documents/php-5.1.0/sapi/cgi/php -c /usr/local/lib/php.ini",
52586 +                                   "bin-path" => "/home/jan/Documents/php-5.1.4/sapi/cgi/php -c /usr/local/lib/php.ini",
52587                                     "bin-copy-environment" => ( "PATH", "SHELL", "USER" ),
52588                                   )
52589                                 )
52590 @@ -102,7 +102,7 @@
52591  ssl.pemfile                 = "server.pem"
52592  
52593  auth.backend                = "plain"
52594 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52595 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52596  auth.backend.plain.groupfile = "lighttpd.group"
52597  
52598  auth.backend.ldap.hostname  = "localhost"
52599 @@ -145,11 +145,11 @@
52600  status.config-url           = "/server-config"
52601  
52602  $HTTP["host"] == "vvv.example.org" {
52603 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52604 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52605  }
52606  
52607  $HTTP["host"] == "zzz.example.org" {
52608 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52609 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52610    server.name = "zzz.example.org"
52611  }
52612  
52613 --- ../lighttpd-1.4.11/tests/fastcgi-auth.conf  2005-08-27 17:44:19.000000000 +0300
52614 +++ lighttpd-1.4.12/tests/fastcgi-auth.conf     2006-07-16 00:26:05.000000000 +0300
52615 @@ -1,5 +1,5 @@
52616 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52617 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52618 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52619 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52620  
52621  debug.log-request-header   = "enable"
52622  debug.log-response-header  = "enable"
52623 @@ -12,7 +12,7 @@
52624  
52625  ## bind to localhost (default: all interfaces)
52626  server.bind                = "localhost"
52627 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52628 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52629  server.name                = "www.example.org"
52630  server.tag                 = "Apache 1.3.29"
52631  
52632 @@ -61,7 +61,7 @@
52633  ######################## MODULE CONFIG ############################
52634  
52635  
52636 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52637 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52638  
52639  mimetype.assign             = ( ".png"  => "image/png", 
52640                                  ".jpg"  => "image/jpeg",
52641 @@ -79,7 +79,7 @@
52642                                 ".c"    => "text/plain",
52643                                 ".conf" => "text/plain" )
52644  
52645 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52646 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52647  compress.filetype           = ("text/plain", "text/html")
52648  
52649  fastcgi.debug               = 0
52650 @@ -87,9 +87,9 @@
52651                                    "grisu" => ( 
52652                                     "host" => "127.0.0.1",
52653                                     "port" => 20000,
52654 -                                   "bin-path" => "@SRCDIR@/fcgi-auth",
52655 +                                   "bin-path" => env.SRCDIR + "/fcgi-auth",
52656                                      "mode" => "authorizer",
52657 -                                    "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
52658 +                                    "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
52659                                     
52660                                   )
52661                                 )
52662 @@ -106,7 +106,7 @@
52663  ssl.pemfile                 = "server.pem"
52664  
52665  auth.backend                = "plain"
52666 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52667 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52668  auth.backend.plain.groupfile = "lighttpd.group"
52669  
52670  auth.backend.ldap.hostname  = "localhost"
52671 @@ -149,11 +149,11 @@
52672  status.config-url           = "/server-config"
52673  
52674  $HTTP["host"] == "vvv.example.org" {
52675 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52676 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52677  }
52678  
52679  $HTTP["host"] == "zzz.example.org" {
52680 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52681 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52682    server.name = "zzz.example.org"
52683  }
52684  
52685 --- ../lighttpd-1.4.11/tests/fastcgi-responder.conf     2005-08-27 17:44:19.000000000 +0300
52686 +++ lighttpd-1.4.12/tests/fastcgi-responder.conf        2006-07-16 00:26:05.000000000 +0300
52687 @@ -1,5 +1,5 @@
52688 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52689 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52690 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52691 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52692  
52693  #debug.log-request-header   = "enable"
52694  #debug.log-response-header  = "enable"
52695 @@ -15,7 +15,7 @@
52696  
52697  ## bind to localhost (default: all interfaces)
52698  server.bind                = "localhost"
52699 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52700 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52701  server.name                = "www.example.org"
52702  server.tag                 = "Apache 1.3.29"
52703  
52704 @@ -64,7 +64,7 @@
52705  ######################## MODULE CONFIG ############################
52706  
52707  
52708 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52709 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52710  
52711  mimetype.assign             = ( ".png"  => "image/png", 
52712                                  ".jpg"  => "image/jpeg",
52713 @@ -82,7 +82,7 @@
52714                                 ".c"    => "text/plain",
52715                                 ".conf" => "text/plain" )
52716  
52717 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52718 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52719  compress.filetype           = ("text/plain", "text/html")
52720  
52721  fastcgi.debug               = 0
52722 @@ -90,10 +90,11 @@
52723                                    "grisu" => ( 
52724                                     "host" => "127.0.0.1",
52725                                     "port" => 10000,
52726 -                                   "bin-path" => "@SRCDIR@/fcgi-responder",
52727 +                                   "bin-path" => env.SRCDIR + "/fcgi-responder",
52728                                     "check-local" => "disable",
52729                                     "max-procs" => 1,
52730 -                                   "min-procs" => 1
52731 +                                   "min-procs" => 1,
52732 +                                   "allow-x-send-file" => "enable",
52733                                   )
52734                                 )
52735                               )
52736 @@ -109,7 +110,7 @@
52737  ssl.pemfile                 = "server.pem"
52738  
52739  auth.backend                = "plain"
52740 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52741 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52742  auth.backend.plain.groupfile = "lighttpd.group"
52743  
52744  auth.backend.ldap.hostname  = "localhost"
52745 @@ -152,11 +153,11 @@
52746  status.config-url           = "/server-config"
52747  
52748  $HTTP["host"] == "vvv.example.org" {
52749 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52750 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52751  }
52752  
52753  $HTTP["host"] == "zzz.example.org" {
52754 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52755 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52756    server.name = "zzz.example.org"
52757  }
52758  
52759 --- ../lighttpd-1.4.11/tests/fcgi-responder.c   2005-08-11 01:26:55.000000000 +0300
52760 +++ lighttpd-1.4.12/tests/fcgi-responder.c      2006-07-16 00:26:05.000000000 +0300
52761 @@ -6,11 +6,17 @@
52762  int main () {
52763         int num_requests = 2;
52764         
52765 -       while (num_requests > 0 &&
52766 -              FCGI_Accept() >= 0) {
52767 -               char* p;
52768 -               
52769 -               if (NULL != (p = getenv("QUERY_STRING"))) {
52770 +       while (num_requests > 0 && FCGI_Accept() >= 0) {
52771 +               char* p = NULL;
52772 +               char* doc_root = NULL;
52773 +               char fname[4096];
52774 +               char* pfname = (char *)fname;
52775 +
52776 +               doc_root = getenv("DOCUMENT_ROOT");
52777 +               p = getenv("QUERY_STRING");
52778 +
52779 +               if (NULL != p && NULL != doc_root) {
52780 +                       snprintf(pfname, sizeof(fname), "%s/phpinfo.php", doc_root);
52781                         if (0 == strcmp(p, "lf")) {
52782                                 printf("Status: 200 OK\n\n");
52783                         } else if (0 == strcmp(p, "crlf")) {
52784 @@ -23,6 +29,18 @@
52785                                 printf("Status: 200 OK\r\n");
52786                                 fflush(stdout);
52787                                 printf("\r\n");
52788 +                       } else if (0 == strcmp(p,"x-lighttpd-send-file")) {
52789 +                               printf("Status: 200 OK\r\n");
52790 +                               printf("X-LIGHTTPD-send-file: %s\r\n", pfname);
52791 +                               printf("\r\n");
52792 +                       } else if (0 == strcmp(p,"xsendfile")) {
52793 +                               printf("Status: 200 OK\r\n");
52794 +                               printf("X-Sendfile: %s\r\n", pfname);
52795 +                               printf("\r\n");
52796 +                       } else if (0 == strcmp(p,"xsendfile-mixed-case")) {
52797 +                               printf("Status: 200 OK\r\n");
52798 +                               printf("X-SeNdFiLe: %s\r\n", pfname);
52799 +                               printf("\r\n");
52800                         } else if (0 == strcmp(p, "die-at-end")) {
52801                                 printf("Status: 200 OK\r\n\r\n");
52802                                 num_requests--;
52803 --- ../lighttpd-1.4.11/tests/lighttpd.conf      2006-03-09 15:26:58.000000000 +0200
52804 +++ lighttpd-1.4.12/tests/lighttpd.conf 2006-07-16 00:26:05.000000000 +0300
52805 @@ -1,80 +1,18 @@
52806 -debug.log-request-handling = "enable"
52807 -debug.log-condition-handling = "enable"
52808 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52809 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52810 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52811 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52812 +server.tag = "Apache 1.3.29"
52813  
52814  ## 64 Mbyte ... nice limit
52815  server.max-request-size = 65000
52816  
52817 -## bind to port (default: 80)
52818 -server.port                 = 2048
52819 +include "default.conf"
52820  
52821 -## bind to localhost (default: all interfaces)
52822 -server.bind                = "localhost"
52823 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52824 -server.name                = "www.example.org"
52825 -server.tag                 = "Apache 1.3.29"
52826 -
52827 -server.dir-listing          = "enable"
52828 -
52829 -#server.event-handler        = "linux-sysepoll"
52830 -#server.event-handler        = "linux-rtsig"
52831 -
52832 -#server.modules.path         = ""
52833 -server.modules              = ( 
52834 -                               "mod_rewrite",
52835 -                               "mod_setenv",
52836 -                               "mod_secdownload",
52837 -                               "mod_access", 
52838 -                               "mod_auth",
52839 -#                              "mod_httptls",
52840 -                               "mod_status", 
52841 -                               "mod_expire",
52842 -                               "mod_simple_vhost",
52843 -                               "mod_redirect", 
52844 -#                              "mod_evhost",
52845 -#                              "mod_localizer",
52846 -                               "mod_fastcgi",
52847 -                               "mod_cgi",
52848 -                               "mod_compress",
52849 -                               "mod_userdir",
52850 -                               "mod_ssi",
52851 -                               "mod_accesslog" ) 
52852 -
52853 -server.indexfiles           = ( "index.php", "index.html", 
52854 -                                "index.htm", "default.htm" )
52855 -
52856 -
52857 -######################## MODULE CONFIG ############################
52858 -
52859 -ssi.extension = ( ".shtml" )
52860 -
52861 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52862 -
52863 -mimetype.assign             = ( ".png"  => "image/png", 
52864 -                                ".jpg"  => "image/jpeg",
52865 -                                ".jpeg" => "image/jpeg",
52866 -                                ".gif"  => "image/gif",
52867 -                                ".html" => "text/html",
52868 -                                ".htm"  => "text/html",
52869 -                                ".pdf"  => "application/pdf",
52870 -                                ".swf"  => "application/x-shockwave-flash",
52871 -                                ".spl"  => "application/futuresplash",
52872 -                                ".txt"  => "text/plain",
52873 -                                ".tar.gz" =>   "application/x-tgz",
52874 -                                ".tgz"  => "application/x-tgz",
52875 -                                ".gz"   => "application/x-gzip",
52876 -                               ".c"    => "text/plain",
52877 -                               ".conf" => "text/plain" )
52878 +setenv.add-request-header   = ( "FOO" => "foo")
52879 +setenv.add-response-header  = ( "BAR" => "foo")
52880  
52881  $HTTP["host"] == "cache.example.org" {
52882 -  compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52883 +  compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52884  }
52885 -compress.filetype           = ("text/plain", "text/html")
52886 -
52887 -setenv.add-environment      = ( "TRAC_ENV" => "tracenv", "SETENV" => "setenv")
52888 -setenv.add-request-header   = ( "FOO" => "foo")
52889 -setenv.add-response-header  = ( "BAR" => "foo")
52890  
52891  $HTTP["url"] =~ "\.pdf$" {
52892    server.range-requests = "disable"
52893 @@ -85,76 +23,31 @@
52894                                 "/prefix.fcgi" => ( ( "host" => "127.0.0.1", "port" => 1026, "check-local" => "disable", "broken-scriptfilename" => "enable" ) )
52895                               )
52896                 
52897 -
52898 -cgi.assign                  = ( ".pl"  => "/usr/bin/perl",
52899 -                                ".cgi" => "/usr/bin/perl",
52900 -                               ".py"  => "/usr/bin/python" )
52901 -                       
52902 -userdir.include-user = ( "jan" )
52903 -userdir.path = "/"
52904 -
52905 -ssl.engine                  = "disable"
52906 -ssl.pemfile                 = "server.pem"
52907 -
52908  $HTTP["host"] == "auth-htpasswd.example.org" {
52909         auth.backend                = "htpasswd"
52910  }
52911  
52912 -auth.backend                = "plain"
52913 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52914 -
52915 -auth.backend.htpasswd.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.htpasswd"
52916 -
52917 -
52918 -auth.require                = ( "/server-status" => 
52919 -                                ( 
52920 -                                 "method"  => "digest",
52921 -                                 "realm"   => "download archiv",
52922 -                                 "require" => "group=www|user=jan|host=192.168.2.10"
52923 -                               ),
52924 -                               "/server-config" => 
52925 -                                ( 
52926 -                                 "method"  => "basic",
52927 -                                 "realm"   => "download archiv",
52928 -                                 "require" => "valid-user"
52929 -                               )
52930 -                              )
52931 -
52932 -url.access-deny             = ( "~", ".inc")
52933 -
52934 -url.rewrite                = ( "^/rewrite/foo($|\?.+)" => "/indexfile/rewrite.php$1",
52935 -                               "^/rewrite/bar(?:$|\?(.+))" => "/indexfile/rewrite.php?bar&$1" )
52936 -
52937 -expire.url                  = ( "/expire/access" => "access 2 hours", 
52938 -                               "/expire/modification" => "access plus 1 seconds 2 minutes")
52939 -
52940 -#cache.cache-dir             = "/home/weigon/wwwroot/cache/"
52941 -
52942 -#### status module
52943 -status.status-url           = "/server-status"
52944 -status.config-url           = "/server-config"
52945 -
52946  $HTTP["host"] == "vvv.example.org" {
52947 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52948 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52949    secdownload.secret          = "verysecret"
52950 -  secdownload.document-root   = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52951 +  secdownload.document-root   = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52952    secdownload.uri-prefix      = "/sec/"
52953    secdownload.timeout         = 120
52954  }
52955  
52956  $HTTP["host"] == "zzz.example.org" {
52957 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52958 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52959    server.name = "zzz.example.org"
52960  }
52961  
52962  $HTTP["host"] == "no-simple.example.org" {
52963 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/123.example.org/pages/"
52964 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/123.example.org/pages/"
52965    server.name = "zzz.example.org"
52966  }
52967  
52968  $HTTP["host"] !~ "(no-simple\.example\.org)" {
52969    simple-vhost.document-root  = "pages"
52970 -  simple-vhost.server-root    = "@SRCDIR@/tmp/lighttpd/servers/"
52971 +  simple-vhost.server-root    = env.SRCDIR + "/tmp/lighttpd/servers/"
52972    simple-vhost.default-host   = "www.example.org"
52973  }
52974  
52975 --- ../lighttpd-1.4.11/tests/lowercase.conf     1970-01-01 03:00:00.000000000 +0300
52976 +++ lighttpd-1.4.12/tests/lowercase.conf        2006-07-16 00:26:05.000000000 +0300
52977 @@ -0,0 +1,80 @@
52978 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52979 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52980 +
52981 +## bind to port (default: 80)
52982 +server.port                 = 2048
52983 +
52984 +## bind to localhost (default: all interfaces)
52985 +server.bind                = "localhost"
52986 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52987 +
52988 +server.force-lowercase-filenames = "enable"
52989 +
52990 +server.dir-listing          = "enable"
52991 +
52992 +server.modules              = ( 
52993 +                               "mod_rewrite",
52994 +                               "mod_setenv",
52995 +                               "mod_secdownload",
52996 +                               "mod_access", 
52997 +                               "mod_auth",
52998 +                               "mod_status", 
52999 +                               "mod_expire",
53000 +                               "mod_redirect", 
53001 +                               "mod_fastcgi",
53002 +                               "mod_cgi" ) 
53003 +
53004 +server.indexfiles           = ( "index.php", "index.html", 
53005 +                                "index.htm", "default.htm" )
53006 +
53007 +
53008 +######################## MODULE CONFIG ############################
53009 +
53010 +mimetype.assign             = ( ".png"  => "image/png", 
53011 +                                ".jpg"  => "image/jpeg",
53012 +                                ".jpeg" => "image/jpeg",
53013 +                                ".gif"  => "image/gif",
53014 +                                ".html" => "text/html",
53015 +                                ".htm"  => "text/html",
53016 +                                ".pdf"  => "application/pdf",
53017 +                                ".swf"  => "application/x-shockwave-flash",
53018 +                                ".spl"  => "application/futuresplash",
53019 +                                ".txt"  => "text/plain",
53020 +                                ".tar.gz" =>   "application/x-tgz",
53021 +                                ".tgz"  => "application/x-tgz",
53022 +                                ".gz"   => "application/x-gzip",
53023 +                               ".c"    => "text/plain",
53024 +                               ".conf" => "text/plain" )
53025 +
53026 +fastcgi.debug               = 0
53027 +fastcgi.server              = ( ".php" =>        ( ( "host" => "127.0.0.1", "port" => 1026, "broken-scriptfilename" => "enable" ) ),
53028 +                               "/prefix.fcgi" => ( ( "host" => "127.0.0.1", "port" => 1026, "check-local" => "disable", "broken-scriptfilename" => "enable" ) )
53029 +                             )
53030 +               
53031 +
53032 +cgi.assign                  = ( ".pl"  => "/usr/bin/perl",
53033 +                                ".cgi" => "/usr/bin/perl",
53034 +                               ".py"  => "/usr/bin/python" )
53035 +                       
53036 +auth.backend                = "plain"
53037 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53038 +
53039 +auth.backend.htpasswd.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.htpasswd"
53040 +
53041 +$HTTP["host"] == "lowercase-auth" {
53042 +  auth.require             = ( "/image.jpg" => 
53043 +                                ( 
53044 +                                 "method"  => "digest",
53045 +                                 "realm"   => "download archiv",
53046 +                                 "require" => "valid-user"
53047 +                               )
53048 +                              )
53049 +}
53050 +
53051 +$HTTP["host"] == "lowercase-deny" {
53052 +  url.access-deny             = ( ".jpg")
53053 +}
53054 +
53055 +$HTTP["host"] == "lowercase-exclude" {
53056 +  static-file.exclude-extensions = ( ".jpg" )
53057 +}
53058 --- ../lighttpd-1.4.11/tests/lowercase.t        1970-01-01 03:00:00.000000000 +0300
53059 +++ lighttpd-1.4.12/tests/lowercase.t   2006-07-16 00:26:05.000000000 +0300
53060 @@ -0,0 +1,94 @@
53061 +#!/usr/bin/env perl
53062 +BEGIN {
53063 +    # add current source dir to the include-path
53064 +    # we need this for make distcheck
53065 +   (my $srcdir = $0) =~ s#/[^/]+$#/#;
53066 +   unshift @INC, $srcdir;
53067 +}
53068 +
53069 +use strict;
53070 +use IO::Socket;
53071 +use Test::More tests => 10;
53072 +use LightyTest;
53073 +
53074 +my $tf = LightyTest->new();
53075 +my $t;
53076 +
53077 +$tf->{CONFIGFILE} = 'lowercase.conf';
53078 +    
53079 +ok($tf->start_proc == 0, "Starting lighttpd") or die();
53080 +
53081 +## check if lower-casing works
53082 +
53083 +$t->{REQUEST}  = ( <<EOF
53084 +GET /image.JPG HTTP/1.0
53085 +EOF
53086 + );
53087 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53088 +ok($tf->handle_http($t) == 0, 'uppercase access');
53089 +
53090 +$t->{REQUEST}  = ( <<EOF
53091 +GET /image.jpg HTTP/1.0
53092 +EOF
53093 + );
53094 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53095 +ok($tf->handle_http($t) == 0, 'lowercase access');
53096 +
53097 +## check that mod-auth works
53098 +
53099 +$t->{REQUEST}  = ( <<EOF
53100 +GET /image.JPG HTTP/1.0
53101 +Host: lowercase-auth
53102 +EOF
53103 + );
53104 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ];
53105 +ok($tf->handle_http($t) == 0, 'uppercase access');
53106 +
53107 +$t->{REQUEST}  = ( <<EOF
53108 +GET /image.jpg HTTP/1.0
53109 +Host: lowercase-auth
53110 +EOF
53111 + );
53112 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ];
53113 +ok($tf->handle_http($t) == 0, 'lowercase access');
53114 +
53115 +
53116 +## check that mod-staticfile exclude works
53117 +$t->{REQUEST}  = ( <<EOF
53118 +GET /image.JPG HTTP/1.0
53119 +Host: lowercase-exclude
53120 +EOF
53121 + );
53122 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53123 +ok($tf->handle_http($t) == 0, 'upper case access to staticfile.exclude-extension');
53124 +
53125 +$t->{REQUEST}  = ( <<EOF
53126 +GET /image.jpg HTTP/1.0
53127 +Host: lowercase-exclude
53128 +EOF
53129 + );
53130 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53131 +ok($tf->handle_http($t) == 0, 'lowercase access');
53132 +
53133 +
53134 +## check that mod-access exclude works
53135 +$t->{REQUEST}  = ( <<EOF
53136 +GET /image.JPG HTTP/1.0
53137 +Host: lowercase-deny
53138 +EOF
53139 + );
53140 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53141 +ok($tf->handle_http($t) == 0, 'uppercase access to url.access-deny protected location');
53142 +
53143 +$t->{REQUEST}  = ( <<EOF
53144 +GET /image.jpg HTTP/1.0
53145 +Host: lowercase-deny
53146 +EOF
53147 + );
53148 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53149 +ok($tf->handle_http($t) == 0, 'lowercase access');
53150 +
53151 +
53152 +
53153 +ok($tf->stop_proc == 0, "Stopping lighttpd");
53154 +
53155 --- ../lighttpd-1.4.11/tests/mod-cgi.t  2005-09-01 14:43:05.000000000 +0300
53156 +++ lighttpd-1.4.12/tests/mod-cgi.t     2006-07-18 13:03:40.000000000 +0300
53157 @@ -43,7 +43,7 @@
53158  GET /nph-status.pl HTTP/1.0
53159  EOF
53160   );
53161 -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53162 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 502 } ];
53163  ok($tf->handle_http($t) == 0, 'NPH + perl, Bug #14');
53164  
53165  $t->{REQUEST} = ( <<EOF
53166 --- ../lighttpd-1.4.11/tests/mod-fastcgi.t      2006-03-09 15:30:45.000000000 +0200
53167 +++ lighttpd-1.4.12/tests/mod-fastcgi.t 2006-07-18 13:03:40.000000000 +0300
53168 @@ -7,7 +7,7 @@
53169  }
53170  
53171  use strict;
53172 -use Test::More tests => 47;
53173 +use Test::More tests => 49;
53174  use LightyTest;
53175  
53176  my $tf = LightyTest->new();
53177 @@ -15,7 +15,7 @@
53178  my $t;
53179  
53180  SKIP: {
53181 -       skip "no PHP running on port 1026", 30 unless $tf->listening_on(1026);
53182 +       skip "no PHP running on port 1026", 29 unless $tf->listening_on(1026);
53183  
53184         ok($tf->start_proc == 0, "Starting lighttpd") or die();
53185  
53186 @@ -223,7 +223,7 @@
53187  }
53188  
53189  SKIP: {
53190 -       skip "no php found", 4 unless -x "/home/jan/Documents/php-5.1.0/sapi/cgi/php"; 
53191 +       skip "no php found", 4 unless -x "/home/jan/Documents/php-5.1.4/sapi/cgi/php";
53192         $tf->{CONFIGFILE} = 'fastcgi-13.conf';
53193         ok($tf->start_proc == 0, "Starting lighttpd with $tf->{CONFIGFILE}") or die();
53194         $t->{REQUEST}  = ( <<EOF
53195 @@ -285,6 +285,34 @@
53196         $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => 'test123' } ];
53197         ok($tf->handle_http($t) == 0, 'line-ending \r\n + \r\n');
53198  
53199 +    # X-LIGHTTPD-send-file
53200 +       $t->{REQUEST}  = ( <<EOF
53201 +GET /index.fcgi?x-lighttpd-send-file HTTP/1.0
53202 +Host: www.example.org
53203 +EOF
53204 + );
53205 +       $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
53206 +' } ];
53207 +       ok($tf->handle_http($t) == 0, 'X-LIGHTTPD-send-file');
53208 +    # X-Sendfile
53209 +       $t->{REQUEST}  = ( <<EOF
53210 +GET /index.fcgi?xsendfile HTTP/1.0
53211 +Host: www.example.org
53212 +EOF
53213 + );
53214 +       $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
53215 +' } ];
53216 +       ok($tf->handle_http($t) == 0, 'X-Sendfile');
53217 +
53218 +       $t->{REQUEST}  = ( <<EOF
53219 +GET /index.fcgi?xsendfile-mixed-case HTTP/1.0
53220 +Host: www.example.org
53221 +EOF
53222 + );
53223 +       $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
53224 +' } ];
53225 +       ok($tf->handle_http($t) == 0, 'X-SeNdFiLe in mixed case');
53226 +
53227         $t->{REQUEST}  = ( <<EOF
53228  GET /index.fcgi?die-at-end HTTP/1.0
53229  Host: www.example.org
53230 --- ../lighttpd-1.4.11/tests/mod-proxy.t        1970-01-01 03:00:00.000000000 +0300
53231 +++ lighttpd-1.4.12/tests/mod-proxy.t   2006-07-18 13:03:40.000000000 +0300
53232 @@ -0,0 +1,175 @@
53233 +#!/usr/bin/env perl
53234 +BEGIN {
53235 +    # add current source dir to the include-path
53236 +    # we need this for make distcheck
53237 +   (my $srcdir = $0) =~ s#/[^/]+$#/#;
53238 +   unshift @INC, $srcdir;
53239 +}
53240 +
53241 +use strict;
53242 +use IO::Socket;
53243 +use Test::More tests => 21;
53244 +use LightyTest;
53245 +
53246 +my $tf_proxy = LightyTest->new();
53247 +my $tf_backend1 = LightyTest->new();
53248 +my $tf_backend2 = LightyTest->new();
53249 +
53250 +my $t;
53251 +
53252 +## we need two procs
53253 +## 1. the real webserver
53254 +## 2. the proxy server
53255 +
53256 +SKIP: {
53257 +  skip "disabled for now", 21;
53258 +$tf_proxy->{PORT} = 2048;
53259 +$tf_proxy->{CONFIGFILE} = 'proxy.conf';
53260 +$tf_proxy->{LIGHTTPD_PIDFILE} = $tf_proxy->{SRCDIR}.'/tmp/lighttpd/lighttpd-proxy.pid';
53261 +
53262 +$tf_backend1->{PORT} = 2050;
53263 +$tf_backend1->{CONFIGFILE} = 'proxy-backend-1.conf';
53264 +$tf_backend1->{LIGHTTPD_PIDFILE} = $tf_backend1->{SRCDIR}.'/tmp/lighttpd/lighttpd-backend-1.pid';
53265 +
53266 +$tf_backend2->{PORT} = 2051;
53267 +$tf_backend2->{CONFIGFILE} = 'proxy-backend-2.conf';
53268 +$tf_backend2->{LIGHTTPD_PIDFILE} = $tf_backend2->{SRCDIR}.'/tmp/lighttpd/lighttpd-backend-2.pid';
53269 +
53270 +
53271 +ok($tf_backend1->start_proc == 0, "Starting lighttpd") or die();
53272 +
53273 +ok($tf_proxy->start_proc == 0, "Starting lighttpd as proxy") or die();
53274 +
53275 +sleep(1);
53276 +
53277 +$t->{REQUEST}  = ( <<EOF
53278 +GET /index.html HTTP/1.0
53279 +Host: www.example.org
53280 +EOF
53281 + );
53282 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53283 +ok($tf_proxy->handle_http($t) == 0, 'valid request');
53284 +
53285 +$t->{REQUEST}  = ( <<EOF
53286 +GET /index.html HTTP/1.0
53287 +Host: www.example.org
53288 +EOF
53289 + );
53290 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Server' => 'proxy-backend-1' } ];
53291 +ok($tf_proxy->handle_http($t) == 0, 'drop Server from real server');
53292 +
53293 +$t->{REQUEST}  = ( <<EOF
53294 +GET /balance-rr/foo HTTP/1.0
53295 +Host: www.example.org
53296 +EOF
53297 + );
53298 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53299 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - one backend');
53300 +
53301 +$t->{REQUEST}  = ( <<EOF
53302 +GET /balance-rr/foo HTTP/1.0
53303 +Host: www.example.org
53304 +EOF
53305 + );
53306 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53307 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - one host down, failover');
53308 +
53309 +$t->{REQUEST}  = ( <<EOF
53310 +GET /balance-fair/foo HTTP/1.0
53311 +Host: www.example.org
53312 +EOF
53313 + );
53314 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53315 +ok($tf_proxy->handle_http($t) == 0, 'balance fair - one backend');
53316 +
53317 +## backend 2 starting 
53318 +ok($tf_backend2->start_proc == 0, "Starting second proxy backend") or die();
53319 +
53320 +$t->{REQUEST}  = ( <<EOF
53321 +GET /balance-rr/foo HTTP/1.0
53322 +Host: www.example.org
53323 +EOF
53324 + );
53325 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53326 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - lb, backend 1');
53327 +
53328 +$t->{REQUEST}  = ( <<EOF
53329 +GET /balance-rr/foo HTTP/1.0
53330 +Host: www.example.org
53331 +EOF
53332 + );
53333 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53334 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - lb, backend 2');
53335 +
53336 +$t->{REQUEST}  = ( <<EOF
53337 +GET /balance-hash/foo HTTP/1.0
53338 +Host: www.example.org
53339 +EOF
53340 + );
53341 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53342 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 1');
53343 +
53344 +$t->{REQUEST}  = ( <<EOF
53345 +GET /balance-hash/foo HTTP/1.0
53346 +Host: www.example.org
53347 +EOF
53348 + );
53349 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53350 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 1 - same URL');
53351 +
53352 +$t->{REQUEST}  = ( <<EOF
53353 +GET /balance-hash/bar HTTP/1.0
53354 +Host: www.example.org
53355 +EOF
53356 + );
53357 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53358 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 2');
53359 +
53360 +$t->{REQUEST}  = ( <<EOF
53361 +GET /balance-hash/bar HTTP/1.0
53362 +Host: www.example.org
53363 +EOF
53364 + );
53365 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53366 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 2 - same URL');
53367 +
53368 +## backend 1 stopping, failover 
53369 +ok($tf_backend1->stop_proc == 0, "Stopping backend 1");
53370 +
53371 +$t->{REQUEST}  = ( <<EOF
53372 +GET /balance-hash/foo HTTP/1.0
53373 +Host: www.example.org
53374 +EOF
53375 + );
53376 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53377 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - failover to backend 2');
53378 +
53379 +$t->{REQUEST}  = ( <<EOF
53380 +GET /balance-hash/bar HTTP/1.0
53381 +Host: www.example.org
53382 +EOF
53383 + );
53384 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53385 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - failover to backend 2 - same URL');
53386 +
53387 +$t->{REQUEST}  = ( <<EOF
53388 +GET /balance-rr/foo HTTP/1.0
53389 +Host: www.example.org
53390 +EOF
53391 + );
53392 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53393 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - failover to backend 2');
53394 +
53395 +$t->{REQUEST}  = ( <<EOF
53396 +GET /balance-fair/foo HTTP/1.0
53397 +Host: www.example.org
53398 +EOF
53399 + );
53400 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53401 +ok($tf_proxy->handle_http($t) == 0, 'balance fair - failover to backend 2');
53402 +
53403 +
53404 +ok($tf_backend2->stop_proc == 0, "Stopping lighttpd");
53405 +
53406 +ok($tf_proxy->stop_proc == 0, "Stopping lighttpd proxy");
53407 +}
53408 --- ../lighttpd-1.4.11/tests/proxy-backend-1.conf       1970-01-01 03:00:00.000000000 +0300
53409 +++ lighttpd-1.4.12/tests/proxy-backend-1.conf  2006-07-16 00:26:05.000000000 +0300
53410 @@ -0,0 +1,7 @@
53411 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53412 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd-backend-1.pid"
53413 +
53414 +include "default.conf"
53415 +
53416 +
53417 +server.tag = "proxy-backend-1"
53418 --- ../lighttpd-1.4.11/tests/proxy-backend-2.conf       1970-01-01 03:00:00.000000000 +0300
53419 +++ lighttpd-1.4.12/tests/proxy-backend-2.conf  2006-07-16 00:26:04.000000000 +0300
53420 @@ -0,0 +1,7 @@
53421 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53422 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd-backend-2.pid"
53423 +
53424 +include "default.conf"
53425 +
53426 +
53427 +server.tag = "proxy-backend-2"
53428 --- ../lighttpd-1.4.11/tests/proxy.conf 1970-01-01 03:00:00.000000000 +0300
53429 +++ lighttpd-1.4.12/tests/proxy.conf    2006-07-16 00:26:05.000000000 +0300
53430 @@ -0,0 +1,26 @@
53431 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53432 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd-proxy.pid"
53433 +server.tag = "proxy"
53434 +
53435 +include "default.conf"
53436 +
53437 +## 127.0.0.1 and 127.0.0.2 are the same host
53438 +proxy.server              = ( 
53439 +  "" => (( "host" => "127.0.0.1",
53440 +          "port" => 2050 ),
53441 +         ( "host" => "127.0.0.2",
53442 +           "port" => 2051 )
53443 +  ))
53444 +               
53445 +$HTTP["url"] =~ "^/balance-rr/" {
53446 +  proxy.balance = "round-robin"
53447 +}
53448 +
53449 +$HTTP["url"] =~ "^/balance-hash/" {
53450 +  proxy.balance = "hash"
53451 +}
53452 +
53453 +$HTTP["url"] =~ "^/balance-fair/" {
53454 +  proxy.balance = "fair"
53455 +}
53456 +
53457 --- ../lighttpd-1.4.11/tests/var-include.conf   2005-08-27 17:44:19.000000000 +0300
53458 +++ lighttpd-1.4.12/tests/var-include.conf      2006-07-16 00:26:05.000000000 +0300
53459 @@ -2,15 +2,15 @@
53460  debug.log-request-handling = "enable"
53461  debug.log-condition-handling = "enable"
53462  
53463 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53464 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
53465 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53466 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53467  
53468  ## bind to port (default: 80)
53469  server.port                 = 2048
53470  
53471  ## bind to localhost (default: all interfaces)
53472  server.bind                = "localhost"
53473 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
53474 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53475  server.name                = "www.example.org"
53476  server.tag                 = "Apache 1.3.29"
53477  
53478 @@ -21,19 +21,19 @@
53479  ######################## MODULE CONFIG ############################
53480  
53481  
53482 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
53483 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
53484  
53485  mimetype.assign             = ( ".html" => "text/html" )
53486  
53487  url.redirect = ("^" => "/default")
53488  
53489  $HTTP["host"] == "www.example.org" {
53490 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53491 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53492    server.name = "www.example.org"
53493    url.redirect = ("^" => "/redirect")
53494  }
53495  $HTTP["host"] == "test.example.org" {
53496 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53497 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53498    server.name = "test.example.org"
53499    var.myvar = "good"
53500    var.one = 1
This page took 5.351743 seconds and 4 git commands to generate.