]> git.pld-linux.org Git - packages/lighttpd.git/blob - lighttpd-branch.diff
- r1202
[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 17:34:32.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,14 @@
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 \
874 +                           mod_proxy_core_backlog.c mod_proxy_core_rewrites.c
875 +mod_proxy_core_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
876 +mod_proxy_core_la_LIBADD = $(common_libadd) $(PCRE_LIB)
877 +
878 +
879  lib_LTLIBRARIES += mod_ssi.la
880  mod_ssi_la_SOURCES = mod_ssi_exprparser.c mod_ssi_expr.c mod_ssi.c 
881  mod_ssi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
882 @@ -240,7 +259,12 @@
883        mod_ssi.h mod_ssi_expr.h inet_ntop_cache.h \
884        configparser.h mod_ssi_exprparser.h \
885        sys-mmap.h sys-socket.h mod_cml.h mod_cml_funcs.h \
886 -      splaytree.h proc_open.h
887 +      splaytree.h proc_open.h http_resp.h mod_sql_vhost_core.h \
888 +      sys-files.h sys-process.h sys-strings.h http_resp_parser.h \
889 +      iosocket.h array-static.h \
890 +      mod_proxy_core_address.h mod_proxy_core_backend.h \
891 +      mod_proxy_core_backlog.h mod_proxy_core.h  \
892 +      mod_proxy_core_pool.h mod_proxy_core_rewrites.h
893  
894  DEFS= @DEFS@ -DLIBRARY_DIR="\"$(libdir)\""
895  
896 @@ -267,4 +291,4 @@
897  #ajp_SOURCES = ajp.c
898  
899  noinst_HEADERS   = $(hdr)
900 -EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c
901 +EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c http_resp_parser.y
902 --- ../lighttpd-1.4.11/src/array-static.h       1970-01-01 03:00:00.000000000 +0300
903 +++ lighttpd-1.4.12/src/array-static.h  2006-07-18 13:03:40.000000000 +0300
904 @@ -0,0 +1,33 @@
905 +#ifndef _ARRAY_STATIC_H_
906 +#define _ARRAY_STATIC_H_
907 +
908 +/* define a generic array of <type>
909 + * */
910 +
911 +#define ARRAY_STATIC_DEF(name, type, extra) \
912 +typedef struct { \
913 +       type **ptr; \
914 +       size_t used; \
915 +       size_t size; \
916 +       extra\
917 +} name
918 +
919 +/* all append operations need a 'resize' for the +1 */
920 +
921 +#define ARRAY_STATIC_PREPARE_APPEND(a) \
922 +        if (a->size == 0) { \
923 +               a->size = 16; \
924 +               a->ptr = malloc(a->size * sizeof(*(a->ptr))); \
925 +       } else if (a->size == a->used) { \
926 +               a->size += 16; \
927 +               a->ptr = realloc(a->ptr, a->size * sizeof(*(a->ptr))); \
928 +       }
929 +       
930 +#define FOREACH(array, element, func) \
931 +do { size_t _i; for (_i = 0; _i < array->used; _i++) { void *element = array->ptr[_i]; func; } } while(0);
932 +
933 +#define STRUCT_INIT(type, var) \
934 +       type *var;\
935 +       var = calloc(1, sizeof(*var))
936 +
937 +#endif
938 --- ../lighttpd-1.4.11/src/array.c      2005-11-18 13:58:32.000000000 +0200
939 +++ lighttpd-1.4.12/src/array.c 2006-07-16 00:26:03.000000000 +0300
940 @@ -11,12 +11,12 @@
941  
942  array *array_init(void) {
943         array *a;
944 -       
945 +
946         a = calloc(1, sizeof(*a));
947         assert(a);
948 -       
949 +
950         a->next_power_of_2 = 1;
951 -       
952 +
953         return a;
954  }
955  
956 @@ -43,29 +43,29 @@
957  void array_free(array *a) {
958         size_t i;
959         if (!a) return;
960 -       
961 +
962         if (!a->is_weakref) {
963                 for (i = 0; i < a->size; i++) {
964                         if (a->data[i]) a->data[i]->free(a->data[i]);
965                 }
966         }
967 -       
968 +
969         if (a->data) free(a->data);
970         if (a->sorted) free(a->sorted);
971 -       
972 +
973         free(a);
974  }
975  
976  void array_reset(array *a) {
977         size_t i;
978         if (!a) return;
979 -       
980 +
981         if (!a->is_weakref) {
982                 for (i = 0; i < a->used; i++) {
983                         a->data[i]->reset(a->data[i]);
984                 }
985         }
986 -       
987 +
988         a->used = 0;
989  }
990  
991 @@ -84,20 +84,20 @@
992  static int array_get_index(array *a, const char *key, size_t keylen, int *rndx) {
993         int ndx = -1;
994         int i, pos = 0;
995 -       
996 +
997         if (key == NULL) return -1;
998 -       
999 +
1000         /* try to find the string */
1001         for (i = pos = a->next_power_of_2 / 2; ; i >>= 1) {
1002                 int cmp;
1003 -               
1004 +
1005                 if (pos < 0) {
1006                         pos += i;
1007                 } else if (pos >= (int)a->used) {
1008                         pos -= i;
1009                 } else {
1010                         cmp = buffer_caseless_compare(key, keylen, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used);
1011 -                       
1012 +
1013                         if (cmp == 0) {
1014                                 /* found */
1015                                 ndx = a->sorted[pos];
1016 @@ -110,46 +110,46 @@
1017                 }
1018                 if (i == 0) break;
1019         }
1020 -       
1021 +
1022         if (rndx) *rndx = pos;
1023 -       
1024 +
1025         return ndx;
1026  }
1027  
1028  data_unset *array_get_element(array *a, const char *key) {
1029         int ndx;
1030 -       
1031 +
1032         if (-1 != (ndx = array_get_index(a, key, strlen(key) + 1, NULL))) {
1033                 /* found, leave here */
1034 -               
1035 +
1036                 return a->data[ndx];
1037 -       } 
1038 -       
1039 +       }
1040 +
1041         return NULL;
1042  }
1043  
1044  data_unset *array_get_unused_element(array *a, data_type_t t) {
1045         data_unset *ds = NULL;
1046 -       
1047 +
1048         UNUSED(t);
1049  
1050         if (a->size == 0) return NULL;
1051 -       
1052 +
1053         if (a->used == a->size) return NULL;
1054  
1055         if (a->data[a->used]) {
1056                 ds = a->data[a->used];
1057 -               
1058 +
1059                 a->data[a->used] = NULL;
1060         }
1061 -       
1062 +
1063         return ds;
1064  }
1065  
1066  /* replace or insert data, return the old one with the same key */
1067  data_unset *array_replace(array *a, data_unset *du) {
1068         int ndx;
1069 -       
1070 +
1071         if (-1 == (ndx = array_get_index(a, du->key->ptr, du->key->used, NULL))) {
1072                 array_insert_unique(a, du);
1073                 return NULL;
1074 @@ -164,13 +164,13 @@
1075         int ndx = -1;
1076         int pos = 0;
1077         size_t j;
1078 -       
1079 -       /* generate unique index if neccesary */
1080 +
1081 +       /* generate unique index if necessary */
1082         if (str->key->used == 0 || str->is_index_key) {
1083                 buffer_copy_long(str->key, a->unique_ndx++);
1084                 str->is_index_key = 1;
1085         }
1086 -       
1087 +
1088         /* try to find the string */
1089         if (-1 != (ndx = array_get_index(a, str->key->ptr, str->key->used, &pos))) {
1090                 /* found, leave here */
1091 @@ -181,14 +181,14 @@
1092                 }
1093                 return 0;
1094         }
1095 -       
1096 +
1097         /* insert */
1098 -       
1099 +
1100         if (a->used+1 > INT_MAX) {
1101                 /* we can't handle more then INT_MAX entries: see array_get_index() */
1102                 return -1;
1103         }
1104 -       
1105 +
1106         if (a->size == 0) {
1107                 a->size   = 16;
1108                 a->data   = malloc(sizeof(*a->data)     * a->size);
1109 @@ -204,27 +204,27 @@
1110                 assert(a->sorted);
1111                 for (j = a->used; j < a->size; j++) a->data[j] = NULL;
1112         }
1113 -       
1114 +
1115         ndx = (int) a->used;
1116 -       
1117 +
1118         a->data[a->used++] = str;
1119 -       
1120 +
1121         if (pos != ndx &&
1122 -           ((pos < 0) || 
1123 +           ((pos < 0) ||
1124              buffer_caseless_compare(str->key->ptr, str->key->used, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used) > 0)) {
1125                 pos++;
1126 -       } 
1127 -       
1128 -       /* move everything on step to the right */
1129 +       }
1130 +
1131 +       /* move everything one step to the right */
1132         if (pos != ndx) {
1133                 memmove(a->sorted + (pos + 1), a->sorted + (pos), (ndx - pos) * sizeof(*a->sorted));
1134         }
1135 -       
1136 +
1137         /* insert */
1138         a->sorted[pos] = ndx;
1139 -       
1140 +
1141         if (a->next_power_of_2 == (size_t)ndx) a->next_power_of_2 <<= 1;
1142 -       
1143 +
1144         return 0;
1145  }
1146  
1147 @@ -254,7 +254,7 @@
1148         size_t i;
1149         size_t maxlen;
1150         int oneline = 1;
1151 -       
1152 +
1153         if (a->used > 5) {
1154                 oneline = 0;
1155         }
1156 @@ -314,7 +314,7 @@
1157         }
1158         array_print_indent(depth);
1159         fprintf(stderr, ")");
1160 -       
1161 +
1162         return 0;
1163  }
1164  
1165 @@ -323,47 +323,47 @@
1166         array *a;
1167         data_string *ds;
1168         data_count *dc;
1169 -       
1170 +
1171         UNUSED(argc);
1172         UNUSED(argv);
1173  
1174         a = array_init();
1175 -       
1176 +
1177         ds = data_string_init();
1178         buffer_copy_string(ds->key, "abc");
1179         buffer_copy_string(ds->value, "alfrag");
1180 -       
1181 +
1182         array_insert_unique(a, (data_unset *)ds);
1183 -       
1184 +
1185         ds = data_string_init();
1186         buffer_copy_string(ds->key, "abc");
1187         buffer_copy_string(ds->value, "hameplman");
1188 -       
1189 +
1190         array_insert_unique(a, (data_unset *)ds);
1191 -       
1192 +
1193         ds = data_string_init();
1194         buffer_copy_string(ds->key, "123");
1195         buffer_copy_string(ds->value, "alfrag");
1196 -       
1197 +
1198         array_insert_unique(a, (data_unset *)ds);
1199 -       
1200 +
1201         dc = data_count_init();
1202         buffer_copy_string(dc->key, "def");
1203 -       
1204 +
1205         array_insert_unique(a, (data_unset *)dc);
1206 -       
1207 +
1208         dc = data_count_init();
1209         buffer_copy_string(dc->key, "def");
1210 -       
1211 +
1212         array_insert_unique(a, (data_unset *)dc);
1213 -       
1214 +
1215         array_print(a, 0);
1216 -       
1217 +
1218         array_free(a);
1219 -       
1220 +
1221         fprintf(stderr, "%d\n",
1222                buffer_caseless_compare(CONST_STR_LEN("Content-Type"), CONST_STR_LEN("Content-type")));
1223 -       
1224 +
1225         return 0;
1226  }
1227  #endif
1228 --- ../lighttpd-1.4.11/src/array.h      2005-09-23 21:24:18.000000000 +0300
1229 +++ lighttpd-1.4.12/src/array.h 2006-07-16 00:26:03.000000000 +0300
1230 @@ -16,7 +16,7 @@
1231  #define DATA_UNSET \
1232         data_type_t type; \
1233         buffer *key; \
1234 -       int is_index_key; /* 1 if key is a array index (autogenerated keys) */ \
1235 +       int is_index_key; /* 1 if key is an array index (auto-generated keys) */ \
1236         struct data_unset *(*copy)(const struct data_unset *src); \
1237         void (* free)(struct data_unset *p); \
1238         void (* reset)(struct data_unset *p); \
1239 @@ -29,21 +29,21 @@
1240  
1241  typedef struct {
1242         data_unset  **data;
1243 -       
1244 +
1245         size_t *sorted;
1246 -       
1247 +
1248         size_t used;
1249         size_t size;
1250 -       
1251 +
1252         size_t unique_ndx;
1253 -       
1254 +
1255         size_t next_power_of_2;
1256         int is_weakref; /* data is weakref, don't bother the data */
1257  } array;
1258  
1259  typedef struct {
1260         DATA_UNSET;
1261 -       
1262 +
1263         int count;
1264  } data_count;
1265  
1266 @@ -51,7 +51,7 @@
1267  
1268  typedef struct {
1269         DATA_UNSET;
1270 -       
1271 +
1272         buffer *value;
1273  } data_string;
1274  
1275 @@ -60,7 +60,7 @@
1276  
1277  typedef struct {
1278         DATA_UNSET;
1279 -       
1280 +
1281         array *value;
1282  } data_array;
1283  
1284 @@ -74,7 +74,7 @@
1285         COMP_SERVER_SOCKET, COMP_HTTP_URL, COMP_HTTP_HOST, COMP_HTTP_REFERER, COMP_HTTP_USERAGENT, COMP_HTTP_COOKIE, COMP_HTTP_REMOTEIP
1286  } comp_key_t;
1287  
1288 -/* $HTTP["host"] ==    "incremental.home.kneschke.de" { ... } 
1289 +/* $HTTP["host"] ==    "incremental.home.kneschke.de" { ... }
1290   * for print:   comp_key      op    string
1291   * for compare: comp          cond  string/regex
1292   */
1293 @@ -82,15 +82,15 @@
1294  typedef struct _data_config data_config;
1295  struct _data_config {
1296         DATA_UNSET;
1297 -       
1298 +
1299         array *value;
1300 -       
1301 +
1302         buffer *comp_key;
1303         comp_key_t comp;
1304 -       
1305 +
1306         config_cond_t cond;
1307         buffer *op;
1308 -       
1309 +
1310         int context_ndx; /* more or less like an id */
1311         array *childs;
1312         /* nested */
1313 @@ -98,7 +98,7 @@
1314         /* for chaining only */
1315         data_config *prev;
1316         data_config *next;
1317 -       
1318 +
1319         buffer *string;
1320  #ifdef HAVE_PCRE_H
1321         pcre   *regex;
1322 @@ -110,7 +110,7 @@
1323  
1324  typedef struct {
1325         DATA_UNSET;
1326 -       
1327 +
1328         int value;
1329  } data_integer;
1330  
1331 @@ -120,13 +120,13 @@
1332         DATA_UNSET;
1333  
1334         buffer *host;
1335 -       
1336 +
1337         unsigned short port;
1338  
1339         time_t disable_ts;
1340         int is_disabled;
1341         size_t balance;
1342 -               
1343 +
1344         int usage; /* fair-balancing needs the no. of connections active on this host */
1345         int last_used_ndx; /* round robin */
1346  } data_fastcgi;
1347 --- ../lighttpd-1.4.11/src/base.h       2006-01-11 16:51:04.000000000 +0200
1348 +++ lighttpd-1.4.12/src/base.h  2006-07-18 13:03:40.000000000 +0300
1349 @@ -2,7 +2,6 @@
1350  #define _BASE_H_
1351  
1352  #include <sys/types.h>
1353 -#include <sys/time.h>
1354  #include <sys/stat.h>
1355  
1356  #ifdef HAVE_CONFIG_H
1357 @@ -26,10 +25,9 @@
1358  #include "sys-socket.h"
1359  #include "splaytree.h"
1360  
1361 -
1362  #if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
1363  # define USE_OPENSSL
1364 -# include <openssl/ssl.h> 
1365 +# include <openssl/ssl.h>
1366  #endif
1367  
1368  #ifdef HAVE_FAM_H
1369 @@ -40,10 +38,6 @@
1370  # define O_BINARY 0
1371  #endif
1372  
1373 -#ifndef O_LARGEFILE
1374 -# define O_LARGEFILE 0
1375 -#endif
1376 -
1377  #ifndef SIZE_MAX
1378  # ifdef SIZE_T_MAX
1379  #  define SIZE_MAX SIZE_T_MAX
1380 @@ -70,7 +64,8 @@
1381  
1382  /* solaris and NetBSD 1.3.x again */
1383  #if (!defined(HAVE_STDINT_H)) && (!defined(HAVE_INTTYPES_H)) && (!defined(uint32_t))
1384 -# define uint32_t u_int32_t
1385 +/* # define uint32_t u_int32_t */
1386 +typedef unsigned __int32 uint32_t;
1387  #endif
1388  
1389  
1390 @@ -80,24 +75,24 @@
1391  
1392  #include "settings.h"
1393  
1394 -typedef enum { T_CONFIG_UNSET, 
1395 -               T_CONFIG_STRING, 
1396 -               T_CONFIG_SHORT, 
1397 -               T_CONFIG_BOOLEAN, 
1398 -               T_CONFIG_ARRAY, 
1399 -               T_CONFIG_LOCAL, 
1400 +typedef enum { T_CONFIG_UNSET,
1401 +               T_CONFIG_STRING,
1402 +               T_CONFIG_SHORT,
1403 +               T_CONFIG_BOOLEAN,
1404 +               T_CONFIG_ARRAY,
1405 +               T_CONFIG_LOCAL,
1406                 T_CONFIG_DEPRECATED
1407  } config_values_type_t;
1408  
1409 -typedef enum { T_CONFIG_SCOPE_UNSET, 
1410 -               T_CONFIG_SCOPE_SERVER, 
1411 +typedef enum { T_CONFIG_SCOPE_UNSET,
1412 +               T_CONFIG_SCOPE_SERVER,
1413                 T_CONFIG_SCOPE_CONNECTION
1414  } config_scope_type_t;
1415  
1416  typedef struct {
1417         const char *key;
1418         void *destination;
1419 -       
1420 +
1421         config_values_type_t type;
1422         config_scope_type_t scope;
1423  } config_values_t;
1424 @@ -118,18 +113,6 @@
1425         short factor;
1426  } fcgi_connections;
1427  
1428 -
1429 -typedef union {
1430 -#ifdef HAVE_IPV6
1431 -       struct sockaddr_in6 ipv6;
1432 -#endif
1433 -       struct sockaddr_in ipv4;
1434 -#ifdef HAVE_SYS_UN_H
1435 -       struct sockaddr_un un;
1436 -#endif
1437 -       struct sockaddr plain;
1438 -} sock_addr;
1439 -
1440  /* fcgi_response_header contains ... */
1441  #define HTTP_STATUS         BV(0)
1442  #define HTTP_CONNECTION     BV(1)
1443 @@ -142,40 +125,40 @@
1444         /* the request-line */
1445         buffer *request;
1446         buffer *uri;
1447 -       
1448 +
1449         buffer *orig_uri;
1450 -       
1451 +
1452         http_method_t  http_method;
1453         http_version_t http_version;
1454 -       
1455 +
1456         buffer *request_line;
1457 -       
1458 +
1459         /* strings to the header */
1460         buffer *http_host; /* not alloced */
1461         const char   *http_range;
1462         const char   *http_content_type;
1463         const char   *http_if_modified_since;
1464         const char   *http_if_none_match;
1465 -       
1466 +
1467         array  *headers;
1468 -       
1469 +
1470         /* CONTENT */
1471         size_t content_length; /* returned by strtoul() */
1472 -       
1473 +
1474         /* internal representation */
1475         int     accept_encoding;
1476 -       
1477 +
1478         /* internal */
1479         buffer *pathinfo;
1480  } request;
1481  
1482  typedef struct {
1483         off_t   content_length;
1484 -       int     keep_alive;               /* used by  the subrequests in proxy, cgi and fcgi to say the subrequest was keep-alive or not */
1485 -       
1486 +       int     keep_alive;               /* used by the subrequests in proxy, cgi and fcgi to say whether the subrequest was keep-alive or not */
1487 +
1488         array  *headers;
1489 -       
1490 -       enum { 
1491 +
1492 +       enum {
1493                 HTTP_TRANSFER_ENCODING_IDENTITY, HTTP_TRANSFER_ENCODING_CHUNKED
1494         } transfer_encoding;
1495  } response;
1496 @@ -191,21 +174,21 @@
1497  typedef struct {
1498         buffer *path;
1499         buffer *basedir; /* path = "(basedir)(.*)" */
1500 -       
1501 +
1502         buffer *doc_root; /* path = doc_root + rel_path */
1503         buffer *rel_path;
1504 -       
1505 +
1506         buffer *etag;
1507  } physical;
1508  
1509  typedef struct {
1510         buffer *name;
1511         buffer *etag;
1512 -       
1513 +
1514         struct stat st;
1515 -       
1516 +
1517         time_t stat_ts;
1518 -       
1519 +
1520  #ifdef HAVE_FAM_H
1521         int    dir_version;
1522         int    dir_ndx;
1523 @@ -215,20 +198,20 @@
1524  } stat_cache_entry;
1525  
1526  typedef struct {
1527 -       splay_tree *files; /* the nodes of the tree are stat_cache_entry's */
1528 -       
1529 +       splay_tree *files; /* the nodes of the tree are stat_cache_entries */
1530 +
1531         buffer *dir_name; /* for building the dirname from the filename */
1532  #ifdef HAVE_FAM_H
1533         splay_tree *dirs; /* the nodes of the tree are fam_dir_entry */
1534  
1535         FAMConnection *fam;
1536 -       int    fam_fcce_ndx;
1537 +       iosocket *sock;
1538  #endif
1539  } stat_cache;
1540  
1541  typedef struct {
1542         array *mimetypes;
1543 -       
1544 +
1545         /* virtual-servers */
1546         buffer *document_root;
1547         buffer *server_name;
1548 @@ -236,7 +219,7 @@
1549         buffer *server_tag;
1550         buffer *dirlist_encoding;
1551         buffer *errorfile_prefix;
1552 -       
1553 +
1554         unsigned short max_keep_alive_requests;
1555         unsigned short max_keep_alive_idle;
1556         unsigned short max_read_idle;
1557 @@ -244,16 +227,17 @@
1558         unsigned short use_xattr;
1559         unsigned short follow_symlink;
1560         unsigned short range_requests;
1561 -       
1562 +
1563         /* debug */
1564 -       
1565 +
1566         unsigned short log_file_not_found;
1567         unsigned short log_request_header;
1568         unsigned short log_request_handling;
1569         unsigned short log_response_header;
1570         unsigned short log_condition_handling;
1571 -       
1572 -       
1573 +       unsigned short log_condition_cache_handling;
1574 +
1575 +
1576         /* server wide */
1577         buffer *ssl_pemfile;
1578         buffer *ssl_ca_file;
1579 @@ -268,22 +252,22 @@
1580         /* configside */
1581         unsigned short global_kbytes_per_second; /*  */
1582  
1583 -       off_t  global_bytes_per_second_cnt; 
1584 +       off_t  global_bytes_per_second_cnt;
1585         /* server-wide traffic-shaper
1586 -        * 
1587 +        *
1588          * each context has the counter which is inited once
1589 -        * a second by the global_kbytes_per_second config-var
1590 +        * per second by the global_kbytes_per_second config-var
1591          *
1592          * as soon as global_kbytes_per_second gets below 0
1593          * the connected conns are "offline" a little bit
1594          *
1595          * the problem:
1596 -        * we somehow have to loose our "we are writable" signal 
1597 +        * we somehow have to lose our "we are writable" signal
1598          * on the way.
1599 -        * 
1600 +        *
1601          */
1602         off_t *global_bytes_per_second_cnt_ptr; /*  */
1603 -       
1604 +
1605  #ifdef USE_OPENSSL
1606         SSL_CTX *ssl_ctx;
1607  #endif
1608 @@ -291,18 +275,18 @@
1609  
1610  /* the order of the items should be the same as they are processed
1611   * read before write as we use this later */
1612 -typedef enum { 
1613 -       CON_STATE_CONNECT, 
1614 -       CON_STATE_REQUEST_START, 
1615 -       CON_STATE_READ, 
1616 -       CON_STATE_REQUEST_END, 
1617 -       CON_STATE_READ_POST, 
1618 -       CON_STATE_HANDLE_REQUEST, 
1619 -       CON_STATE_RESPONSE_START, 
1620 -       CON_STATE_WRITE, 
1621 -       CON_STATE_RESPONSE_END, 
1622 -       CON_STATE_ERROR, 
1623 -       CON_STATE_CLOSE 
1624 +typedef enum {
1625 +       CON_STATE_CONNECT,
1626 +       CON_STATE_REQUEST_START,
1627 +       CON_STATE_READ,
1628 +       CON_STATE_REQUEST_END,
1629 +       CON_STATE_READ_POST,
1630 +       CON_STATE_HANDLE_REQUEST,
1631 +       CON_STATE_RESPONSE_START,
1632 +       CON_STATE_WRITE,
1633 +       CON_STATE_RESPONSE_END,
1634 +       CON_STATE_ERROR,
1635 +       CON_STATE_CLOSE
1636  } connection_state_t;
1637  
1638  typedef enum { COND_RESULT_UNSET, COND_RESULT_FALSE, COND_RESULT_TRUE } cond_result_t;
1639 @@ -315,91 +299,86 @@
1640  
1641  typedef struct {
1642         connection_state_t state;
1643 -       
1644 +
1645         /* timestamps */
1646         time_t read_idle_ts;
1647         time_t close_timeout_ts;
1648         time_t write_request_ts;
1649 -       
1650 +
1651         time_t connection_start;
1652         time_t request_start;
1653 -       
1654 +
1655         struct timeval start_tv;
1656 -       
1657 +
1658         size_t request_count;        /* number of requests handled in this connection */
1659         size_t loops_per_request;    /* to catch endless loops in a single request
1660 -                                     * 
1661 +                                     *
1662                                       * used by mod_rewrite, mod_fastcgi, ... and others
1663                                       * this is self-protection
1664                                       */
1665 -       
1666 -       int fd;                      /* the FD for this connection */
1667 -       int fde_ndx;                 /* index for the fdevent-handler */
1668 +
1669 +       iosocket *sock;
1670         int ndx;                     /* reverse mapping to server->connection[ndx] */
1671 -       
1672 +
1673         /* fd states */
1674         int is_readable;
1675         int is_writable;
1676 -       
1677 -       int     keep_alive;           /* only request.c can enable it, all other just disable */
1678 -       
1679 +
1680 +       int     keep_alive;           /* only request.c can enable it, all others just disable */
1681 +
1682         int file_started;
1683         int file_finished;
1684 -       
1685 +
1686         chunkqueue *write_queue;      /* a large queue for low-level write ( HTTP response ) [ file, mem ] */
1687         chunkqueue *read_queue;       /* a small queue for low-level read ( HTTP request ) [ mem ] */
1688         chunkqueue *request_content_queue; /* takes request-content into tempfile if necessary [ tempfile, mem ]*/
1689 -       
1690 +
1691         int traffic_limit_reached;
1692 -       
1693 +
1694         off_t bytes_written;          /* used by mod_accesslog, mod_rrd */
1695         off_t bytes_written_cur_second; /* used by mod_accesslog, mod_rrd */
1696         off_t bytes_read;             /* used by mod_accesslog, mod_rrd */
1697         off_t bytes_header;
1698 -       
1699 +
1700         int http_status;
1701 -       
1702 +
1703         sock_addr dst_addr;
1704         buffer *dst_addr_buf;
1705  
1706         /* request */
1707         buffer *parse_request;
1708         unsigned int parsed_response; /* bitfield which contains the important header-fields of the parsed response header */
1709 -       
1710 +
1711         request  request;
1712         request_uri uri;
1713 -       physical physical; 
1714 +       physical physical;
1715         response response;
1716 -       
1717 +
1718         size_t header_len;
1719 -       
1720 +
1721         buffer *authed_user;
1722         array  *environment; /* used to pass lighttpd internal stuff to the FastCGI/CGI apps, setenv does that */
1723 -       
1724 +
1725         /* response */
1726         int    got_response;
1727 -       
1728 +
1729         int    in_joblist;
1730 -       
1731 +
1732         connection_type mode;
1733 -       
1734 +
1735         void **plugin_ctx;           /* plugin connection specific config */
1736 -       
1737 +
1738         specific_config conf;        /* global connection specific config */
1739         cond_cache_t *cond_cache;
1740 -       
1741 +
1742         buffer *server_name;
1743 -       
1744 +
1745         /* error-handler */
1746         buffer *error_handler;
1747         int error_handler_saved_status;
1748         int in_error_handler;
1749 -       
1750 +
1751         void *srv_socket;   /* reference to the server-socket (typecast to server_socket) */
1752 -       
1753 -#ifdef USE_OPENSSL
1754 -       SSL *ssl;
1755 -#endif
1756  } connection;
1757  
1758  typedef struct {
1759 @@ -439,55 +418,63 @@
1760         size_t size;
1761  } buffer_plugin;
1762  
1763 +typedef enum {
1764 +    NETWORK_STATUS_UNSET,
1765 +    NETWORK_STATUS_SUCCESS,
1766 +    NETWORK_STATUS_FATAL_ERROR,
1767 +    NETWORK_STATUS_CONNECTION_CLOSE,
1768 +    NETWORK_STATUS_WAIT_FOR_EVENT,
1769 +    NETWORK_STATUS_INTERRUPTED
1770 +} network_status_t;
1771 +
1772  typedef struct {
1773         unsigned short port;
1774         buffer *bindhost;
1775 -       
1776 -       buffer *errorlog_file;
1777 -       unsigned short errorlog_use_syslog;
1778 -       
1779 +
1780         unsigned short dont_daemonize;
1781         buffer *changeroot;
1782         buffer *username;
1783         buffer *groupname;
1784 -       
1785 +
1786         buffer *pid_file;
1787 -       
1788 +
1789         buffer *event_handler;
1790 -       
1791 +
1792         buffer *modules_dir;
1793         buffer *network_backend;
1794         array *modules;
1795         array *upload_tempdirs;
1796 -       
1797 +
1798         unsigned short max_worker;
1799         unsigned short max_fds;
1800         unsigned short max_conns;
1801         unsigned short max_request_size;
1802 -       
1803 +
1804         unsigned short log_request_header_on_error;
1805         unsigned short log_state_handling;
1806 -       
1807 -       enum { STAT_CACHE_ENGINE_UNSET, 
1808 -                       STAT_CACHE_ENGINE_NONE, 
1809 -                       STAT_CACHE_ENGINE_SIMPLE, 
1810 -                       STAT_CACHE_ENGINE_FAM 
1811 +
1812 +       enum { STAT_CACHE_ENGINE_UNSET,
1813 +                       STAT_CACHE_ENGINE_NONE,
1814 +                       STAT_CACHE_ENGINE_SIMPLE,
1815 +                       STAT_CACHE_ENGINE_FAM
1816         } stat_cache_engine;
1817         unsigned short enable_cores;
1818 +
1819 +       buffer *errorlog_file;
1820 +       unsigned short errorlog_use_syslog;
1821  } server_config;
1822  
1823  typedef struct {
1824         sock_addr addr;
1825 -       int       fd;
1826 -       int       fde_ndx;
1827 -       
1828 +       iosocket *sock;
1829 +
1830         buffer *ssl_pemfile;
1831         buffer *ssl_ca_file;
1832         unsigned short use_ipv6;
1833         unsigned short is_ssl;
1834 -       
1835 +
1836         buffer *srv_token;
1837 -       
1838 +
1839  #ifdef USE_OPENSSL
1840         SSL_CTX *ssl_ctx;
1841  #endif
1842 @@ -495,37 +482,32 @@
1843  
1844  typedef struct {
1845         server_socket **ptr;
1846 -       
1847 +
1848         size_t size;
1849         size_t used;
1850  } server_socket_array;
1851  
1852  typedef struct server {
1853         server_socket_array srv_sockets;
1854 -       
1855 -       /* the errorlog */
1856 -       int errorlog_fd;
1857 -       enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG } errorlog_mode;
1858 -       buffer *errorlog_buf;
1859 -       
1860 +
1861         fdevents *ev, *ev_ins;
1862 -       
1863 +
1864         buffer_plugin plugins;
1865         void *plugin_slots;
1866 -       
1867 +
1868         /* counters */
1869         int con_opened;
1870         int con_read;
1871         int con_written;
1872         int con_closed;
1873 -       
1874 +
1875         int ssl_is_init;
1876 -       
1877 +
1878         int max_fds;    /* max possible fds */
1879         int cur_fds;    /* currently used fds */
1880         int want_fds;   /* waiting fds */
1881         int sockets_disabled;
1882 -       
1883 +
1884         size_t max_conns;
1885  
1886         /* buffers */
1887 @@ -533,13 +515,13 @@
1888         buffer *response_header;
1889         buffer *response_range;
1890         buffer *tmp_buf;
1891 -       
1892 +
1893         buffer *tmp_chunk_len;
1894 -       
1895 +
1896         buffer *empty_string; /* is necessary for cond_match */
1897  
1898         buffer *cond_check_buf;
1899 -       
1900 +
1901         /* caches */
1902  #ifdef HAVE_IPV6
1903         inet_ntop_cache_type inet_ntop_cache[INET_NTOP_CACHE_MAX];
1904 @@ -547,31 +529,31 @@
1905         mtime_cache_type mtime_cache[FILE_CACHE_MAX];
1906  
1907         array *split_vals;
1908 -       
1909 +
1910         /* Timestamps */
1911         time_t cur_ts;
1912         time_t last_generated_date_ts;
1913         time_t last_generated_debug_ts;
1914         time_t startup_ts;
1915 -       
1916 +
1917         buffer *ts_debug_str;
1918         buffer *ts_date_str;
1919 -       
1920 +
1921         /* config-file */
1922         array *config;
1923         array *config_touched;
1924 -       
1925 +
1926         array *config_context;
1927         specific_config **config_storage;
1928 -       
1929 +
1930         server_config  srvconf;
1931 -       
1932 +
1933         int config_deprecated;
1934 -       
1935 +
1936         connections *conns;
1937         connections *joblist;
1938         connections *fdwaitqueue;
1939 -       
1940 +
1941         stat_cache  *stat_cache;
1942  
1943         /**
1944 @@ -588,18 +570,20 @@
1945          *   fastcgi.backend.<key>.disconnects = ...
1946          */
1947         array *status;
1948 -       
1949 +
1950         fdevent_handler_t event_handler;
1951  
1952 -       int (* network_backend_write)(struct server *srv, connection *con, int fd, chunkqueue *cq);
1953 -       int (* network_backend_read)(struct server *srv, connection *con, int fd, chunkqueue *cq);
1954 +       network_status_t (* network_backend_write)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1955 +       network_status_t (* network_backend_read)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1956  #ifdef USE_OPENSSL
1957 -       int (* network_ssl_backend_write)(struct server *srv, connection *con, SSL *ssl, chunkqueue *cq);
1958 -       int (* network_ssl_backend_read)(struct server *srv, connection *con, SSL *ssl, chunkqueue *cq);
1959 +       network_status_t (* network_ssl_backend_write)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1960 +       network_status_t (* network_ssl_backend_read)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1961  #endif
1962  
1963 +#ifdef HAVE_PWD_H
1964         uid_t uid;
1965         gid_t gid;
1966 +#endif
1967  } server;
1968  
1969  
1970 --- ../lighttpd-1.4.11/src/bitset.c     2005-08-22 01:54:12.000000000 +0300
1971 +++ lighttpd-1.4.12/src/bitset.c        2006-07-18 13:03:40.000000000 +0300
1972 @@ -6,6 +6,7 @@
1973  
1974  #include "bitset.h"
1975  #include "buffer.h"
1976 +#include "log.h"
1977  
1978  #define BITSET_BITS \
1979         ( CHAR_BIT * sizeof(size_t) )
1980 --- ../lighttpd-1.4.11/src/buffer.c     2006-01-13 00:00:45.000000000 +0200
1981 +++ lighttpd-1.4.12/src/buffer.c        2006-07-18 13:03:40.000000000 +0300
1982 @@ -12,20 +12,20 @@
1983  
1984  
1985  /**
1986 - * init the buffer 
1987 - * 
1988 + * init the buffer
1989 + *
1990   */
1991  
1992  buffer* buffer_init(void) {
1993         buffer *b;
1994 -       
1995 +
1996         b = malloc(sizeof(*b));
1997         assert(b);
1998 -       
1999 +
2000         b->ptr = NULL;
2001         b->size = 0;
2002         b->used = 0;
2003 -       
2004 +
2005         return b;
2006  }
2007  
2008 @@ -36,8 +36,8 @@
2009  }
2010  
2011  /**
2012 - * free the buffer 
2013 - * 
2014 + * free the buffer
2015 + *
2016   */
2017  
2018  void buffer_free(buffer *b) {
2019 @@ -49,39 +49,39 @@
2020  
2021  void buffer_reset(buffer *b) {
2022         if (!b) return;
2023 -       
2024 +
2025         /* limit don't reuse buffer larger than ... bytes */
2026         if (b->size > BUFFER_MAX_REUSE_SIZE) {
2027                 free(b->ptr);
2028                 b->ptr = NULL;
2029                 b->size = 0;
2030         }
2031 -       
2032 +
2033         b->used = 0;
2034  }
2035  
2036  
2037  /**
2038 - * 
2039 - * allocate (if neccessary) enough space for 'size' bytes and 
2040 + *
2041 + * allocate (if necessary) enough space for 'size' bytes and
2042   * set the 'used' counter to 0
2043 - * 
2044 + *
2045   */
2046  
2047  #define BUFFER_PIECE_SIZE 64
2048  
2049  int buffer_prepare_copy(buffer *b, size_t size) {
2050         if (!b) return -1;
2051 -       
2052 -       if ((0 == b->size) || 
2053 +
2054 +       if ((0 == b->size) ||
2055             (size > b->size)) {
2056                 if (b->size) free(b->ptr);
2057 -               
2058 +
2059                 b->size = size;
2060 -               
2061 -               /* always allocate a multiply of BUFFER_PIECE_SIZE */
2062 +
2063 +               /* always allocate a multiple of BUFFER_PIECE_SIZE */
2064                 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2065 -               
2066 +
2067                 b->ptr = malloc(b->size);
2068                 assert(b->ptr);
2069         }
2070 @@ -90,30 +90,30 @@
2071  }
2072  
2073  /**
2074 - * 
2075 - * increase the internal buffer (if neccessary) to append another 'size' byte
2076 + *
2077 + * increase the internal buffer (if necessary) to append another 'size' byte
2078   * ->used isn't changed
2079 - * 
2080 + *
2081   */
2082  
2083  int buffer_prepare_append(buffer *b, size_t size) {
2084         if (!b) return -1;
2085 -       
2086 +
2087         if (0 == b->size) {
2088                 b->size = size;
2089 -               
2090 -               /* always allocate a multiply of BUFFER_PIECE_SIZE */
2091 +
2092 +               /* always allocate a multiple of BUFFER_PIECE_SIZE */
2093                 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2094 -               
2095 +
2096                 b->ptr = malloc(b->size);
2097                 b->used = 0;
2098                 assert(b->ptr);
2099         } else if (b->used + size > b->size) {
2100                 b->size += size;
2101 -               
2102 -               /* always allocate a multiply of BUFFER_PIECE_SIZE */
2103 +
2104 +               /* always allocate a multiple of BUFFER_PIECE_SIZE */
2105                 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2106 -               
2107 +
2108                 b->ptr = realloc(b->ptr, b->size);
2109                 assert(b->ptr);
2110         }
2111 @@ -122,7 +122,7 @@
2112  
2113  int buffer_copy_string(buffer *b, const char *s) {
2114         size_t s_len;
2115 -       
2116 +
2117         if (!s || !b) return -1;
2118  
2119         s_len = strlen(s) + 1;
2120 @@ -136,26 +136,26 @@
2121  
2122  int buffer_copy_string_len(buffer *b, const char *s, size_t s_len) {
2123         if (!s || !b) return -1;
2124 -#if 0  
2125 -       /* removed optimization as we have to keep the empty string 
2126 +#if 0
2127 +       /* removed optimization as we have to keep the empty string
2128          * in some cases for the config handling
2129 -        * 
2130 +        *
2131          * url.access-deny = ( "" )
2132          */
2133         if (s_len == 0) return 0;
2134 -#endif 
2135 +#endif
2136         buffer_prepare_copy(b, s_len + 1);
2137 -       
2138 +
2139         memcpy(b->ptr, s, s_len);
2140         b->ptr[s_len] = '\0';
2141         b->used = s_len + 1;
2142 -       
2143 +
2144         return 0;
2145  }
2146  
2147  int buffer_copy_string_buffer(buffer *b, const buffer *src) {
2148         if (!src) return -1;
2149 -       
2150 +
2151         if (src->used == 0) {
2152                 b->used = 0;
2153                 return 0;
2154 @@ -201,10 +201,10 @@
2155  
2156  /**
2157   * append a string to the end of the buffer
2158 - * 
2159 - * the resulting buffer is terminated with a '\0' 
2160 - * s is treated as a un-terminated string (a \0 is handled a normal character)
2161 - * 
2162 + *
2163 + * the resulting buffer is terminated with a '\0'
2164 + * s is treated as an un-terminated string (a \0 is handled as a normal character)
2165 + *
2166   * @param b a buffer
2167   * @param s the string
2168   * @param s_len size of the string (without the terminating \0)
2169 @@ -228,7 +228,7 @@
2170  int buffer_append_string_buffer(buffer *b, const buffer *src) {
2171         if (!src) return -1;
2172         if (src->used == 0) return 0;
2173 -       
2174 +
2175         return buffer_append_string_len(b, src->ptr, src->used - 1);
2176  }
2177  
2178 @@ -245,9 +245,9 @@
2179  
2180  int buffer_copy_memory(buffer *b, const char *s, size_t s_len) {
2181         if (!s || !b) return -1;
2182 -       
2183 +
2184         b->used = 0;
2185 -       
2186 +
2187         return buffer_append_memory(b, s, s_len);
2188  }
2189  
2190 @@ -402,46 +402,115 @@
2191  
2192  
2193  /**
2194 - * init the buffer 
2195 - * 
2196 + * init the ptr buffer
2197 + *
2198 + */
2199 +buffer_ptr *buffer_ptr_init(buffer_ptr_free_t freer)
2200 +{
2201 +       buffer_ptr *l = calloc(1, sizeof(buffer_ptr));
2202 +       l->free = freer;
2203 +
2204 +       return l;
2205 +}
2206 +
2207 +/**
2208 + * free the buffer_array
2209 + *
2210 + */
2211 +void buffer_ptr_free(buffer_ptr *l)
2212 +{
2213 +       if (NULL != l) {
2214 +               buffer_ptr_clear(l);
2215 +               free(l);
2216 +       }
2217 +}
2218 +
2219 +void buffer_ptr_clear(buffer_ptr *l)
2220 +{
2221 +       assert(NULL != l);
2222 +
2223 +       if (l->free && l->used) {
2224 +               size_t i;
2225 +               for (i = 0; i < l->used; i ++) {
2226 +                       l->free(l->ptr[i]);
2227 +               }
2228 +       }
2229 +
2230 +       if (l->ptr) {
2231 +               free(l->ptr);
2232 +               l->ptr = NULL;
2233 +       }
2234 +       l->used = 0;
2235 +       l->size = 0;
2236 +}
2237 +
2238 +void buffer_ptr_append(buffer_ptr* l, void *item)
2239 +{
2240 +       assert(NULL != l);
2241 +       if (l->ptr == NULL) {
2242 +               l->size = 16;
2243 +               l->ptr = (void **)malloc(sizeof(void *) * l->size);
2244 +       }
2245 +       else if (l->used == l->size) {
2246 +               l->size += 16;
2247 +               l->ptr = realloc(l->ptr, sizeof(void *) * l->size);
2248 +       }
2249 +       l->ptr[l->used++] = item;
2250 +}
2251 +
2252 +void *buffer_ptr_pop(buffer_ptr* l)
2253 +{
2254 +       assert(NULL != l && l->used > 0);
2255 +       return l->ptr[--l->used];
2256 +}
2257 +
2258 +void *buffer_ptr_top(buffer_ptr* l)
2259 +{
2260 +       assert(NULL != l && l->used > 0);
2261 +       return l->ptr[l->used-1];
2262 +}
2263 +
2264 +/**
2265 + * init the buffer
2266 + *
2267   */
2268  
2269  buffer_array* buffer_array_init(void) {
2270         buffer_array *b;
2271 -       
2272 +
2273         b = malloc(sizeof(*b));
2274 -       
2275 +
2276         assert(b);
2277         b->ptr = NULL;
2278         b->size = 0;
2279         b->used = 0;
2280 -       
2281 +
2282         return b;
2283  }
2284  
2285  void buffer_array_reset(buffer_array *b) {
2286         size_t i;
2287 -       
2288 +
2289         if (!b) return;
2290 -       
2291 +
2292         /* if they are too large, reduce them */
2293         for (i = 0; i < b->used; i++) {
2294                 buffer_reset(b->ptr[i]);
2295         }
2296 -       
2297 +
2298         b->used = 0;
2299  }
2300  
2301  
2302  /**
2303 - * free the buffer_array 
2304 - * 
2305 + * free the buffer_array
2306 + *
2307   */
2308  
2309  void buffer_array_free(buffer_array *b) {
2310         size_t i;
2311         if (!b) return;
2312 -       
2313 +
2314         for (i = 0; i < b->size; i++) {
2315                 if (b->ptr[i]) buffer_free(b->ptr[i]);
2316         }
2317 @@ -451,7 +520,7 @@
2318  
2319  buffer *buffer_array_append_get_buffer(buffer_array *b) {
2320         size_t i;
2321 -       
2322 +
2323         if (b->size == 0) {
2324                 b->size = 16;
2325                 b->ptr = malloc(sizeof(*b->ptr) * b->size);
2326 @@ -467,13 +536,13 @@
2327                         b->ptr[i] = NULL;
2328                 }
2329         }
2330 -       
2331 +
2332         if (b->ptr[b->used] == NULL) {
2333                 b->ptr[b->used] = buffer_init();
2334         }
2335 -       
2336 +
2337         b->ptr[b->used]->used = 0;
2338 -       
2339 +
2340         return b->ptr[b->used++];
2341  }
2342  
2343 @@ -482,23 +551,23 @@
2344         size_t i;
2345         if (len == 0) return NULL;
2346         if (needle == NULL) return NULL;
2347 -       
2348 +
2349         if (b->used < len) return NULL;
2350 -       
2351 +
2352         for(i = 0; i < b->used - len; i++) {
2353                 if (0 == memcmp(b->ptr + i, needle, len)) {
2354                         return b->ptr + i;
2355                 }
2356         }
2357 -       
2358 +
2359         return NULL;
2360  }
2361  
2362  buffer *buffer_init_string(const char *str) {
2363         buffer *b = buffer_init();
2364 -       
2365 +
2366         buffer_copy_string(b, str);
2367 -       
2368 +
2369         return b;
2370  }
2371  
2372 @@ -507,8 +576,8 @@
2373  }
2374  
2375  /**
2376 - * check if two buffer contain the same data
2377 - * 
2378 + * check if two buffers contain the same data
2379 + *
2380   * HISTORY: this function was pretty much optimized, but didn't handled
2381   * alignment properly.
2382   */
2383 @@ -517,105 +586,105 @@
2384         if (a->used != b->used) return 0;
2385         if (a->used == 0) return 1;
2386  
2387 -       return (0 == strcmp(a->ptr, b->ptr));
2388 +       return (0 == strncmp(a->ptr, b->ptr, a->used - 1));
2389  }
2390  
2391  int buffer_is_equal_string(buffer *a, const char *s, size_t b_len) {
2392         buffer b;
2393 -       
2394 +
2395         b.ptr = (char *)s;
2396         b.used = b_len + 1;
2397 -       
2398 +
2399         return buffer_is_equal(a, &b);
2400  }
2401  
2402  /* simple-assumption:
2403 - * 
2404 - * most parts are equal and doing a case conversion needs time
2405 - * 
2406 + *
2407 + * most parts are equal and doing a case conversion takes time
2408 + *
2409   */
2410  int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b_len) {
2411         size_t ndx = 0, max_ndx;
2412         size_t *al, *bl;
2413         size_t mask = sizeof(*al) - 1;
2414 -       
2415 +
2416         al = (size_t *)a;
2417         bl = (size_t *)b;
2418 -       
2419 -       /* is the alignment correct ? */
2420 +
2421 +       /* is the alignment correct? */
2422         if ( ((size_t)al & mask) == 0 &&
2423              ((size_t)bl & mask) == 0 ) {
2424 -               
2425 +
2426                 max_ndx = ((a_len < b_len) ? a_len : b_len) & ~mask;
2427 -               
2428 +
2429                 for (; ndx < max_ndx; ndx += sizeof(*al)) {
2430                         if (*al != *bl) break;
2431                         al++; bl++;
2432 -                       
2433 +
2434                 }
2435 -               
2436 +
2437         }
2438 -       
2439 +
2440         a = (char *)al;
2441         b = (char *)bl;
2442 -       
2443 +
2444         max_ndx = ((a_len < b_len) ? a_len : b_len);
2445 -       
2446 +
2447         for (; ndx < max_ndx; ndx++) {
2448                 char a1 = *a++, b1 = *b++;
2449 -               
2450 +
2451                 if (a1 != b1) {
2452                         if ((a1 >= 'A' && a1 <= 'Z') && (b1 >= 'a' && b1 <= 'z'))
2453                                 a1 |= 32;
2454                         else if ((a1 >= 'a' && a1 <= 'z') && (b1 >= 'A' && b1 <= 'Z'))
2455                                 b1 |= 32;
2456                         if ((a1 - b1) != 0) return (a1 - b1);
2457 -                       
2458 +
2459                 }
2460         }
2461 -       
2462 +
2463         return 0;
2464  }
2465  
2466  
2467  /**
2468   * check if the rightmost bytes of the string are equal.
2469 - * 
2470 - * 
2471 + *
2472 + *
2473   */
2474  
2475  int buffer_is_equal_right_len(buffer *b1, buffer *b2, size_t len) {
2476         /* no, len -> equal */
2477         if (len == 0) return 1;
2478 -       
2479 +
2480         /* len > 0, but empty buffers -> not equal */
2481         if (b1->used == 0 || b2->used == 0) return 0;
2482 -       
2483 +
2484         /* buffers too small -> not equal */
2485 -       if (b1->used - 1 < len || b1->used - 1 < len) return 0;
2486 -       
2487 -       if (0 == strncmp(b1->ptr + b1->used - 1 - len, 
2488 +       if (b1->used - 1 < len || b2->used - 1 < len) return 0;
2489 +
2490 +       if (0 == strncmp(b1->ptr + b1->used - 1 - len,
2491                          b2->ptr + b2->used - 1 - len, len)) {
2492                 return 1;
2493         }
2494 -       
2495 +
2496         return 0;
2497  }
2498  
2499  int buffer_copy_string_hex(buffer *b, const char *in, size_t in_len) {
2500         size_t i;
2501 -       
2502 +
2503         /* BO protection */
2504         if (in_len * 2 < in_len) return -1;
2505 -       
2506 +
2507         buffer_prepare_copy(b, in_len * 2 + 1);
2508 -       
2509 +
2510         for (i = 0; i < in_len; i++) {
2511                 b->ptr[b->used++] = hex_chars[(in[i] >> 4) & 0x0F];
2512                 b->ptr[b->used++] = hex_chars[in[i] & 0x0F];
2513         }
2514         b->ptr[b->used++] = '\0';
2515 -       
2516 +
2517         return 0;
2518  }
2519  
2520 @@ -624,7 +693,7 @@
2521         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2522         */
2523         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2524 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2525 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2526         1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1,  /*  20 -  2F space " # $ % & ' + , / */
2527         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,  /*  30 -  3F : ; = ? @ < > */
2528         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
2529 @@ -646,7 +715,7 @@
2530         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2531         */
2532         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2533 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2534 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2535         1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0,  /*  20 -  2F space " # $ % & ' + , / */
2536         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,  /*  30 -  3F : ; = ? @ < > */
2537         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
2538 @@ -668,7 +737,7 @@
2539         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2540         */
2541         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2542 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2543 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2544         0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  20 -  2F & */
2545         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,  /*  30 -  3F < > */
2546         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
2547 @@ -690,7 +759,7 @@
2548         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2549         */
2550         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2551 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2552 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2553         0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  20 -  2F & */
2554         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,  /*  30 -  3F < > */
2555         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
2556 @@ -712,12 +781,12 @@
2557         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2558         */
2559         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2560 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2561 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  20 -  2F */ 
2562 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  30 -  3F */ 
2563 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  40 -  4F */ 
2564 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  50 -  5F */ 
2565 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  60 -  6F */ 
2566 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2567 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  20 -  2F */
2568 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  30 -  3F */
2569 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  40 -  4F */
2570 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  50 -  5F */
2571 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  60 -  6F */
2572         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  70 -  7F */
2573         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */
2574         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  90 -  9F */
2575 @@ -734,13 +803,12 @@
2576         unsigned char *ds, *d;
2577         size_t d_len, ndx;
2578         const char *map = NULL;
2579 -       
2580 +
2581         if (!s || !b) return -1;
2582 -       
2583 -       if (b->ptr[b->used - 1] != '\0') {
2584 -               SEGFAULT();
2585 -       }
2586 -       
2587 +       if (b->used == 0) return -1;
2588 +
2589 +       if (b->ptr[b->used - 1] != '\0') return -1;
2590 +
2591         if (s_len == 0) return 0;
2592  
2593         switch(encoding) {
2594 @@ -760,12 +828,12 @@
2595                 map = encoded_chars_hex;
2596                 break;
2597         case ENCODING_UNSET:
2598 -               break;
2599 +               return buffer_append_string_len(b, s, s_len);
2600         }
2601  
2602         assert(map != NULL);
2603 -       
2604 -       /* count to-be-encoded-characters */
2605 +
2606 +       /* count to-be-encoded characters */
2607         for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
2608                 if (map[*ds]) {
2609                         switch(encoding) {
2610 @@ -787,9 +855,9 @@
2611                         d_len ++;
2612                 }
2613         }
2614 -       
2615 +
2616         buffer_prepare_append(b, d_len);
2617 -       
2618 +
2619         for (ds = (unsigned char *)s, d = (unsigned char *)b->ptr + b->used - 1, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
2620                 if (map[*ds]) {
2621                         switch(encoding) {
2622 @@ -820,16 +888,16 @@
2623                 }
2624         }
2625  
2626 -       /* terminate buffer and calculate new length */ 
2627 +       /* terminate buffer and calculate new length */
2628         b->ptr[b->used + d_len - 1] = '\0';
2629 -       
2630 +
2631         b->used += d_len;
2632  
2633         return 0;
2634  }
2635  
2636  
2637 -/* decodes url-special-chars inplace.
2638 +/* decodes url-special chars in-place.
2639   * replaces non-printable characters with '_'
2640   */
2641  
2642 @@ -854,10 +922,10 @@
2643                                 low = hex2int(*(src + 2));
2644                                 if (low != 0xFF) {
2645                                         high = (high << 4) | low;
2646 -                                       
2647 -                                       /* map control-characters out */        
2648 +
2649 +                                       /* map out control characters */
2650                                         if (high < 32 || high == 127) high = '_';
2651 -                                       
2652 +
2653                                         *dst = high;
2654                                         src += 2;
2655                                 }
2656 @@ -891,7 +959,7 @@
2657   * /abc/./xyz       gets  /abc/xyz
2658   * /abc//xyz        gets  /abc/xyz
2659   *
2660 - * NOTE: src and dest can point to the same buffer, in which case,
2661 + * NOTE: src and dest can point to the same buffer, in which case
2662   *       the operation is performed in-place.
2663   */
2664  
2665 @@ -979,7 +1047,7 @@
2666  
2667  int light_isxdigit(int c) {
2668         if (light_isdigit(c)) return 1;
2669 -       
2670 +
2671         c |= 32;
2672         return (c >= 'a' && c <= 'f');
2673  }
2674 @@ -993,31 +1061,56 @@
2675         return light_isdigit(c) || light_isalpha(c);
2676  }
2677  
2678 +#undef BUFFER_CTYPE_FUNC
2679 +#define BUFFER_CTYPE_FUNC(type) \
2680 +       int buffer_is##type(buffer *b) { \
2681 +               size_t i, len; \
2682 +               if (b->used < 2) return 0; \
2683 +               /* strlen */ \
2684 +               len = b->used - 1; \
2685 +               /* c-string only */ \
2686 +               if (b->ptr[len] != '\0') { \
2687 +                       return 0; \
2688 +               } \
2689 +               /* check on the whole string */ \
2690 +               for (i = 0; i < len; i ++) { \
2691 +                       if (!light_is##type(b->ptr[i])) { \
2692 +                               return 0; \
2693 +                       } \
2694 +               } \
2695 +               return 1; \
2696 +       }
2697 +
2698 +BUFFER_CTYPE_FUNC(digit)
2699 +BUFFER_CTYPE_FUNC(xdigit)
2700 +BUFFER_CTYPE_FUNC(alpha)
2701 +BUFFER_CTYPE_FUNC(alnum)
2702 +
2703  int buffer_to_lower(buffer *b) {
2704         char *c;
2705 -       
2706 +
2707         if (b->used == 0) return 0;
2708 -       
2709 +
2710         for (c = b->ptr; *c; c++) {
2711                 if (*c >= 'A' && *c <= 'Z') {
2712                         *c |= 32;
2713                 }
2714         }
2715 -       
2716 +
2717         return 0;
2718  }
2719  
2720  
2721  int buffer_to_upper(buffer *b) {
2722         char *c;
2723 -       
2724 +
2725         if (b->used == 0) return 0;
2726 -       
2727 +
2728         for (c = b->ptr; *c; c++) {
2729                 if (*c >= 'a' && *c <= 'z') {
2730                         *c &= ~32;
2731                 }
2732         }
2733 -       
2734 +
2735         return 0;
2736  }
2737 --- ../lighttpd-1.4.11/src/buffer.h     2006-01-13 00:00:45.000000000 +0200
2738 +++ lighttpd-1.4.12/src/buffer.h        2006-07-18 13:03:40.000000000 +0300
2739 @@ -12,27 +12,43 @@
2740  
2741  typedef struct {
2742         char *ptr;
2743 -       
2744 +
2745         size_t used;
2746         size_t size;
2747  } buffer;
2748  
2749 +typedef void (*buffer_ptr_free_t)(void *p);
2750 +
2751 +typedef struct {
2752 +       void **ptr;
2753 +       size_t size;
2754 +       size_t used;
2755 +       buffer_ptr_free_t free;
2756 +} buffer_ptr;
2757 +
2758  typedef struct {
2759         buffer **ptr;
2760 -       
2761 +
2762         size_t used;
2763         size_t size;
2764  } buffer_array;
2765  
2766  typedef struct {
2767         char *ptr;
2768 -       
2769 -       size_t offset; /* input-pointer */
2770 -       
2771 -       size_t used;   /* output-pointer */
2772 +
2773 +       size_t offset; /* input pointer */
2774 +
2775 +       size_t used;   /* output pointer */
2776         size_t size;
2777  } read_buffer;
2778  
2779 +buffer_ptr *buffer_ptr_init(buffer_ptr_free_t freer);
2780 +void buffer_ptr_free(buffer_ptr *b);
2781 +void buffer_ptr_clear(buffer_ptr *b);
2782 +void buffer_ptr_append(buffer_ptr *b, void *item);
2783 +void *buffer_ptr_pop(buffer_ptr *b);
2784 +void *buffer_ptr_top(buffer_ptr *b);
2785 +
2786  buffer_array* buffer_array_init(void);
2787  void buffer_array_free(buffer_array *b);
2788  void buffer_array_reset(buffer_array *b);
2789 @@ -43,7 +59,7 @@
2790  buffer* buffer_init_string(const char *str);
2791  void buffer_free(buffer *b);
2792  void buffer_reset(buffer *b);
2793 -       
2794 +
2795  int buffer_prepare_copy(buffer *b, size_t size);
2796  int buffer_prepare_append(buffer *b, size_t size);
2797  
2798 @@ -85,9 +101,9 @@
2799  
2800  typedef enum {
2801         ENCODING_UNSET,
2802 -       ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of a href */
2803 -       ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus coding / too as %2F */
2804 -       ENCODING_HTML,    /* & becomes &amp; and so on */
2805 +       ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of an href */
2806 +       ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus encoding "/" as "%2F" */
2807 +       ENCODING_HTML,    /* "&" becomes "&amp;" and so on */
2808         ENCODING_MINIMAL_XML, /* minimal encoding for xml */
2809         ENCODING_HEX      /* encode string as hex */
2810  } buffer_encoding_t;
2811 @@ -111,20 +127,23 @@
2812  int light_isalpha(int c);
2813  int light_isalnum(int c);
2814  
2815 +#define BUFFER_CTYPE_FUNC(type) int buffer_is##type(buffer *b);
2816 +BUFFER_CTYPE_FUNC(digit)
2817 +BUFFER_CTYPE_FUNC(xdigit)
2818 +BUFFER_CTYPE_FUNC(alpha)
2819 +BUFFER_CTYPE_FUNC(alnum)
2820 +
2821 +#define BUF_STR(x) x->ptr
2822  #define BUFFER_APPEND_STRING_CONST(x, y) \
2823         buffer_append_string_len(x, y, sizeof(y) - 1)
2824  
2825  #define BUFFER_COPY_STRING_CONST(x, y) \
2826         buffer_copy_string_len(x, y, sizeof(y) - 1)
2827  
2828 -#define BUFFER_APPEND_SLASH(x) \
2829 -       if (x->used > 1 && x->ptr[x->used - 2] != '/') { BUFFER_APPEND_STRING_CONST(x, "/"); }
2830 -
2831  #define CONST_STR_LEN(x) x, x ? sizeof(x) - 1 : 0
2832 -#define CONST_BUF_LEN(x) x->ptr, x->used ? x->used - 1 : 0
2833 +#define CONST_BUF_LEN(x) BUF_STR(x), x->used ? x->used - 1 : 0
2834  
2835 -
2836 -#define SEGFAULT() do { fprintf(stderr, "%s.%d: aborted\n", __FILE__, __LINE__); abort(); } while(0)
2837 +       
2838  #define UNUSED(x) ( (void)(x) )
2839  
2840  #endif
2841 --- ../lighttpd-1.4.11/src/chunk.c      2005-11-18 15:18:19.000000000 +0200
2842 +++ lighttpd-1.4.12/src/chunk.c 2006-07-18 13:03:40.000000000 +0300
2843 @@ -1,16 +1,14 @@
2844  /**
2845   * the network chunk-API
2846 - * 
2847 - * 
2848 + *
2849 + *
2850   */
2851  
2852  #include <sys/types.h>
2853  #include <sys/stat.h>
2854 -#include <sys/mman.h>
2855  
2856  #include <stdlib.h>
2857  #include <fcntl.h>
2858 -#include <unistd.h>
2859  
2860  #include <stdio.h>
2861  #include <errno.h>
2862 @@ -18,36 +16,39 @@
2863  
2864  #include "chunk.h"
2865  
2866 +#include "sys-mmap.h"
2867 +#include "sys-files.h"
2868 +
2869  chunkqueue *chunkqueue_init(void) {
2870         chunkqueue *cq;
2871 -       
2872 +
2873         cq = calloc(1, sizeof(*cq));
2874 -       
2875 +
2876         cq->first = NULL;
2877         cq->last = NULL;
2878 -       
2879 +
2880         cq->unused = NULL;
2881 -       
2882 +
2883         return cq;
2884  }
2885  
2886  static chunk *chunk_init(void) {
2887         chunk *c;
2888 -       
2889 +
2890         c = calloc(1, sizeof(*c));
2891 -       
2892 +
2893         c->mem = buffer_init();
2894         c->file.name = buffer_init();
2895         c->file.fd = -1;
2896         c->file.mmap.start = MAP_FAILED;
2897         c->next = NULL;
2898 -       
2899 +
2900         return c;
2901  }
2902  
2903  static void chunk_free(chunk *c) {
2904         if (!c) return;
2905 -       
2906 +
2907         buffer_free(c->mem);
2908         buffer_free(c->file.name);
2909  
2910 @@ -56,13 +57,13 @@
2911  
2912  static void chunk_reset(chunk *c) {
2913         if (!c) return;
2914 -       
2915 +
2916         buffer_reset(c->mem);
2917  
2918         if (c->file.is_temp && !buffer_is_empty(c->file.name)) {
2919                 unlink(c->file.name->ptr);
2920         }
2921 -       
2922 +
2923         buffer_reset(c->file.name);
2924  
2925         if (c->file.fd != -1) {
2926 @@ -78,28 +79,28 @@
2927  
2928  void chunkqueue_free(chunkqueue *cq) {
2929         chunk *c, *pc;
2930 -       
2931 +
2932         if (!cq) return;
2933 -       
2934 +
2935         for (c = cq->first; c; ) {
2936                 pc = c;
2937                 c = c->next;
2938                 chunk_free(pc);
2939         }
2940 -       
2941 +
2942         for (c = cq->unused; c; ) {
2943                 pc = c;
2944                 c = c->next;
2945                 chunk_free(pc);
2946         }
2947 -       
2948 +
2949         free(cq);
2950  }
2951  
2952  static chunk *chunkqueue_get_unused_chunk(chunkqueue *cq) {
2953         chunk *c;
2954 -       
2955 -       /* check if we have a unused chunk */
2956 +
2957 +       /* check if we have an unused chunk */
2958         if (!cq->unused) {
2959                 c = chunk_init();
2960         } else {
2961 @@ -109,18 +110,18 @@
2962                 c->next = NULL;
2963                 cq->unused_chunks--;
2964         }
2965 -       
2966 +
2967         return c;
2968  }
2969  
2970  static int chunkqueue_prepend_chunk(chunkqueue *cq, chunk *c) {
2971         c->next = cq->first;
2972         cq->first = c;
2973 -       
2974 +
2975         if (cq->last == NULL) {
2976                 cq->last = c;
2977         }
2978 -       
2979 +
2980         return 0;
2981  }
2982  
2983 @@ -129,19 +130,19 @@
2984                 cq->last->next = c;
2985         }
2986         cq->last = c;
2987 -       
2988 +
2989         if (cq->first == NULL) {
2990                 cq->first = c;
2991         }
2992 -       
2993 +
2994         return 0;
2995  }
2996  
2997  void chunkqueue_reset(chunkqueue *cq) {
2998         chunk *c;
2999         /* move everything to the unused queue */
3000 -       
3001 -       /* mark all read written */ 
3002 +
3003 +       /* mark all read written */
3004         for (c = cq->first; c; c = c->next) {
3005                 switch(c->type) {
3006                 case MEM_CHUNK:
3007 @@ -150,7 +151,7 @@
3008                 case FILE_CHUNK:
3009                         c->offset = c->file.length;
3010                         break;
3011 -               default: 
3012 +               default:
3013                         break;
3014                 }
3015         }
3016 @@ -162,93 +163,93 @@
3017  
3018  int chunkqueue_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len) {
3019         chunk *c;
3020 -       
3021 +
3022         if (len == 0) return 0;
3023 -       
3024 +
3025         c = chunkqueue_get_unused_chunk(cq);
3026 -       
3027 +
3028         c->type = FILE_CHUNK;
3029 -       
3030 +
3031         buffer_copy_string_buffer(c->file.name, fn);
3032         c->file.start = offset;
3033         c->file.length = len;
3034         c->offset = 0;
3035 -       
3036 +
3037         chunkqueue_append_chunk(cq, c);
3038 -       
3039 +
3040         return 0;
3041  }
3042  
3043  int chunkqueue_append_buffer(chunkqueue *cq, buffer *mem) {
3044         chunk *c;
3045 -       
3046 +
3047         if (mem->used == 0) return 0;
3048 -       
3049 +
3050         c = chunkqueue_get_unused_chunk(cq);
3051         c->type = MEM_CHUNK;
3052         c->offset = 0;
3053         buffer_copy_string_buffer(c->mem, mem);
3054 -       
3055 +
3056         chunkqueue_append_chunk(cq, c);
3057 -       
3058 +
3059         return 0;
3060  }
3061  
3062  int chunkqueue_prepend_buffer(chunkqueue *cq, buffer *mem) {
3063         chunk *c;
3064 -       
3065 +
3066         if (mem->used == 0) return 0;
3067 -       
3068 +
3069         c = chunkqueue_get_unused_chunk(cq);
3070         c->type = MEM_CHUNK;
3071         c->offset = 0;
3072         buffer_copy_string_buffer(c->mem, mem);
3073 -       
3074 +
3075         chunkqueue_prepend_chunk(cq, c);
3076 -       
3077 +
3078         return 0;
3079  }
3080  
3081  int chunkqueue_append_mem(chunkqueue *cq, const char * mem, size_t len) {
3082         chunk *c;
3083 -       
3084 +
3085         if (len == 0) return 0;
3086 -       
3087 +
3088         c = chunkqueue_get_unused_chunk(cq);
3089         c->type = MEM_CHUNK;
3090         c->offset = 0;
3091         buffer_copy_string_len(c->mem, mem, len - 1);
3092 -       
3093 +
3094         chunkqueue_append_chunk(cq, c);
3095 -       
3096 +
3097         return 0;
3098  }
3099  
3100  buffer * chunkqueue_get_prepend_buffer(chunkqueue *cq) {
3101         chunk *c;
3102 -       
3103 +
3104         c = chunkqueue_get_unused_chunk(cq);
3105 -       
3106 +
3107         c->type = MEM_CHUNK;
3108         c->offset = 0;
3109         buffer_reset(c->mem);
3110 -       
3111 +
3112         chunkqueue_prepend_chunk(cq, c);
3113 -       
3114 +
3115         return c->mem;
3116  }
3117  
3118  buffer *chunkqueue_get_append_buffer(chunkqueue *cq) {
3119         chunk *c;
3120 -       
3121 +
3122         c = chunkqueue_get_unused_chunk(cq);
3123 -       
3124 +
3125         c->type = MEM_CHUNK;
3126         c->offset = 0;
3127         buffer_reset(c->mem);
3128 -       
3129 +
3130         chunkqueue_append_chunk(cq, c);
3131 -       
3132 +
3133         return c->mem;
3134  }
3135  
3136 @@ -263,7 +264,7 @@
3137  chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) {
3138         chunk *c;
3139         buffer *template = buffer_init_string("/var/tmp/lighttpd-upload-XXXXXX");
3140 -       
3141 +
3142         c = chunkqueue_get_unused_chunk(cq);
3143  
3144         c->type = FILE_CHUNK;
3145 @@ -273,12 +274,12 @@
3146                 size_t i;
3147  
3148                 /* we have several tempdirs, only if all of them fail we jump out */
3149 -               
3150 +
3151                 for (i = 0; i < cq->tempdirs->used; i++) {
3152                         data_string *ds = (data_string *)cq->tempdirs->data[i];
3153  
3154                         buffer_copy_string_buffer(template, ds->value);
3155 -                       BUFFER_APPEND_SLASH(template);
3156 +                       PATHNAME_APPEND_SLASH(template);
3157                         BUFFER_APPEND_STRING_CONST(template, "lighttpd-upload-XXXXXX");
3158  
3159                         if (-1 != (c->file.fd = mkstemp(template->ptr))) {
3160 @@ -300,7 +301,7 @@
3161         chunkqueue_append_chunk(cq, c);
3162  
3163         buffer_free(template);
3164 -       
3165 +
3166         return c;
3167  }
3168  
3169 @@ -308,7 +309,7 @@
3170  off_t chunkqueue_length(chunkqueue *cq) {
3171         off_t len = 0;
3172         chunk *c;
3173 -       
3174 +
3175         for (c = cq->first; c; c = c->next) {
3176                 switch (c->type) {
3177                 case MEM_CHUNK:
3178 @@ -321,14 +322,14 @@
3179                         break;
3180                 }
3181         }
3182 -       
3183 +
3184         return len;
3185  }
3186  
3187  off_t chunkqueue_written(chunkqueue *cq) {
3188         off_t len = 0;
3189         chunk *c;
3190 -       
3191 +
3192         for (c = cq->first; c; c = c->next) {
3193                 switch (c->type) {
3194                 case MEM_CHUNK:
3195 @@ -339,7 +340,7 @@
3196                         break;
3197                 }
3198         }
3199 -       
3200 +
3201         return len;
3202  }
3203  
3204 @@ -355,12 +356,13 @@
3205  
3206                 switch (c->type) {
3207                 case MEM_CHUNK:
3208 +                       if (c->mem->used == 0) is_finished = 1;
3209                         if (c->offset == (off_t)c->mem->used - 1) is_finished = 1;
3210                         break;
3211                 case FILE_CHUNK:
3212 -                       if (c->offset == c->file.length) is_finished = 1; 
3213 +                       if (c->offset == c->file.length) is_finished = 1;
3214                         break;
3215 -               default: 
3216 +               default:
3217                         break;
3218                 }
3219  
3220 @@ -383,3 +385,50 @@
3221  
3222         return 0;
3223  }
3224 +
3225 +void chunkqueue_print(chunkqueue *cq) {
3226 +       chunk *c;
3227 +
3228 +       for (c = cq->first; c; c = c->next) {
3229 +               fprintf(stderr, "(mem) %s", c->mem->ptr + c->offset);
3230 +       }
3231 +       fprintf(stderr, "\r\n");
3232 +}
3233 +
3234 +
3235 +/**
3236 + * remove the last chunk if it is empty
3237 + */
3238 +
3239 +void chunkqueue_remove_empty_last_chunk(chunkqueue *cq) {
3240 +       chunk *c;
3241 +       if (!cq->last) return;
3242 +       if (!cq->first) return;
3243 +
3244 +       if (cq->first == cq->last) {
3245 +               c = cq->first;
3246 +
3247 +               if (c->type != MEM_CHUNK) return;
3248 +               if (c->mem->used == 0) {
3249 +                       chunk_free(c);
3250 +                       cq->first = cq->last = NULL;
3251 +               }
3252 +               return;
3253 +       }
3254 +
3255 +       for (c = cq->first; c->next; c = c->next) {
3256 +               if (c->type != MEM_CHUNK) continue;
3257 +               if (c->mem->used != 0) continue;
3258 +
3259 +               if (c->next == cq->last) {
3260 +                       cq->last = c;
3261 +
3262 +                       chunk_free(c->next);
3263 +                       c->next = NULL;
3264 +
3265 +                       return;
3266 +               }
3267 +       }
3268 +}
3269 +
3270 +
3271 --- ../lighttpd-1.4.11/src/chunk.h      2005-11-01 09:32:21.000000000 +0200
3272 +++ lighttpd-1.4.12/src/chunk.h 2006-07-18 13:03:40.000000000 +0300
3273 @@ -6,7 +6,7 @@
3274  
3275  typedef struct chunk {
3276         enum { UNUSED_CHUNK, MEM_CHUNK, FILE_CHUNK } type;
3277 -       
3278 +
3279         buffer *mem; /* either the storage of the mem-chunk or the read-ahead buffer */
3280  
3281         struct {
3282 @@ -16,28 +16,28 @@
3283                 off_t  length; /* octets to send from the starting offset */
3284  
3285                 int    fd;
3286 -               struct { 
3287 +               struct {
3288                         char   *start; /* the start pointer of the mmap'ed area */
3289                         size_t length; /* size of the mmap'ed area */
3290 -                       off_t  offset; /* start is <n> octet away from the start of the file */
3291 +                       off_t  offset; /* start is <n> octets away from the start of the file */
3292                 } mmap;
3293  
3294 -               int is_temp; /* file is temporary and will be deleted if on cleanup */
3295 +               int is_temp; /* file is temporary and will be deleted on cleanup */
3296         } file;
3297 -       
3298 -       off_t  offset; /* octets sent from this chunk 
3299 -                         the size of the chunk is either 
3300 +
3301 +       off_t  offset; /* octets sent from this chunk
3302 +                         the size of the chunk is either
3303                           - mem-chunk: mem->used - 1
3304                           - file-chunk: file.length
3305                         */
3306 -       
3307 +
3308         struct chunk *next;
3309  } chunk;
3310  
3311  typedef struct {
3312         chunk *first;
3313         chunk *last;
3314 -       
3315 +
3316         chunk *unused;
3317         size_t unused_chunks;
3318  
3319 @@ -56,6 +56,7 @@
3320  buffer * chunkqueue_get_append_buffer(chunkqueue *c);
3321  buffer * chunkqueue_get_prepend_buffer(chunkqueue *c);
3322  chunk * chunkqueue_get_append_tempfile(chunkqueue *cq);
3323 +void chunkqueue_remove_empty_last_chunk(chunkqueue *cq);
3324  
3325  int chunkqueue_remove_finished_chunks(chunkqueue *cq);
3326  
3327 @@ -66,4 +67,6 @@
3328  
3329  int chunkqueue_is_empty(chunkqueue *c);
3330  
3331 +void chunkqueue_print(chunkqueue *cq);
3332 +
3333  #endif
3334 --- ../lighttpd-1.4.11/src/configfile-glue.c    2006-03-03 20:14:56.000000000 +0200
3335 +++ lighttpd-1.4.12/src/configfile-glue.c       2006-07-16 00:26:03.000000000 +0300
3336 @@ -1,4 +1,5 @@
3337  #include <string.h>
3338 +#include <ctype.h>
3339  
3340  #include "base.h"
3341  #include "buffer.h"
3342 @@ -11,10 +12,10 @@
3343   * are the external interface of lighttpd. The functions
3344   * are used by the server itself and the plugins.
3345   *
3346 - * The main-goal is to have a small library in the end 
3347 - * which is linked against both and which will define 
3348 + * The main-goal is to have a small library in the end
3349 + * which is linked against both and which will define
3350   * the interface itself in the end.
3351 - * 
3352 + *
3353   */
3354  
3355  
3356 @@ -24,56 +25,60 @@
3357  int config_insert_values_internal(server *srv, array *ca, const config_values_t cv[]) {
3358         size_t i;
3359         data_unset *du;
3360 -       
3361 +
3362         for (i = 0; cv[i].key; i++) {
3363 -               
3364 +
3365                 if (NULL == (du = array_get_element(ca, cv[i].key))) {
3366                         /* no found */
3367 -                       
3368 +
3369                         continue;
3370                 }
3371 -               
3372 +
3373                 switch (cv[i].type) {
3374                 case T_CONFIG_ARRAY:
3375                         if (du->type == TYPE_ARRAY) {
3376                                 size_t j;
3377                                 data_array *da = (data_array *)du;
3378 -                               
3379 +
3380                                 for (j = 0; j < da->value->used; j++) {
3381                                         if (da->value->data[j]->type == TYPE_STRING) {
3382                                                 data_string *ds = data_string_init();
3383 -                                               
3384 +
3385                                                 buffer_copy_string_buffer(ds->value, ((data_string *)(da->value->data[j]))->value);
3386                                                 if (!da->is_index_key) {
3387                                                         /* the id's were generated automaticly, as we copy now we might have to renumber them
3388 -                                                        * this is used to prepend server.modules by mod_indexfiles as it has to be loaded 
3389 +                                                        * this is used to prepend server.modules by mod_indexfiles as it has to be loaded
3390                                                          * before mod_fastcgi and friends */
3391                                                         buffer_copy_string_buffer(ds->key, ((data_string *)(da->value->data[j]))->key);
3392                                                 }
3393 -                                               
3394 +
3395                                                 array_insert_unique(cv[i].destination, (data_unset *)ds);
3396                                         } else {
3397 -                                               log_error_write(srv, __FILE__, __LINE__, "sssd", 
3398 -                                                               "the key of and array can only be a string or a integer, variable:", 
3399 -                                                               cv[i].key, "type:", da->value->data[j]->type); 
3400 -                                               
3401 +                                               log_error_write(srv, __FILE__, __LINE__, "sssd",
3402 +                                                               "the key of and array can only be a string or a integer, variable:",
3403 +                                                               cv[i].key, "type:", da->value->data[j]->type);
3404 +
3405                                                 return -1;
3406                                         }
3407                                 }
3408                         } else {
3409                                 log_error_write(srv, __FILE__, __LINE__, "sss", "unexpected type for key: ", cv[i].key, "array of strings");
3410 -                               
3411 +
3412                                 return -1;
3413                         }
3414                         break;
3415                 case T_CONFIG_STRING:
3416                         if (du->type == TYPE_STRING) {
3417                                 data_string *ds = (data_string *)du;
3418 -                               
3419 +
3420                                 buffer_copy_string_buffer(cv[i].destination, ds->value);
3421 +                       } else if (du->type == TYPE_INTEGER) {
3422 +                               data_integer *di = (data_integer *)du;
3423 +
3424 +                               buffer_copy_long(cv[i].destination, di->value);
3425                         } else {
3426                                 log_error_write(srv, __FILE__, __LINE__, "ssss", "unexpected type for key: ", cv[i].key, "(string)", "\"...\"");
3427 -                               
3428 +
3429                                 return -1;
3430                         }
3431                         break;
3432 @@ -81,15 +86,20 @@
3433                         switch(du->type) {
3434                         case TYPE_INTEGER: {
3435                                 data_integer *di = (data_integer *)du;
3436 -                               
3437 +
3438                                 *((unsigned short *)(cv[i].destination)) = di->value;
3439                                 break;
3440                         }
3441                         case TYPE_STRING: {
3442                                 data_string *ds = (data_string *)du;
3443 -                                       
3444 +
3445 +                               if (buffer_isdigit(ds->value)) {
3446 +                                       *((unsigned short *)(cv[i].destination)) = strtol(ds->value->ptr, NULL, 10);
3447 +                                       break;
3448 +                               }
3449 +
3450                                 log_error_write(srv, __FILE__, __LINE__, "ssb", "get a string but expected a short:", cv[i].key, ds->value);
3451 -                               
3452 +
3453                                 return -1;
3454                         }
3455                         default:
3456 @@ -100,19 +110,19 @@
3457                 case T_CONFIG_BOOLEAN:
3458                         if (du->type == TYPE_STRING) {
3459                                 data_string *ds = (data_string *)du;
3460 -                               
3461 +
3462                                 if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable"))) {
3463                                         *((unsigned short *)(cv[i].destination)) = 1;
3464                                 } else if (buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))) {
3465                                         *((unsigned short *)(cv[i].destination)) = 0;
3466                                 } else {
3467                                         log_error_write(srv, __FILE__, __LINE__, "ssbs", "ERROR: unexpected value for key:", cv[i].key, ds->value, "(enable|disable)");
3468 -                                               
3469 +
3470                                         return -1;
3471                                 }
3472                         } else {
3473                                 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: unexpected type for key:", cv[i].key, "(string)", "\"(enable|disable)\"");
3474 -                               
3475 +
3476                                 return -1;
3477                         }
3478                         break;
3479 @@ -121,9 +131,9 @@
3480                         break;
3481                 case T_CONFIG_DEPRECATED:
3482                         log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found deprecated key:", cv[i].key, "-", (char *)(cv[i].destination));
3483 -                       
3484 +
3485                         srv->config_deprecated = 1;
3486 -                       
3487 +
3488                         break;
3489                 }
3490         }
3491 @@ -133,25 +143,25 @@
3492  int config_insert_values_global(server *srv, array *ca, const config_values_t cv[]) {
3493         size_t i;
3494         data_unset *du;
3495 -       
3496 +
3497         for (i = 0; cv[i].key; i++) {
3498                 data_string *touched;
3499 -               
3500 +
3501                 if (NULL == (du = array_get_element(ca, cv[i].key))) {
3502                         /* no found */
3503 -                       
3504 +
3505                         continue;
3506                 }
3507 -               
3508 +
3509                 /* touched */
3510                 touched = data_string_init();
3511 -               
3512 +
3513                 buffer_copy_string(touched->value, "");
3514                 buffer_copy_string_buffer(touched->key, du->key);
3515 -               
3516 +
3517                 array_insert_unique(srv->config_touched, (data_unset *)touched);
3518         }
3519 -       
3520 +
3521         return config_insert_values_internal(srv, ca, cv);
3522  }
3523  
3524 @@ -191,25 +201,25 @@
3525         }
3526  
3527         /* pass the rules */
3528 -       
3529 +
3530         switch (dc->comp) {
3531         case COMP_HTTP_HOST: {
3532                 char *ck_colon = NULL, *val_colon = NULL;
3533 -               
3534 +
3535                 if (!buffer_is_empty(con->uri.authority)) {
3536 -               
3537 -                       /* 
3538 +
3539 +                       /*
3540                          * append server-port to the HTTP_POST if necessary
3541                          */
3542 -                       
3543 +
3544                         l = con->uri.authority;
3545 -                       
3546 +
3547                         switch(dc->cond) {
3548                         case CONFIG_COND_NE:
3549                         case CONFIG_COND_EQ:
3550                                 ck_colon = strchr(dc->string->ptr, ':');
3551                                 val_colon = strchr(l->ptr, ':');
3552 -                               
3553 +
3554                                 if (ck_colon == val_colon) {
3555                                         /* nothing to do with it */
3556                                         break;
3557 @@ -230,21 +240,21 @@
3558                                 break;
3559                         }
3560                 } else {
3561 -                       l = NULL;
3562 +                       l = srv->empty_string;
3563                 }
3564                 break;
3565         }
3566         case COMP_HTTP_REMOTEIP: {
3567                 char *nm_slash;
3568 -               /* handle remoteip limitations 
3569 -                * 
3570 +               /* handle remoteip limitations
3571 +                *
3572                  * "10.0.0.1" is provided for all comparisions
3573 -                * 
3574 +                *
3575                  * only for == and != we support
3576 -                * 
3577 +                *
3578                  * "10.0.0.1/24"
3579                  */
3580 -               
3581 +
3582                 if ((dc->cond == CONFIG_COND_EQ ||
3583                      dc->cond == CONFIG_COND_NE) &&
3584                     (con->dst_addr.plain.sa_family == AF_INET) &&
3585 @@ -253,41 +263,48 @@
3586                         long nm;
3587                         char *err;
3588                         struct in_addr val_inp;
3589 -                       
3590 +
3591 +                       if (con->conf.log_condition_handling) {
3592 +                               l = srv->empty_string;
3593 +
3594 +                               log_error_write(srv, __FILE__, __LINE__,  "bsbsb", dc->comp_key,
3595 +                                               "(", l, ") compare to", dc->string);
3596 +                       }
3597 +
3598                         if (*(nm_slash+1) == '\0') {
3599                                 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: no number after / ", dc->string);
3600 -                                       
3601 +
3602                                 return COND_RESULT_FALSE;
3603                         }
3604 -                       
3605 +
3606                         nm_bits = strtol(nm_slash + 1, &err, 10);
3607 -                       
3608 +
3609                         if (*err) {
3610                                 log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", dc->string, *err);
3611 -                               
3612 +
3613                                 return COND_RESULT_FALSE;
3614                         }
3615 -                       
3616 +
3617                         /* take IP convert to the native */
3618                         buffer_copy_string_len(srv->cond_check_buf, dc->string->ptr, nm_slash - dc->string->ptr);
3619 -#ifdef __WIN32                 
3620 +#ifdef _WIN32
3621                         if (INADDR_NONE == (val_inp.s_addr = inet_addr(srv->cond_check_buf->ptr))) {
3622                                 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
3623 -                               
3624 +
3625                                 return COND_RESULT_FALSE;
3626                         }
3627  
3628  #else
3629                         if (0 == inet_aton(srv->cond_check_buf->ptr, &val_inp)) {
3630                                 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
3631 -                               
3632 +
3633                                 return COND_RESULT_FALSE;
3634                         }
3635  #endif
3636 -                       
3637 +
3638                         /* build netmask */
3639                         nm = htonl(~((1 << (32 - nm_bits)) - 1));
3640 -                       
3641 +
3642                         if ((val_inp.s_addr & nm) == (con->dst_addr.ipv4.sin_addr.s_addr & nm)) {
3643                                 return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
3644                         } else {
3645 @@ -308,7 +325,7 @@
3646  
3647         case COMP_HTTP_REFERER: {
3648                 data_string *ds;
3649 -               
3650 +
3651                 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Referer"))) {
3652                         l = ds->value;
3653                 } else {
3654 @@ -338,7 +355,7 @@
3655         default:
3656                 return COND_RESULT_FALSE;
3657         }
3658 -       
3659 +
3660         if (NULL == l) {
3661                 if (con->conf.log_condition_handling) {
3662                         log_error_write(srv, __FILE__, __LINE__,  "bsbs", dc->comp_key,
3663 @@ -346,10 +363,10 @@
3664                 }
3665                 return COND_RESULT_FALSE;
3666         }
3667 -       
3668 +
3669         if (con->conf.log_condition_handling) {
3670                 log_error_write(srv, __FILE__, __LINE__,  "bsbsb", dc->comp_key,
3671 -                               "(", l, ") compare to ", dc->string);
3672 +                               "(", l, ") compare to", dc->string);
3673         }
3674         switch(dc->cond) {
3675         case CONFIG_COND_NE:
3676 @@ -365,13 +382,13 @@
3677         case CONFIG_COND_MATCH: {
3678                 cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
3679                 int n;
3680 -               
3681 +
3682  #ifndef elementsof
3683  #define elementsof(x) (sizeof(x) / sizeof(x[0]))
3684  #endif
3685                 n = pcre_exec(dc->regex, dc->regex_study, l->ptr, l->used - 1, 0, 0,
3686                                 cache->matches, elementsof(cache->matches));
3687 -               
3688 +
3689                 cache->patterncount = n;
3690                 if (n > 0) {
3691                         cache->comp_value = l;
3692 @@ -387,7 +404,7 @@
3693                 /* no way */
3694                 break;
3695         }
3696 -       
3697 +
3698         return COND_RESULT_FALSE;
3699  }
3700  
3701 @@ -395,6 +412,9 @@
3702         cond_cache_t *caches = con->cond_cache;
3703  
3704         if (COND_RESULT_UNSET == caches[dc->context_ndx].result) {
3705 +               if (con->conf.log_condition_handling) {
3706 +                       log_error_write(srv, __FILE__, __LINE__,  "sds",  "=== start of", dc->context_ndx, "condition block ===");
3707 +               }
3708                 if (COND_RESULT_TRUE == (caches[dc->context_ndx].result = config_check_cond_nocache(srv, con, dc))) {
3709                         if (dc->next) {
3710                                 data_config *c;
3711 @@ -409,11 +429,11 @@
3712                 }
3713                 if (con->conf.log_condition_handling) {
3714                         log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
3715 -                                       "(uncached) result:",
3716 +                                       "result:",
3717                                         caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
3718                 }
3719         } else {
3720 -               if (con->conf.log_condition_handling) {
3721 +               if (con->conf.log_condition_cache_handling) {
3722                         log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
3723                                         "(cached) result:",
3724                                         caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
3725 @@ -423,9 +443,6 @@
3726  }
3727  
3728  int config_check_cond(server *srv, connection *con, data_config *dc) {
3729 -       if (con->conf.log_condition_handling) {
3730 -               log_error_write(srv, __FILE__, __LINE__,  "s",  "=== start of condition block ===");
3731 -       }
3732         return (config_check_cond_cached(srv, con, dc) == COND_RESULT_TRUE);
3733  }
3734  
3735 @@ -443,3 +460,85 @@
3736         return 1;
3737  }
3738  
3739 +/* return <0 on error
3740 + * return 0-x if matched (and replaced)
3741 + */
3742 +int config_exec_pcre_keyvalue_buffer(connection *con, pcre_keyvalue_buffer *kvb, data_config *context, buffer *match_buf, buffer *result)
3743 +{
3744 +#ifdef HAVE_PCRE_H
3745 +       pcre *match;
3746 +       pcre_extra *extra;
3747 +       const char *pattern;
3748 +       size_t pattern_len;
3749 +       int n;
3750 +       size_t i;
3751 +       pcre_keyvalue *kv;
3752 +# define N 10
3753 +       int ovec[N * 3];
3754 +
3755 +       for (i = 0; i < kvb->used; i++) {
3756 +               kv = kvb->kv[i];
3757 +
3758 +               match       = kv->key;
3759 +               extra       = kv->key_extra;
3760 +               pattern     = kv->value->ptr;
3761 +               pattern_len = kv->value->used - 1;
3762 +
3763 +               if ((n = pcre_exec(match, extra, match_buf->ptr, match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
3764 +                       if (n != PCRE_ERROR_NOMATCH) {
3765 +                               return n;
3766 +                       }
3767 +               } else {
3768 +                       const char **list;
3769 +                       size_t start, end;
3770 +                       size_t k;
3771 +
3772 +                       /* it matched */
3773 +                       pcre_get_substring_list(match_buf->ptr, ovec, n, &list);
3774 +
3775 +                       /* search for $[0-9] */
3776 +
3777 +                       buffer_reset(result);
3778 +
3779 +                       start = 0; end = pattern_len;
3780 +                       for (k = 0; k < pattern_len; k++) {
3781 +                               if ((pattern[k] == '$' || pattern[k] == '%') &&
3782 +                                   isdigit((unsigned char)pattern[k + 1])) {
3783 +                                       /* got one */
3784 +
3785 +                                       size_t num = pattern[k + 1] - '0';
3786 +
3787 +                                       end = k;
3788 +
3789 +                                       buffer_append_string_len(result, pattern + start, end - start);
3790 +
3791 +                                       if (pattern[k] == '$') {
3792 +                                               /* n is always > 0 */
3793 +                                               if (num < (size_t)n) {
3794 +                                                       buffer_append_string(result, list[num]);
3795 +                                               }
3796 +                                       } else {
3797 +                                               config_append_cond_match_buffer(con, context, result, num);
3798 +                                       }
3799 +
3800 +                                       k++;
3801 +                                       start = k + 1;
3802 +                               }
3803 +                       }
3804 +
3805 +                       buffer_append_string_len(result, pattern + start, pattern_len - start);
3806 +
3807 +                       pcre_free(list);
3808 +
3809 +                       return i;
3810 +               }
3811 +       }
3812 +
3813 +       return PCRE_ERROR_NOMATCH;
3814 +#undef N
3815 +#else
3816 +       UNUSED(kvb);
3817 +       return -2;
3818 +#endif
3819 +}
3820 +
3821 --- ../lighttpd-1.4.11/src/configfile.c 2006-02-15 14:26:42.000000000 +0200
3822 +++ lighttpd-1.4.12/src/configfile.c    2006-07-18 13:03:40.000000000 +0300
3823 @@ -2,7 +2,6 @@
3824  
3825  #include <stdlib.h>
3826  #include <fcntl.h>
3827 -#include <unistd.h>
3828  #include <errno.h>
3829  #include <string.h>
3830  #include <stdio.h>
3831 @@ -13,21 +12,24 @@
3832  #include "log.h"
3833  #include "stream.h"
3834  #include "plugin.h"
3835 -#ifdef USE_LICENSE
3836 -#include "license.h"
3837 -#endif
3838 -
3839  #include "configparser.h"
3840  #include "configfile.h"
3841  #include "proc_open.h"
3842  
3843 +#include "sys-files.h"
3844 +#include "sys-process.h"
3845 +
3846 +#ifndef PATH_MAX
3847 +/* win32 */
3848 +#define PATH_MAX 64
3849 +#endif
3850  
3851  static int config_insert(server *srv) {
3852         size_t i;
3853         int ret = 0;
3854         buffer *stat_cache_string;
3855 -       
3856 -       config_values_t cv[] = { 
3857 +
3858 +       config_values_t cv[] = {
3859                 { "server.bind",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 0 */
3860                 { "server.errorlog",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 1 */
3861                 { "server.errorfile-prefix",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 2 */
3862 @@ -38,7 +40,7 @@
3863                 { "server.tag",                  NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 7 */
3864                 { "server.use-ipv6",             NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
3865                 { "server.modules",              NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_SERVER },       /* 9 */
3866 -               
3867 +
3868                 { "server.event-handler",        NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 10 */
3869                 { "server.pid-file",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 11 */
3870                 { "server.max-request-size",     NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 12 */
3871 @@ -49,7 +51,7 @@
3872                 { "server.max-keep-alive-requests", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 17 */
3873                 { "server.name",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 18 */
3874                 { "server.max-keep-alive-idle",  NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 19 */
3875 -               
3876 +
3877                 { "server.max-read-idle",        NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 20 */
3878                 { "server.max-write-idle",       NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 21 */
3879                 { "server.error-handler-404",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 22 */
3880 @@ -60,19 +62,19 @@
3881                 { "mimetype.use-xattr",          NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 27 */
3882                 { "mimetype.assign",             NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },   /* 28 */
3883                 { "ssl.pemfile",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 29 */
3884 -               
3885 +
3886                 { "ssl.engine",                  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 30 */
3887 -               
3888 +
3889                 { "debug.log-file-not-found",    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 31 */
3890                 { "debug.log-request-handling",  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 32 */
3891                 { "debug.log-response-header",   NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 33 */
3892                 { "debug.log-request-header",    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 34 */
3893 -               
3894 +
3895                 { "server.protocol-http11",      NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 35 */
3896                 { "debug.log-request-header-on-error", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 36 */
3897                 { "debug.log-state-handling",    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 37 */
3898                 { "ssl.ca-file",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 38 */
3899 -               
3900 +
3901                 { "server.errorlog-use-syslog",  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 39 */
3902                 { "server.range-requests",       NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 40 */
3903                 { "server.stat-cache-engine",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 41 */
3904 @@ -80,7 +82,8 @@
3905                 { "server.network-backend",      NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 43 */
3906                 { "server.upload-dirs",          NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },   /* 44 */
3907                 { "server.core-files",           NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 45 */
3908 -               
3909 +               { "debug.log-condition-cache-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },    /* 46 */
3910 +
3911                 { "server.host",                 "use server.bind instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3912                 { "server.docroot",              "use server.document-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3913                 { "server.virtual-root",         "load mod_simple_vhost and use simple-vhost.server-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3914 @@ -90,11 +93,11 @@
3915                 { "server.groupid",              "use server.groupname instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3916                 { "server.use-keep-alive",       "use server.max-keep-alive-requests = 0 instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3917                 { "server.force-lower-case-files",       "use server.force-lowercase-filenames instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3918 -               
3919 +
3920                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
3921         };
3922  
3923 -       
3924 +
3925         /* 0 */
3926         cv[0].destination = srv->srvconf.bindhost;
3927         cv[1].destination = srv->srvconf.errorlog_file;
3928 @@ -102,33 +105,33 @@
3929         cv[4].destination = srv->srvconf.username;
3930         cv[5].destination = srv->srvconf.groupname;
3931         cv[6].destination = &(srv->srvconf.port);
3932 -       
3933 +
3934         cv[9].destination = srv->srvconf.modules;
3935         cv[10].destination = srv->srvconf.event_handler;
3936         cv[11].destination = srv->srvconf.pid_file;
3937 -       
3938 +
3939         cv[13].destination = &(srv->srvconf.max_worker);
3940         cv[23].destination = &(srv->srvconf.max_fds);
3941         cv[36].destination = &(srv->srvconf.log_request_header_on_error);
3942         cv[37].destination = &(srv->srvconf.log_state_handling);
3943 -       
3944 +
3945         cv[39].destination = &(srv->srvconf.errorlog_use_syslog);
3946 -       
3947 +
3948         stat_cache_string = buffer_init();
3949         cv[41].destination = stat_cache_string;
3950         cv[43].destination = srv->srvconf.network_backend;
3951         cv[44].destination = srv->srvconf.upload_tempdirs;
3952         cv[45].destination = &(srv->srvconf.enable_cores);
3953 -       
3954 +
3955         cv[42].destination = &(srv->srvconf.max_conns);
3956         cv[12].destination = &(srv->srvconf.max_request_size);
3957         srv->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
3958  
3959         assert(srv->config_storage);
3960 -       
3961 +
3962         for (i = 0; i < srv->config_context->used; i++) {
3963                 specific_config *s;
3964 -               
3965 +
3966                 s = calloc(1, sizeof(specific_config));
3967                 assert(s);
3968                 s->document_root = buffer_init();
3969 @@ -154,17 +157,18 @@
3970                 s->global_kbytes_per_second = 0;
3971                 s->global_bytes_per_second_cnt = 0;
3972                 s->global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
3973 -               
3974 +
3975                 cv[2].destination = s->errorfile_prefix;
3976 -               
3977 +
3978                 cv[7].destination = s->server_tag;
3979                 cv[8].destination = &(s->use_ipv6);
3980 -               
3981 -               
3982 +
3983 +
3984                 /* 13 max-worker */
3985                 cv[14].destination = s->document_root;
3986                 cv[15].destination = &(s->force_lowercase_filenames);
3987                 cv[16].destination = &(s->log_condition_handling);
3988 +               cv[46].destination = &(s->log_condition_cache_handling);
3989                 cv[17].destination = &(s->max_keep_alive_requests);
3990                 cv[18].destination = s->server_name;
3991                 cv[19].destination = &(s->max_keep_alive_idle);
3992 @@ -179,23 +183,23 @@
3993                 cv[28].destination = s->mimetypes;
3994                 cv[29].destination = s->ssl_pemfile;
3995                 cv[30].destination = &(s->is_ssl);
3996 -               
3997 +
3998                 cv[31].destination = &(s->log_file_not_found);
3999                 cv[32].destination = &(s->log_request_handling);
4000                 cv[33].destination = &(s->log_response_header);
4001                 cv[34].destination = &(s->log_request_header);
4002 -               
4003 +
4004                 cv[35].destination = &(s->allow_http11);
4005                 cv[38].destination = s->ssl_ca_file;
4006                 cv[40].destination = &(s->range_requests);
4007 -               
4008 +
4009                 srv->config_storage[i] = s;
4010 -       
4011 +
4012                 if (0 != (ret = config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv))) {
4013                         break;
4014                 }
4015         }
4016 -       
4017 +
4018         if (buffer_is_empty(stat_cache_string)) {
4019                 srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
4020         } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("simple"))) {
4021 @@ -205,22 +209,22 @@
4022         } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("disable"))) {
4023                 srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_NONE;
4024         } else {
4025 -               log_error_write(srv, __FILE__, __LINE__, "sb", 
4026 +               log_error_write(srv, __FILE__, __LINE__, "sb",
4027                                 "server.stat-cache-engine can be one of \"disable\", \"simple\", \"fam\", but not:", stat_cache_string);
4028                 ret = HANDLER_ERROR;
4029         }
4030 -       
4031 +
4032         buffer_free(stat_cache_string);
4033 -       
4034 +
4035         return ret;
4036 -                                                                
4037 -}
4038  
4039 +}
4040  
4041 -#define PATCH(x) con->conf.x = s->x
4042 +#define PATCH(x) \
4043 +       con->conf.x = s->x
4044  int config_setup_connection(server *srv, connection *con) {
4045         specific_config *s = srv->config_storage[0];
4046 -       
4047 +
4048         PATCH(allow_http11);
4049         PATCH(mimetypes);
4050         PATCH(document_root);
4051 @@ -236,20 +240,21 @@
4052         PATCH(kbytes_per_second);
4053         PATCH(global_kbytes_per_second);
4054         PATCH(global_bytes_per_second_cnt);
4055 -       
4056 +
4057         con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
4058         buffer_copy_string_buffer(con->server_name, s->server_name);
4059 -       
4060 +
4061         PATCH(log_request_header);
4062         PATCH(log_response_header);
4063         PATCH(log_request_handling);
4064         PATCH(log_condition_handling);
4065 +       PATCH(log_condition_cache_handling);
4066         PATCH(log_file_not_found);
4067 -       
4068 +
4069         PATCH(range_requests);
4070         PATCH(force_lowercase_filenames);
4071         PATCH(is_ssl);
4072 -       
4073 +
4074         PATCH(ssl_pemfile);
4075         PATCH(ssl_ca_file);
4076         return 0;
4077 @@ -257,22 +262,22 @@
4078  
4079  int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
4080         size_t i, j;
4081 -       
4082 +
4083         /* skip the first, the global context */
4084         for (i = 1; i < srv->config_context->used; i++) {
4085                 data_config *dc = (data_config *)srv->config_context->data[i];
4086                 specific_config *s = srv->config_storage[i];
4087 -               
4088 +
4089                 /* not our stage */
4090                 if (comp != dc->comp) continue;
4091 -               
4092 +
4093                 /* condition didn't match */
4094                 if (!config_check_cond(srv, con, dc)) continue;
4095 -               
4096 +
4097                 /* merge config */
4098                 for (j = 0; j < dc->value->used; j++) {
4099                         data_unset *du = dc->value->data[j];
4100 -                       
4101 +
4102                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.document-root"))) {
4103                                 PATCH(document_root);
4104                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.range-requests"))) {
4105 @@ -315,11 +320,13 @@
4106                                 PATCH(log_response_header);
4107                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-condition-handling"))) {
4108                                 PATCH(log_condition_handling);
4109 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-condition-cache-handling"))) {
4110 +                               PATCH(log_condition_cache_handling);
4111                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-file-not-found"))) {
4112                                 PATCH(log_file_not_found);
4113                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.protocol-http11"))) {
4114                                 PATCH(allow_http11);
4115 -                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {  
4116 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {
4117                                 PATCH(force_lowercase_filenames);
4118                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.kbytes-per-second"))) {
4119                                 PATCH(global_kbytes_per_second);
4120 @@ -328,7 +335,7 @@
4121                         }
4122                 }
4123         }
4124 -       
4125 +
4126         return 0;
4127  }
4128  #undef PATCH
4129 @@ -336,15 +343,15 @@
4130  typedef struct {
4131         int foo;
4132         int bar;
4133 -       
4134 +
4135         const buffer *source;
4136         const char *input;
4137         size_t offset;
4138         size_t size;
4139 -       
4140 +
4141         int line_pos;
4142         int line;
4143 -       
4144 +
4145         int in_key;
4146         int in_brace;
4147         int in_cond;
4148 @@ -362,7 +369,7 @@
4149         }
4150  
4151         if (0 != stream_open(&(t->s), t->file)) {
4152 -               log_error_write(srv, __FILE__, __LINE__, "sbss", 
4153 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
4154                                 "opening configfile ", t->file, "failed:", strerror(errno));
4155                 buffer_free(t->file);
4156                 return -1;
4157 @@ -373,7 +380,7 @@
4158         t->size = t->s.size;
4159         t->line = 1;
4160         t->line_pos = 1;
4161 -       
4162 +
4163         t->in_key = 1;
4164         t->in_brace = 0;
4165         t->in_cond = 0;
4166 @@ -401,7 +408,7 @@
4167  static int config_skip_comment(tokenizer_t *t) {
4168         int i;
4169         assert(t->input[t->offset] == '#');
4170 -       for (i = 1; t->input[t->offset + i] && 
4171 +       for (i = 1; t->input[t->offset + i] &&
4172              (t->input[t->offset + i] != '\n' && t->input[t->offset + i] != '\r');
4173              i++);
4174         t->offset += i;
4175 @@ -411,44 +418,44 @@
4176  static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *token) {
4177         int tid = 0;
4178         size_t i;
4179 -       
4180 +
4181         for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
4182                 char c = t->input[t->offset];
4183                 const char *start = NULL;
4184 -               
4185 +
4186                 switch (c) {
4187 -               case '=': 
4188 +               case '=':
4189                         if (t->in_brace) {
4190                                 if (t->input[t->offset + 1] == '>') {
4191                                         t->offset += 2;
4192 -                                       
4193 +
4194                                         buffer_copy_string(token, "=>");
4195 -                                       
4196 +
4197                                         tid = TK_ARRAY_ASSIGN;
4198                                 } else {
4199 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4200 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4201                                                         "source:", t->source,
4202 -                                                       "line:", t->line, "pos:", t->line_pos, 
4203 +                                                       "line:", t->line, "pos:", t->line_pos,
4204                                                         "use => for assignments in arrays");
4205                                         return -1;
4206                                 }
4207                         } else if (t->in_cond) {
4208                                 if (t->input[t->offset + 1] == '=') {
4209                                         t->offset += 2;
4210 -                                       
4211 +
4212                                         buffer_copy_string(token, "==");
4213 -                                       
4214 +
4215                                         tid = TK_EQ;
4216                                 } else if (t->input[t->offset + 1] == '~') {
4217                                         t->offset += 2;
4218 -                                       
4219 +
4220                                         buffer_copy_string(token, "=~");
4221 -                                       
4222 +
4223                                         tid = TK_MATCH;
4224                                 } else {
4225 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4226 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4227                                                         "source:", t->source,
4228 -                                                       "line:", t->line, "pos:", t->line_pos, 
4229 +                                                       "line:", t->line, "pos:", t->line_pos,
4230                                                         "only =~ and == are allowed in the condition");
4231                                         return -1;
4232                                 }
4233 @@ -456,51 +463,51 @@
4234                                 t->in_cond = 0;
4235                         } else if (t->in_key) {
4236                                 tid = TK_ASSIGN;
4237 -                               
4238 +
4239                                 buffer_copy_string_len(token, t->input + t->offset, 1);
4240 -                               
4241 +
4242                                 t->offset++;
4243                                 t->line_pos++;
4244                         } else {
4245 -                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4246 +                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4247                                                 "source:", t->source,
4248 -                                               "line:", t->line, "pos:", t->line_pos, 
4249 +                                               "line:", t->line, "pos:", t->line_pos,
4250                                                 "unexpected equal-sign: =");
4251                                 return -1;
4252                         }
4253 -                       
4254 +
4255                         break;
4256 -               case '!': 
4257 +               case '!':
4258                         if (t->in_cond) {
4259                                 if (t->input[t->offset + 1] == '=') {
4260                                         t->offset += 2;
4261 -                                       
4262 +
4263                                         buffer_copy_string(token, "!=");
4264 -                                       
4265 +
4266                                         tid = TK_NE;
4267                                 } else if (t->input[t->offset + 1] == '~') {
4268                                         t->offset += 2;
4269 -                                       
4270 +
4271                                         buffer_copy_string(token, "!~");
4272 -                                       
4273 +
4274                                         tid = TK_NOMATCH;
4275                                 } else {
4276 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4277 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4278                                                         "source:", t->source,
4279 -                                                       "line:", t->line, "pos:", t->line_pos, 
4280 +                                                       "line:", t->line, "pos:", t->line_pos,
4281                                                         "only !~ and != are allowed in the condition");
4282                                         return -1;
4283                                 }
4284                                 t->in_key = 1;
4285                                 t->in_cond = 0;
4286                         } else {
4287 -                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4288 +                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4289                                                 "source:", t->source,
4290 -                                               "line:", t->line, "pos:", t->line_pos, 
4291 +                                               "line:", t->line, "pos:", t->line_pos,
4292                                                 "unexpected exclamation-marks: !");
4293                                 return -1;
4294                         }
4295 -                       
4296 +
4297                         break;
4298                 case '\t':
4299                 case ' ':
4300 @@ -546,10 +553,10 @@
4301                 case ',':
4302                         if (t->in_brace > 0) {
4303                                 tid = TK_COMMA;
4304 -                               
4305 +
4306                                 buffer_copy_string(token, "(COMMA)");
4307                         }
4308 -                       
4309 +
4310                         t->offset++;
4311                         t->line_pos++;
4312                         break;
4313 @@ -557,70 +564,70 @@
4314                         /* search for the terminating " */
4315                         start = t->input + t->offset + 1;
4316                         buffer_copy_string(token, "");
4317 -                       
4318 +
4319                         for (i = 1; t->input[t->offset + i]; i++) {
4320                                 if (t->input[t->offset + i] == '\\' &&
4321                                     t->input[t->offset + i + 1] == '"') {
4322 -                                       
4323 +
4324                                         buffer_append_string_len(token, start, t->input + t->offset + i - start);
4325 -                                       
4326 +
4327                                         start = t->input + t->offset + i + 1;
4328 -                                       
4329 +
4330                                         /* skip the " */
4331                                         i++;
4332                                         continue;
4333                                 }
4334 -                               
4335 -                               
4336 +
4337 +
4338                                 if (t->input[t->offset + i] == '"') {
4339                                         tid = TK_STRING;
4340 -                               
4341 +
4342                                         buffer_append_string_len(token, start, t->input + t->offset + i - start);
4343 -                                       
4344 +
4345                                         break;
4346                                 }
4347                         }
4348  
4349                         if (t->input[t->offset + i] == '\0') {
4350                                 /* ERROR */
4351 -                               
4352 -                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4353 +
4354 +                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4355                                                 "source:", t->source,
4356 -                                               "line:", t->line, "pos:", t->line_pos, 
4357 +                                               "line:", t->line, "pos:", t->line_pos,
4358                                                 "missing closing quote");
4359 -                               
4360 +
4361                                 return -1;
4362                         }
4363 -                       
4364 +
4365                         t->offset += i + 1;
4366                         t->line_pos += i + 1;
4367 -                       
4368 +
4369                         break;
4370                 case '(':
4371                         t->offset++;
4372                         t->in_brace++;
4373 -                               
4374 +
4375                         tid = TK_LPARAN;
4376 -                               
4377 +
4378                         buffer_copy_string(token, "(");
4379                         break;
4380                 case ')':
4381                         t->offset++;
4382                         t->in_brace--;
4383 -                               
4384 +
4385                         tid = TK_RPARAN;
4386 -                               
4387 +
4388                         buffer_copy_string(token, ")");
4389                         break;
4390                 case '$':
4391                         t->offset++;
4392 -                               
4393 +
4394                         tid = TK_DOLLAR;
4395                         t->in_cond = 1;
4396                         t->in_key = 0;
4397 -                               
4398 +
4399                         buffer_copy_string(token, "$");
4400 -                       
4401 +
4402                         break;
4403  
4404                 case '+':
4405 @@ -637,115 +644,107 @@
4406  
4407                 case '{':
4408                         t->offset++;
4409 -                               
4410 +
4411                         tid = TK_LCURLY;
4412 -                               
4413 +
4414                         buffer_copy_string(token, "{");
4415 -                       
4416 +
4417                         break;
4418 -                       
4419 +
4420                 case '}':
4421                         t->offset++;
4422 -                               
4423 +
4424                         tid = TK_RCURLY;
4425 -                               
4426 +
4427                         buffer_copy_string(token, "}");
4428 -                       
4429 +
4430                         break;
4431  
4432                 case '[':
4433                         t->offset++;
4434 -                               
4435 +
4436                         tid = TK_LBRACKET;
4437 -                               
4438 +
4439                         buffer_copy_string(token, "[");
4440 -                       
4441 +
4442                         break;
4443 -                       
4444 +
4445                 case ']':
4446                         t->offset++;
4447 -                               
4448 +
4449                         tid = TK_RBRACKET;
4450 -                               
4451 +
4452                         buffer_copy_string(token, "]");
4453 -                       
4454 +
4455                         break;
4456                 case '#':
4457                         t->line_pos += config_skip_comment(t);
4458 -                       
4459 +
4460                         break;
4461                 default:
4462                         if (t->in_cond) {
4463 -                               for (i = 0; t->input[t->offset + i] && 
4464 +                               for (i = 0; t->input[t->offset + i] &&
4465                                      (isalpha((unsigned char)t->input[t->offset + i])
4466                                       ); i++);
4467 -                               
4468 +
4469                                 if (i && t->input[t->offset + i]) {
4470                                         tid = TK_SRVVARNAME;
4471                                         buffer_copy_string_len(token, t->input + t->offset, i);
4472 -                                       
4473 +
4474                                         t->offset += i;
4475                                         t->line_pos += i;
4476                                 } else {
4477                                         /* ERROR */
4478 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4479 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4480                                                         "source:", t->source,
4481 -                                                       "line:", t->line, "pos:", t->line_pos, 
4482 +                                                       "line:", t->line, "pos:", t->line_pos,
4483                                                         "invalid character in condition");
4484                                         return -1;
4485                                 }
4486                         } else if (isdigit((unsigned char)c)) {
4487                                 /* take all digits */
4488                                 for (i = 0; t->input[t->offset + i] && isdigit((unsigned char)t->input[t->offset + i]);  i++);
4489 -                               
4490 +
4491                                 /* was there it least a digit ? */
4492 -                               if (i && t->input[t->offset + i]) {
4493 +                               if (i) {
4494                                         tid = TK_INTEGER;
4495 -                                       
4496 +
4497                                         buffer_copy_string_len(token, t->input + t->offset, i);
4498 -                                       
4499 +
4500                                         t->offset += i;
4501                                         t->line_pos += i;
4502 -                               } else {
4503 -                                       /* ERROR */
4504 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4505 -                                                       "source:", t->source,
4506 -                                                       "line:", t->line, "pos:", t->line_pos, 
4507 -                                                       "unexpected EOF");
4508 -                                       
4509 -                                       return -1;
4510                                 }
4511                         } else {
4512                                 /* the key might consist of [-.0-9a-z] */
4513 -                               for (i = 0; t->input[t->offset + i] && 
4514 -                                    (isalnum((unsigned char)t->input[t->offset + i]) || 
4515 +                               for (i = 0; t->input[t->offset + i] &&
4516 +                                    (isalnum((unsigned char)t->input[t->offset + i]) ||
4517                                       t->input[t->offset + i] == '.' ||
4518                                       t->input[t->offset + i] == '_' || /* for env.* */
4519                                       t->input[t->offset + i] == '-'
4520                                       ); i++);
4521 -                               
4522 +
4523                                 if (i && t->input[t->offset + i]) {
4524                                         buffer_copy_string_len(token, t->input + t->offset, i);
4525 -                                       
4526 -                                       if (strcmp(token->ptr, "include") == 0) {
4527 +
4528 +                                       if (buffer_is_equal_string(token, CONST_STR_LEN("include"))) {
4529                                                 tid = TK_INCLUDE;
4530 -                                       } else if (strcmp(token->ptr, "include_shell") == 0) {
4531 +                                       } else if (buffer_is_equal_string(token, CONST_STR_LEN("include_shell"))) {
4532                                                 tid = TK_INCLUDE_SHELL;
4533 -                                       } else if (strcmp(token->ptr, "global") == 0) {
4534 +                                       } else if (buffer_is_equal_string(token, CONST_STR_LEN("global"))) {
4535                                                 tid = TK_GLOBAL;
4536 -                                       } else if (strcmp(token->ptr, "else") == 0) {
4537 +                                       } else if (buffer_is_equal_string(token, CONST_STR_LEN("else"))) {
4538                                                 tid = TK_ELSE;
4539                                         } else {
4540                                                 tid = TK_LKEY;
4541                                         }
4542 -                                       
4543 +
4544                                         t->offset += i;
4545                                         t->line_pos += i;
4546                                 } else {
4547                                         /* ERROR */
4548 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4549 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4550                                                         "source:", t->source,
4551 -                                                       "line:", t->line, "pos:", t->line_pos, 
4552 +                                                       "line:", t->line, "pos:", t->line_pos,
4553                                                         "invalid character in variable name");
4554                                         return -1;
4555                                 }
4556 @@ -753,16 +752,16 @@
4557                         break;
4558                 }
4559         }
4560 -       
4561 +
4562         if (tid) {
4563                 *token_id = tid;
4564  #if 0
4565 -               log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd", 
4566 +               log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd",
4567                                 "source:", t->source,
4568                                 "line:", t->line, "pos:", t->line_pos,
4569                                 token, token->used - 1, tid);
4570  #endif
4571 -               
4572 +
4573                 return 1;
4574         } else if (t->offset < t->size) {
4575                 fprintf(stderr, "%s.%d: %d, %s\n",
4576 @@ -781,10 +780,11 @@
4577         pParser = configparserAlloc( malloc );
4578         lasttoken = buffer_init();
4579         token = buffer_init();
4580 +
4581         while((1 == (ret = config_tokenizer(srv, t, &token_id, token))) && context->ok) {
4582                 buffer_copy_string_buffer(lasttoken, token);
4583                 configparser(pParser, token_id, token, context);
4584 -               
4585 +
4586                 token = buffer_init();
4587         }
4588         buffer_free(token);
4589 @@ -797,14 +797,14 @@
4590                 }
4591         }
4592         configparserFree(pParser, free);
4593 -       
4594 +
4595         if (ret == -1) {
4596 -               log_error_write(srv, __FILE__, __LINE__, "sb", 
4597 +               log_error_write(srv, __FILE__, __LINE__, "sb",
4598                                 "configfile parser failed:", lasttoken);
4599         } else if (context->ok == 0) {
4600 -               log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb", 
4601 +               log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb",
4602                                 "source:", t->source,
4603 -                               "line:", t->line, "pos:", t->line_pos, 
4604 +                               "line:", t->line, "pos:", t->line_pos,
4605                                 "parser failed somehow near here:", lasttoken);
4606                 ret = -1;
4607         }
4608 @@ -821,7 +821,7 @@
4609         t->offset = 0;
4610         t->line = 1;
4611         t->line_pos = 1;
4612 -       
4613 +
4614         t->in_key = 1;
4615         t->in_brace = 0;
4616         t->in_cond = 0;
4617 @@ -844,7 +844,7 @@
4618         }
4619  
4620         if (0 != stream_open(&s, filename)) {
4621 -               log_error_write(srv, __FILE__, __LINE__, "sbss", 
4622 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
4623                                 "opening configfile ", filename, "failed:", strerror(errno));
4624                 ret = -1;
4625         } else {
4626 @@ -866,7 +866,7 @@
4627         char oldpwd[PATH_MAX];
4628  
4629         if (NULL == getcwd(oldpwd, sizeof(oldpwd))) {
4630 -               log_error_write(srv, __FILE__, __LINE__, "s", 
4631 +               log_error_write(srv, __FILE__, __LINE__, "s",
4632                                 "cannot get cwd", strerror(errno));
4633                 return -1;
4634         }
4635 @@ -879,7 +879,7 @@
4636         }
4637  
4638         if (0 != proc_open_buffer(&proc, cmd, NULL, out, NULL)) {
4639 -               log_error_write(srv, __FILE__, __LINE__, "sbss", 
4640 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
4641                                 "opening", source, "failed:", strerror(errno));
4642                 ret = -1;
4643         } else {
4644 @@ -896,13 +896,12 @@
4645  static void context_init(server *srv, config_t *context) {
4646         context->srv = srv;
4647         context->ok = 1;
4648 -       context->configs_stack = array_init();
4649 -       context->configs_stack->is_weakref = 1;
4650 +       context->configs_stack = buffer_ptr_init(NULL);
4651         context->basedir = buffer_init();
4652  }
4653  
4654  static void context_free(config_t *context) {
4655 -       array_free(context->configs_stack);
4656 +       buffer_ptr_free(context->configs_stack);
4657         buffer_free(context->basedir);
4658  }
4659  
4660 @@ -918,18 +917,15 @@
4661         context_init(srv, &context);
4662         context.all_configs = srv->config_context;
4663  
4664 -       pos = strrchr(fn,
4665 -#ifdef __WIN32
4666 -                       '\\'
4667 -#else
4668 -                       '/'
4669 -#endif
4670 -                       );
4671 +    /* use the current dir as basedir for all other includes
4672 +    */
4673 +       pos = strrchr(fn, DIR_SEPERATOR);
4674 +
4675         if (pos) {
4676                 buffer_copy_string_len(context.basedir, fn, pos - fn + 1);
4677                 fn = pos + 1;
4678         }
4679 -       
4680 +
4681         dc = data_config_init();
4682         buffer_copy_string(dc->key, "global");
4683  
4684 @@ -944,7 +940,7 @@
4685         dpid->value = getpid();
4686         buffer_copy_string(dpid->key, "var.PID");
4687         array_insert_unique(srv->config, (data_unset *)dpid);
4688 -       
4689 +
4690         dcwd = data_string_init();
4691         buffer_prepare_copy(dcwd->value, 1024);
4692         if (NULL != getcwd(dcwd->value->ptr, dcwd->value->size - 1)) {
4693 @@ -968,7 +964,7 @@
4694         } else {
4695                 return -1;
4696         }
4697 -       
4698 +
4699         if (NULL != (modules = (data_array *)array_get_element(srv->config, "server.modules"))) {
4700                 data_string *ds;
4701                 data_array *prepends;
4702 @@ -1026,22 +1022,23 @@
4703                 buffer_copy_string(modules->key, "server.modules");
4704                 array_insert_unique(srv->config, (data_unset *)modules);
4705         }
4706 -       
4707 +
4708  
4709         if (0 != config_insert(srv)) {
4710                 return -1;
4711         }
4712 -       
4713 +
4714         return 0;
4715  }
4716  
4717 +
4718  int config_set_defaults(server *srv) {
4719         size_t i;
4720         specific_config *s = srv->config_storage[0];
4721         struct stat st1, st2;
4722 -       
4723 -       struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] = 
4724 -       { 
4725 +
4726 +       struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
4727 +       {
4728                 /* - poll is most reliable
4729                  * - select works everywhere
4730                  * - linux-* are experimental
4731 @@ -1067,20 +1064,21 @@
4732  #endif
4733                 { FDEVENT_HANDLER_UNSET,          NULL }
4734         };
4735 -       
4736  
4737 -       if (buffer_is_empty(s->document_root)) {  
4738 -               log_error_write(srv, __FILE__, __LINE__, "s",  
4739 -                               "a default document-root has to be set");  
4740 -               
4741 -               return -1;  
4742 -       }  
4743 -       
4744 +
4745 +       if (buffer_is_empty(s->document_root)) {
4746 +               log_error_write(srv, __FILE__, __LINE__, "s",
4747 +                               "a default document-root has to be set");
4748 +
4749 +               return -1;
4750 +       }
4751 +
4752         if (buffer_is_empty(srv->srvconf.changeroot)) {
4753 -               if (-1 == stat(s->document_root->ptr, &st1)) {  
4754 -                       log_error_write(srv, __FILE__, __LINE__, "sb",  
4755 +        pathname_unix2local(s->document_root);
4756 +               if (-1 == stat(s->document_root->ptr, &st1)) {
4757 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
4758                                         "base-docroot doesn't exist:",
4759 -                                       s->document_root);  
4760 +                                       s->document_root, strerror(errno));
4761                         return -1;
4762                 }
4763  
4764 @@ -1088,18 +1086,18 @@
4765                 buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.changeroot);
4766                 buffer_append_string_buffer(srv->tmp_buf, s->document_root);
4767  
4768 -               if (-1 == stat(srv->tmp_buf->ptr, &st1)) {  
4769 -                       log_error_write(srv, __FILE__, __LINE__, "sb",  
4770 +               if (-1 == stat(srv->tmp_buf->ptr, &st1)) {
4771 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
4772                                         "base-docroot doesn't exist:",
4773 -                                       srv->tmp_buf);  
4774 +                                       srv->tmp_buf);
4775                         return -1;
4776                 }
4777 -               
4778 +
4779         }
4780 -       
4781 -       buffer_copy_string_buffer(srv->tmp_buf, s->document_root);  
4782  
4783 -       buffer_to_lower(srv->tmp_buf);  
4784 +       buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
4785 +
4786 +       buffer_to_lower(srv->tmp_buf);
4787  
4788         if (0 == stat(srv->tmp_buf->ptr, &st1)) {
4789                 int is_lower = 0;
4790 @@ -1107,68 +1105,68 @@
4791                 is_lower = buffer_is_equal(srv->tmp_buf, s->document_root);
4792  
4793                 /* lower-case existed, check upper-case */
4794 -               buffer_copy_string_buffer(srv->tmp_buf, s->document_root);  
4795 +               buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
4796  
4797 -               buffer_to_upper(srv->tmp_buf);  
4798 +               buffer_to_upper(srv->tmp_buf);
4799  
4800                 /* we have to handle the special case that upper and lower-casing results in the same filename
4801                  * as in server.document-root = "/" or "/12345/" */
4802  
4803                 if (is_lower && buffer_is_equal(srv->tmp_buf, s->document_root)) {
4804 -                       /* lower-casing and upper-casing didn't result in  
4805 -                        * an other filename, no need to stat(), 
4806 +                       /* lower-casing and upper-casing didn't result in
4807 +                        * an other filename, no need to stat(),
4808                          * just assume it is case-sensitive. */
4809  
4810                         s->force_lowercase_filenames = 0;
4811 -               } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {  
4812 +               } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {
4813 +
4814 +                       /* upper case exists too, doesn't the FS handle this ? */
4815 +
4816 +                       /* upper and lower have the same inode -> case-insensitve FS */
4817 +
4818 +                       if (st1.st_ino == st2.st_ino) {
4819 +                               /* upper and lower have the same inode -> case-insensitve FS */
4820 +
4821 +                               s->force_lowercase_filenames = 1;
4822 +                       }
4823 +               }
4824 +       }
4825  
4826 -                       /* upper case exists too, doesn't the FS handle this ? */  
4827 -                       
4828 -                       /* upper and lower have the same inode -> case-insensitve FS */  
4829 -                       
4830 -                       if (st1.st_ino == st2.st_ino) {  
4831 -                               /* upper and lower have the same inode -> case-insensitve FS */  
4832 -                               
4833 -                               s->force_lowercase_filenames = 1;  
4834 -                       }  
4835 -               }  
4836 -       }  
4837 -       
4838         if (srv->srvconf.port == 0) {
4839                 srv->srvconf.port = s->is_ssl ? 443 : 80;
4840         }
4841 -       
4842 +
4843         if (srv->srvconf.event_handler->used == 0) {
4844                 /* choose a good default
4845 -                * 
4846 -                * the event_handler list is sorted by 'goodness' 
4847 +                *
4848 +                * the event_handler list is sorted by 'goodness'
4849                  * taking the first available should be the best solution
4850                  */
4851                 srv->event_handler = event_handlers[0].et;
4852 -               
4853 +
4854                 if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
4855 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
4856 +                       log_error_write(srv, __FILE__, __LINE__, "s",
4857                                         "sorry, there is no event handler for this system");
4858 -                       
4859 +
4860                         return -1;
4861                 }
4862         } else {
4863                 /*
4864                  * User override
4865                  */
4866 -               
4867 +
4868                 for (i = 0; event_handlers[i].name; i++) {
4869                         if (0 == strcmp(event_handlers[i].name, srv->srvconf.event_handler->ptr)) {
4870                                 srv->event_handler = event_handlers[i].et;
4871                                 break;
4872                         }
4873                 }
4874 -               
4875 +
4876                 if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
4877 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
4878 -                                       "the selected event-handler in unknown or not supported:", 
4879 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
4880 +                                       "the selected event-handler in unknown or not supported:",
4881                                         srv->srvconf.event_handler );
4882 -                       
4883 +
4884                         return -1;
4885                 }
4886         }
4887 @@ -1176,19 +1174,19 @@
4888         if (s->is_ssl) {
4889                 if (buffer_is_empty(s->ssl_pemfile)) {
4890                         /* PEM file is require */
4891 -                       
4892 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
4893 +
4894 +                       log_error_write(srv, __FILE__, __LINE__, "s",
4895                                         "ssl.pemfile has to be set");
4896                         return -1;
4897                 }
4898 -               
4899 +
4900  #ifndef USE_OPENSSL
4901 -               log_error_write(srv, __FILE__, __LINE__, "s", 
4902 +               log_error_write(srv, __FILE__, __LINE__, "s",
4903                                 "ssl support is missing, recompile with --with-openssl");
4904 -               
4905 +
4906                 return -1;
4907  #endif
4908         }
4909 -       
4910 +
4911         return 0;
4912  }
4913 --- ../lighttpd-1.4.11/src/configfile.h 2005-08-23 17:36:12.000000000 +0300
4914 +++ lighttpd-1.4.12/src/configfile.h    2006-07-16 00:26:03.000000000 +0300
4915 @@ -9,7 +9,7 @@
4916         server *srv;
4917         int     ok;
4918         array  *all_configs;
4919 -       array  *configs_stack; /* to parse nested block */
4920 +       buffer_ptr  *configs_stack; /* to parse nested block */
4921         data_config *current; /* current started with { */
4922         buffer *basedir;
4923  } config_t;
4924 --- ../lighttpd-1.4.11/src/configparser.c       2006-02-01 19:51:15.000000000 +0200
4925 +++ lighttpd-1.4.12/src/configparser.c  2006-07-17 22:02:23.000000000 +0300
4926 @@ -24,52 +24,34 @@
4927      dc->parent = ctx->current;
4928      array_insert_unique(dc->parent->childs, (data_unset *)dc);
4929    }
4930 -  array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
4931 +  buffer_ptr_append(ctx->configs_stack, (void *)ctx->current);
4932    ctx->current = dc;
4933  }
4934  
4935  static data_config *configparser_pop(config_t *ctx) {
4936    data_config *old = ctx->current;
4937 -  ctx->current = (data_config *) array_pop(ctx->configs_stack);
4938 +  ctx->current = (data_config *) buffer_ptr_pop(ctx->configs_stack);
4939    return old;
4940  }
4941  
4942  /* return a copied variable */
4943  static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
4944 -  if (strncmp(key->ptr, "env.", sizeof("env.") - 1) == 0) {
4945 -    char *env;
4946 -
4947 -    if (NULL != (env = getenv(key->ptr + 4))) {
4948 -      data_string *ds;
4949 -      ds = data_string_init();
4950 -      buffer_append_string(ds->value, env);
4951 -      return (data_unset *)ds;
4952 -    }
4953 -
4954 -    fprintf(stderr, "Undefined env variable: %s\n", key->ptr + 4);
4955 -    ctx->ok = 0;
4956 -
4957 -    return NULL;
4958 -  } else {
4959 -    data_unset *du;
4960 -    data_config *dc;
4961 +  data_unset *du;
4962 +  data_config *dc;
4963  
4964  #if 0
4965 -    fprintf(stderr, "get var %s\n", key->ptr);
4966 +  fprintf(stderr, "get var %s\n", key->ptr);
4967  #endif
4968 -    for (dc = ctx->current; dc; dc = dc->parent) {
4969 +  for (dc = ctx->current; dc; dc = dc->parent) {
4970  #if 0
4971 -      fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
4972 -      array_print(dc->value, 0);
4973 +    fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
4974 +    array_print(dc->value, 0);
4975  #endif
4976 -      if (NULL != (du = array_get_element(dc->value, key->ptr))) {
4977 -        return du->copy(du);
4978 -      }
4979 +    if (NULL != (du = array_get_element(dc->value, key->ptr))) {
4980 +      return du->copy(du);
4981      }
4982 -    fprintf(stderr, "Undefined config variable: %s\n", key->ptr);
4983 -    ctx->ok = 0;
4984 -    return NULL;
4985    }
4986 +  return NULL;
4987  }
4988  
4989  /* op1 is to be eat/return by this function, op1->key is not cared
4990 @@ -124,14 +106,14 @@
4991  }
4992  
4993  
4994 -#line 128 "configparser.c"
4995 +#line 110 "configparser.c"
4996  /* Next is all token values, in a form suitable for use by makeheaders.
4997  ** This section will be null unless lemon is run with the -m switch.
4998  */
4999 -/* 
5000 +/*
5001  ** These constants (all generated automatically by the parser generator)
5002  ** specify the various kinds of tokens (terminals) that the parser
5003 -** understands. 
5004 +** understands.
5005  **
5006  ** Each symbol here is a terminal symbol in the grammar.
5007  */
5008 @@ -148,7 +130,7 @@
5009  **                       and nonterminals.  "int" is used otherwise.
5010  **    YYNOCODE           is a number of type YYCODETYPE which corresponds
5011  **                       to no legal terminal or nonterminal number.  This
5012 -**                       number is used to fill in empty slots of the hash 
5013 +**                       number is used to fill in empty slots of the hash
5014  **                       table.
5015  **    YYFALLBACK         If defined, this indicates that one or more tokens
5016  **                       have fall-back values which should be used if the
5017 @@ -157,7 +139,7 @@
5018  **                       and nonterminal numbers.  "unsigned char" is
5019  **                       used if there are fewer than 250 rules and
5020  **                       states combined.  "int" is used otherwise.
5021 -**    configparserTOKENTYPE     is the data type used for minor tokens given 
5022 +**    configparserTOKENTYPE     is the data type used for minor tokens given
5023  **                       directly to the parser from the tokenizer.
5024  **    YYMINORTYPE        is the data type used for all minor tokens.
5025  **                       This is typically a union of many types, one of
5026 @@ -192,8 +174,8 @@
5027  #define configparserARG_PDECL ,config_t *ctx
5028  #define configparserARG_FETCH config_t *ctx = yypParser->ctx
5029  #define configparserARG_STORE yypParser->ctx = ctx
5030 -#define YYNSTATE 62
5031 -#define YYNRULE 39
5032 +#define YYNSTATE 63
5033 +#define YYNRULE 40
5034  #define YYERRORSYMBOL 26
5035  #define YYERRSYMDT yy95
5036  #define YY_NO_ACTION      (YYNSTATE+YYNRULE+2)
5037 @@ -203,7 +185,7 @@
5038  /* Next are that tables used to determine what action to take based on the
5039  ** current state and lookahead token.  These tables are used to implement
5040  ** functions that take a state number and lookahead value and return an
5041 -** action integer.  
5042 +** action integer.
5043  **
5044  ** Suppose the action integer is N.  Then the action is determined as
5045  ** follows
5046 @@ -228,7 +210,7 @@
5047  ** If the index value yy_shift_ofst[S]+X is out of range or if the value
5048  ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
5049  ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
5050 -** and that yy_default[S] should be used instead.  
5051 +** and that yy_default[S] should be used instead.
5052  **
5053  ** The formula above is for computing the action when the lookahead is
5054  ** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
5055 @@ -248,67 +230,69 @@
5056  **  yy_default[]       Default action for each state.
5057  */
5058  static YYACTIONTYPE yy_action[] = {
5059 - /*     0 */     2,    3,    4,    5,   13,   14,   62,   15,    7,   44,
5060 - /*    10 */    20,   86,   16,   45,   28,   48,   40,   10,   39,   25,
5061 - /*    20 */    22,   49,   45,    8,   15,  102,    1,   20,   28,   18,
5062 - /*    30 */    57,   59,   19,   25,   22,   39,   19,   61,   98,   45,
5063 - /*    40 */    20,    6,   23,   24,   26,   28,   35,   57,   59,   12,
5064 - /*    50 */    25,   22,   28,   27,   36,   87,   29,   25,   22,   33,
5065 - /*    60 */    15,   30,   31,   20,   28,   38,    9,   17,   37,   25,
5066 - /*    70 */    22,   39,   42,   43,   10,   45,   11,   53,   54,   55,
5067 - /*    80 */    56,   28,   52,   57,   59,   34,   25,   22,   28,   27,
5068 - /*    90 */    32,   88,   41,   25,   22,   33,   28,   48,   46,   28,
5069 - /*   100 */    48,   25,   22,   58,   25,   22,   60,   21,   19,   47,
5070 - /*   110 */    51,   50,   25,   22,   88,   88,   93,
5071 + /*     0 */     2,    3,    4,    5,   13,   14,   63,   15,    7,   45,
5072 + /*    10 */    20,   88,   16,   46,   28,   49,   41,   10,   40,   25,
5073 + /*    20 */    22,   50,   46,    8,   15,  104,    1,   20,   28,   18,
5074 + /*    30 */    58,   60,    6,   25,   22,   40,   47,   62,   11,   46,
5075 + /*    40 */    20,    9,   23,   24,   26,   29,   89,   58,   60,   10,
5076 + /*    50 */    17,   38,   28,   27,   37,   19,   30,   25,   22,   34,
5077 + /*    60 */    15,  100,   20,   20,   23,   24,   26,   12,   19,   31,
5078 + /*    70 */    32,   40,   19,   44,   43,   46,   95,   35,   90,   89,
5079 + /*    80 */    28,   49,   42,   58,   60,   25,   22,   59,   28,   27,
5080 + /*    90 */    33,   48,   52,   25,   22,   34,   28,   49,   51,   28,
5081 + /*   100 */    36,   25,   22,   61,   25,   22,   89,   28,   39,   89,
5082 + /*   110 */    89,   89,   25,   22,   54,   55,   56,   57,   89,   28,
5083 + /*   120 */    53,   21,   89,   89,   25,   22,   25,   22,
5084  };
5085  static YYCODETYPE yy_lookahead[] = {
5086   /*     0 */    29,   30,   31,   32,   33,   34,    0,    1,   44,   38,
5087   /*    10 */     4,   15,   41,   16,   35,   36,   45,   46,   12,   40,
5088   /*    20 */    41,   42,   16,   15,    1,   27,   28,    4,   35,   36,
5089 - /*    30 */    24,   25,    5,   40,   41,   12,    5,   14,   11,   16,
5090 - /*    40 */     4,    1,    6,    7,    8,   35,   36,   24,   25,   28,
5091 - /*    50 */    40,   41,   35,   36,   37,   15,   39,   40,   41,   42,
5092 - /*    60 */     1,    9,   10,    4,   35,   36,   38,    2,    3,   40,
5093 - /*    70 */    41,   12,   28,   14,   46,   16,   13,   20,   21,   22,
5094 - /*    80 */    23,   35,   36,   24,   25,   11,   40,   41,   35,   36,
5095 - /*    90 */    37,   13,   13,   40,   41,   42,   35,   36,   17,   35,
5096 - /*   100 */    36,   40,   41,   42,   40,   41,   42,   35,    5,   18,
5097 - /*   110 */    43,   19,   40,   41,   47,   47,   13,
5098 + /*    30 */    24,   25,    1,   40,   41,   12,   17,   14,   13,   16,
5099 + /*    40 */     4,   38,    6,    7,    8,    9,   15,   24,   25,   46,
5100 + /*    50 */     2,    3,   35,   36,   37,    5,   39,   40,   41,   42,
5101 + /*    60 */     1,   11,    4,    4,    6,    7,    8,   28,    5,    9,
5102 + /*    70 */    10,   12,    5,   14,   28,   16,   13,   11,   13,   47,
5103 + /*    80 */    35,   36,   13,   24,   25,   40,   41,   42,   35,   36,
5104 + /*    90 */    37,   18,   43,   40,   41,   42,   35,   36,   19,   35,
5105 + /*   100 */    36,   40,   41,   42,   40,   41,   47,   35,   36,   47,
5106 + /*   110 */    47,   47,   40,   41,   20,   21,   22,   23,   47,   35,
5107 + /*   120 */    36,   35,   47,   47,   40,   41,   40,   41,
5108  };
5109  #define YY_SHIFT_USE_DFLT (-5)
5110  static signed char yy_shift_ofst[] = {
5111 - /*     0 */    -5,    6,   -5,   -5,   -5,   40,   -4,    8,   -3,   -5,
5112 - /*    10 */    63,   -5,   23,   -5,   -5,   -5,   65,   36,   31,   36,
5113 - /*    20 */    -5,   -5,   -5,   -5,   -5,   -5,   36,   27,   -5,   52,
5114 - /*    30 */    -5,   36,   -5,   74,   36,   31,   -5,   36,   31,   78,
5115 - /*    40 */    79,   -5,   59,   -5,   -5,   81,   91,   36,   31,   92,
5116 - /*    50 */    57,   36,  103,   -5,   -5,   -5,   -5,   36,   -5,   36,
5117 - /*    60 */    -5,   -5,
5118 + /*     0 */    -5,    6,   -5,   -5,   -5,   31,   -4,    8,   -3,   -5,
5119 + /*    10 */    25,   -5,   23,   -5,   -5,   -5,   48,   58,   67,   58,
5120 + /*    20 */    -5,   -5,   -5,   -5,   -5,   -5,   36,   50,   -5,   -5,
5121 + /*    30 */    60,   -5,   58,   -5,   66,   58,   67,   -5,   58,   67,
5122 + /*    40 */    65,   69,   -5,   59,   -5,   -5,   19,   73,   58,   67,
5123 + /*    50 */    79,   94,   58,   63,   -5,   -5,   -5,   -5,   58,   -5,
5124 + /*    60 */    58,   -5,   -5,
5125  };
5126  #define YY_REDUCE_USE_DFLT (-37)
5127  static signed char yy_reduce_ofst[] = {
5128 - /*     0 */    -2,  -29,  -37,  -37,  -37,  -36,  -37,  -37,   28,  -37,
5129 - /*    10 */   -37,   21,  -29,  -37,  -37,  -37,  -37,   -7,  -37,   72,
5130 + /*     0 */    -2,  -29,  -37,  -37,  -37,  -36,  -37,  -37,    3,  -37,
5131 + /*    10 */   -37,   39,  -29,  -37,  -37,  -37,  -37,   -7,  -37,   86,
5132   /*    20 */   -37,  -37,  -37,  -37,  -37,  -37,   17,  -37,  -37,  -37,
5133 - /*    30 */   -37,   53,  -37,  -37,   10,  -37,  -37,   29,  -37,  -37,
5134 - /*    40 */   -37,   44,  -29,  -37,  -37,  -37,  -37,  -21,  -37,  -37,
5135 - /*    50 */    67,   46,  -37,  -37,  -37,  -37,  -37,   61,  -37,   64,
5136 - /*    60 */   -37,  -37,
5137 + /*    30 */   -37,  -37,   53,  -37,  -37,   64,  -37,  -37,   72,  -37,
5138 + /*    40 */   -37,  -37,   46,  -29,  -37,  -37,  -37,  -37,  -21,  -37,
5139 + /*    50 */   -37,   49,   84,  -37,  -37,  -37,  -37,  -37,   45,  -37,
5140 + /*    60 */    61,  -37,  -37,
5141  };
5142  static YYACTIONTYPE yy_default[] = {
5143 - /*     0 */    64,  101,   63,   65,   66,  101,   67,  101,  101,   90,
5144 - /*    10 */   101,   64,  101,   68,   69,   70,  101,  101,   71,  101,
5145 - /*    20 */    73,   74,   76,   77,   78,   79,  101,   84,   75,  101,
5146 - /*    30 */    80,   82,   81,  101,  101,   85,   83,  101,   72,  101,
5147 - /*    40 */   101,   64,  101,   89,   91,  101,  101,  101,   98,  101,
5148 - /*    50 */   101,  101,  101,   94,   95,   96,   97,  101,   99,  101,
5149 - /*    60 */   100,   92,
5150 + /*     0 */    65,  103,   64,   66,   67,  103,   68,  103,  103,   92,
5151 + /*    10 */   103,   65,  103,   69,   70,   71,  103,  103,   72,  103,
5152 + /*    20 */    74,   75,   77,   78,   79,   80,  103,   86,   76,   81,
5153 + /*    30 */   103,   82,   84,   83,  103,  103,   87,   85,  103,   73,
5154 + /*    40 */   103,  103,   65,  103,   91,   93,  103,  103,  103,  100,
5155 + /*    50 */   103,  103,  103,  103,   96,   97,   98,   99,  103,  101,
5156 + /*    60 */   103,  102,   94,
5157  };
5158  #define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
5159  
5160  /* The next table maps tokens into fallback tokens.  If a construct
5161  ** like the following:
5162 -** 
5163 +**
5164  **      %fallback ID X Y Z.
5165  **
5166  ** appears in the grammer, then ID becomes a fallback token for X, Y,
5167 @@ -359,10 +343,10 @@
5168  #endif /* NDEBUG */
5169  
5170  #ifndef NDEBUG
5171 -/* 
5172 +/*
5173  ** Turn parser tracing on by giving a stream to which to write the trace
5174  ** and a prompt to preface each trace message.  Tracing is turned off
5175 -** by making either argument NULL 
5176 +** by making either argument NULL
5177  **
5178  ** Inputs:
5179  ** <ul>
5180 @@ -387,7 +371,7 @@
5181  #ifndef NDEBUG
5182  /* For tracing shifts, the names of all terminals and nonterminals
5183  ** are required.  The following table supplies these names */
5184 -static const char *yyTokenName[] = { 
5185 +static const char *yyTokenName[] = {
5186    "$",             "EOL",           "ASSIGN",        "APPEND",      
5187    "LKEY",          "PLUS",          "STRING",        "INTEGER",     
5188    "LPARAN",        "RPARAN",        "COMMA",         "ARRAY_ASSIGN",
5189 @@ -425,27 +409,28 @@
5190   /*  15 */ "value ::= STRING",
5191   /*  16 */ "value ::= INTEGER",
5192   /*  17 */ "value ::= array",
5193 - /*  18 */ "array ::= LPARAN aelements RPARAN",
5194 - /*  19 */ "aelements ::= aelements COMMA aelement",
5195 - /*  20 */ "aelements ::= aelements COMMA",
5196 - /*  21 */ "aelements ::= aelement",
5197 - /*  22 */ "aelement ::= expression",
5198 - /*  23 */ "aelement ::= stringop ARRAY_ASSIGN expression",
5199 - /*  24 */ "eols ::= EOL",
5200 - /*  25 */ "eols ::=",
5201 - /*  26 */ "globalstart ::= GLOBAL",
5202 - /*  27 */ "global ::= globalstart LCURLY metalines RCURLY",
5203 - /*  28 */ "condlines ::= condlines eols ELSE condline",
5204 - /*  29 */ "condlines ::= condline",
5205 - /*  30 */ "condline ::= context LCURLY metalines RCURLY",
5206 - /*  31 */ "context ::= DOLLAR SRVVARNAME LBRACKET stringop RBRACKET cond expression",
5207 - /*  32 */ "cond ::= EQ",
5208 - /*  33 */ "cond ::= MATCH",
5209 - /*  34 */ "cond ::= NE",
5210 - /*  35 */ "cond ::= NOMATCH",
5211 - /*  36 */ "stringop ::= expression",
5212 - /*  37 */ "include ::= INCLUDE stringop",
5213 - /*  38 */ "include_shell ::= INCLUDE_SHELL stringop",
5214 + /*  18 */ "array ::= LPARAN RPARAN",
5215 + /*  19 */ "array ::= LPARAN aelements RPARAN",
5216 + /*  20 */ "aelements ::= aelements COMMA aelement",
5217 + /*  21 */ "aelements ::= aelements COMMA",
5218 + /*  22 */ "aelements ::= aelement",
5219 + /*  23 */ "aelement ::= expression",
5220 + /*  24 */ "aelement ::= stringop ARRAY_ASSIGN expression",
5221 + /*  25 */ "eols ::= EOL",
5222 + /*  26 */ "eols ::=",
5223 + /*  27 */ "globalstart ::= GLOBAL",
5224 + /*  28 */ "global ::= globalstart LCURLY metalines RCURLY",
5225 + /*  29 */ "condlines ::= condlines eols ELSE condline",
5226 + /*  30 */ "condlines ::= condline",
5227 + /*  31 */ "condline ::= context LCURLY metalines RCURLY",
5228 + /*  32 */ "context ::= DOLLAR SRVVARNAME LBRACKET stringop RBRACKET cond expression",
5229 + /*  33 */ "cond ::= EQ",
5230 + /*  34 */ "cond ::= MATCH",
5231 + /*  35 */ "cond ::= NE",
5232 + /*  36 */ "cond ::= NOMATCH",
5233 + /*  37 */ "stringop ::= expression",
5234 + /*  38 */ "include ::= INCLUDE stringop",
5235 + /*  39 */ "include_shell ::= INCLUDE_SHELL stringop",
5236  };
5237  #endif /* NDEBUG */
5238  
5239 @@ -465,7 +450,7 @@
5240  #endif
5241  }
5242  
5243 -/* 
5244 +/*
5245  ** This function allocates a new parser.
5246  ** The only argument is a pointer to a function which works like
5247  ** malloc.
5248 @@ -496,7 +481,7 @@
5249      /* Here is inserted the actions which take place when a
5250      ** terminal or non-terminal is destroyed.  This can happen
5251      ** when the symbol is popped from the stack during a
5252 -    ** reduce or during error processing or when a parser is 
5253 +    ** reduce or during error processing or when a parser is
5254      ** being destroyed before it is finished parsing.
5255      **
5256      ** Note: during a reduce, the only symbols destroyed are those
5257 @@ -528,44 +513,44 @@
5258      case 23:
5259      case 24:
5260      case 25:
5261 -#line 160 "./configparser.y"
5262 +#line 143 "./configparser.y"
5263  { buffer_free((yypminor->yy0)); }
5264 -#line 533 "configparser.c"
5265 +#line 518 "configparser.c"
5266        break;
5267      case 35:
5268 -#line 151 "./configparser.y"
5269 +#line 134 "./configparser.y"
5270  { (yypminor->yy41)->free((yypminor->yy41)); }
5271 -#line 538 "configparser.c"
5272 +#line 523 "configparser.c"
5273        break;
5274      case 36:
5275 -#line 152 "./configparser.y"
5276 +#line 135 "./configparser.y"
5277  { (yypminor->yy41)->free((yypminor->yy41)); }
5278 -#line 543 "configparser.c"
5279 +#line 528 "configparser.c"
5280        break;
5281      case 37:
5282 -#line 153 "./configparser.y"
5283 +#line 136 "./configparser.y"
5284  { (yypminor->yy41)->free((yypminor->yy41)); }
5285 -#line 548 "configparser.c"
5286 +#line 533 "configparser.c"
5287        break;
5288      case 39:
5289 -#line 154 "./configparser.y"
5290 +#line 137 "./configparser.y"
5291  { array_free((yypminor->yy40)); }
5292 -#line 553 "configparser.c"
5293 +#line 538 "configparser.c"
5294        break;
5295      case 40:
5296 -#line 155 "./configparser.y"
5297 +#line 138 "./configparser.y"
5298  { array_free((yypminor->yy40)); }
5299 -#line 558 "configparser.c"
5300 +#line 543 "configparser.c"
5301        break;
5302      case 41:
5303 -#line 156 "./configparser.y"
5304 +#line 139 "./configparser.y"
5305  { buffer_free((yypminor->yy43)); }
5306 -#line 563 "configparser.c"
5307 +#line 548 "configparser.c"
5308        break;
5309      case 42:
5310 -#line 157 "./configparser.y"
5311 +#line 140 "./configparser.y"
5312  { buffer_free((yypminor->yy43)); }
5313 -#line 568 "configparser.c"
5314 +#line 553 "configparser.c"
5315        break;
5316      default:  break;   /* If no destructor action specified: do nothing */
5317    }
5318 @@ -597,7 +582,7 @@
5319    return yymajor;
5320  }
5321  
5322 -/* 
5323 +/*
5324  ** Deallocate and destroy a parser.  Destructors are all called for
5325  ** all stack elements before shutting the parser down.
5326  **
5327 @@ -633,7 +618,7 @@
5328  ){
5329    int i;
5330    int stateno = pParser->yystack[pParser->yyidx].stateno;
5331
5332 +
5333    /* if( pParser->yyidx<0 ) return YY_NO_ACTION;  */
5334    i = yy_shift_ofst[stateno];
5335    if( i==YY_SHIFT_USE_DFLT ){
5336 @@ -677,7 +662,7 @@
5337  ){
5338    int i;
5339    int stateno = pParser->yystack[pParser->yyidx].stateno;
5340
5341 +
5342    i = yy_reduce_ofst[stateno];
5343    if( i==YY_REDUCE_USE_DFLT ){
5344      return yy_default[stateno];
5345 @@ -759,6 +744,7 @@
5346    { 35, 1 },
5347    { 35, 1 },
5348    { 35, 1 },
5349 +  { 40, 2 },
5350    { 40, 3 },
5351    { 39, 3 },
5352    { 39, 2 },
5353 @@ -800,7 +786,7 @@
5354    configparserARG_FETCH;
5355    yymsp = &yypParser->yystack[yypParser->yyidx];
5356  #ifndef NDEBUG
5357 -  if( yyTraceFILE && yyruleno>=0 
5358 +  if( yyTraceFILE && yyruleno>=0
5359          && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
5360      fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
5361        yyRuleName[yyruleno]);
5362 @@ -832,9 +818,9 @@
5363          /* No destructor defined for global */
5364          break;
5365        case 5:
5366 -#line 134 "./configparser.y"
5367 +#line 116 "./configparser.y"
5368  { yymsp[-1].minor.yy78 = NULL; }
5369 -#line 837 "configparser.c"
5370 +#line 823 "configparser.c"
5371    yy_destructor(1,&yymsp[0].minor);
5372          break;
5373        case 6:
5374 @@ -847,10 +833,15 @@
5375    yy_destructor(1,&yymsp[0].minor);
5376          break;
5377        case 9:
5378 -#line 162 "./configparser.y"
5379 +#line 145 "./configparser.y"
5380  {
5381    buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5382 -  if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) {
5383 +  if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5384 +    fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
5385 +        ctx->current->context_ndx,
5386 +        ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5387 +    ctx->ok = 0;
5388 +  } else if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) {
5389      array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
5390      yymsp[0].minor.yy41 = NULL;
5391    } else {
5392 @@ -864,16 +855,21 @@
5393    buffer_free(yymsp[-2].minor.yy43);
5394    yymsp[-2].minor.yy43 = NULL;
5395  }
5396 -#line 867 "configparser.c"
5397 +#line 858 "configparser.c"
5398    yy_destructor(2,&yymsp[-1].minor);
5399          break;
5400        case 10:
5401 -#line 179 "./configparser.y"
5402 +#line 167 "./configparser.y"
5403  {
5404    array *vars = ctx->current->value;
5405    data_unset *du;
5406  
5407 -  if (NULL != (du = array_get_element(vars, yymsp[-2].minor.yy43->ptr))) {
5408 +  if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5409 +    fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
5410 +        ctx->current->context_ndx,
5411 +        ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5412 +    ctx->ok = 0;
5413 +  } else if (NULL != (du = array_get_element(vars, yymsp[-2].minor.yy43->ptr))) {
5414      /* exists in current block */
5415      du = configparser_merge_data(du, yymsp[0].minor.yy41);
5416      if (NULL == du) {
5417 @@ -883,6 +879,7 @@
5418        buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
5419        array_replace(vars, du);
5420      }
5421 +    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5422    } else if (NULL != (du = configparser_get_variable(ctx, yymsp[-2].minor.yy43))) {
5423      du = configparser_merge_data(du, yymsp[0].minor.yy41);
5424      if (NULL == du) {
5425 @@ -892,22 +889,20 @@
5426        buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
5427        array_insert_unique(ctx->current->value, du);
5428      }
5429 +    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5430    } else {
5431 -    fprintf(stderr, "Undefined config variable in conditional %d %s: %s\n", 
5432 -            ctx->current->context_ndx,
5433 -            ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5434 -    ctx->ok = 0;
5435 +    buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5436 +    array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
5437    }
5438    buffer_free(yymsp[-2].minor.yy43);
5439    yymsp[-2].minor.yy43 = NULL;
5440 -  yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5441    yymsp[0].minor.yy41 = NULL;
5442  }
5443 -#line 906 "configparser.c"
5444 +#line 901 "configparser.c"
5445    yy_destructor(3,&yymsp[-1].minor);
5446          break;
5447        case 11:
5448 -#line 214 "./configparser.y"
5449 +#line 206 "./configparser.y"
5450  {
5451    if (strchr(yymsp[0].minor.yy0->ptr, '.') == NULL) {
5452      yygotominor.yy43 = buffer_init_string("var.");
5453 @@ -919,10 +914,10 @@
5454      yymsp[0].minor.yy0 = NULL;
5455    }
5456  }
5457 -#line 922 "configparser.c"
5458 +#line 917 "configparser.c"
5459          break;
5460        case 12:
5461 -#line 226 "./configparser.y"
5462 +#line 218 "./configparser.y"
5463  {
5464    yygotominor.yy41 = configparser_merge_data(yymsp[-2].minor.yy41, yymsp[0].minor.yy41);
5465    if (NULL == yygotominor.yy41) {
5466 @@ -932,21 +927,38 @@
5467    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5468    yymsp[0].minor.yy41 = NULL;
5469  }
5470 -#line 935 "configparser.c"
5471 +#line 930 "configparser.c"
5472    yy_destructor(5,&yymsp[-1].minor);
5473          break;
5474        case 13:
5475 -#line 236 "./configparser.y"
5476 +#line 228 "./configparser.y"
5477  {
5478    yygotominor.yy41 = yymsp[0].minor.yy41;
5479    yymsp[0].minor.yy41 = NULL;
5480  }
5481 -#line 944 "configparser.c"
5482 +#line 939 "configparser.c"
5483          break;
5484        case 14:
5485 -#line 241 "./configparser.y"
5486 +#line 233 "./configparser.y"
5487  {
5488 -  yygotominor.yy41 = configparser_get_variable(ctx, yymsp[0].minor.yy43);
5489 +  if (strncmp(yymsp[0].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5490 +    char *env;
5491 +
5492 +    if (NULL != (env = getenv(yymsp[0].minor.yy43->ptr + 4))) {
5493 +      data_string *ds;
5494 +      ds = data_string_init();
5495 +      buffer_append_string(ds->value, env);
5496 +      yygotominor.yy41 = (data_unset *)ds;
5497 +    }
5498 +    else {
5499 +      yygotominor.yy41 = NULL;
5500 +      fprintf(stderr, "Undefined env variable: %s\n", yymsp[0].minor.yy43->ptr + 4);
5501 +      ctx->ok = 0;
5502 +    }
5503 +  } else if (NULL == (yygotominor.yy41 = configparser_get_variable(ctx, yymsp[0].minor.yy43))) {
5504 +    fprintf(stderr, "Undefined config variable: %s\n", yymsp[0].minor.yy43->ptr);
5505 +    ctx->ok = 0;
5506 +  }
5507    if (!yygotominor.yy41) {
5508      /* make a dummy so it won't crash */
5509      yygotominor.yy41 = (data_unset *)data_string_init();
5510 @@ -954,50 +966,59 @@
5511    buffer_free(yymsp[0].minor.yy43);
5512    yymsp[0].minor.yy43 = NULL;
5513  }
5514 -#line 957 "configparser.c"
5515 +#line 969 "configparser.c"
5516          break;
5517        case 15:
5518 -#line 251 "./configparser.y"
5519 +#line 260 "./configparser.y"
5520  {
5521    yygotominor.yy41 = (data_unset *)data_string_init();
5522    buffer_copy_string_buffer(((data_string *)(yygotominor.yy41))->value, yymsp[0].minor.yy0);
5523    buffer_free(yymsp[0].minor.yy0);
5524    yymsp[0].minor.yy0 = NULL;
5525  }
5526 -#line 967 "configparser.c"
5527 +#line 979 "configparser.c"
5528          break;
5529        case 16:
5530 -#line 258 "./configparser.y"
5531 +#line 267 "./configparser.y"
5532  {
5533    yygotominor.yy41 = (data_unset *)data_integer_init();
5534    ((data_integer *)(yygotominor.yy41))->value = strtol(yymsp[0].minor.yy0->ptr, NULL, 10);
5535    buffer_free(yymsp[0].minor.yy0);
5536    yymsp[0].minor.yy0 = NULL;
5537  }
5538 -#line 977 "configparser.c"
5539 +#line 989 "configparser.c"
5540          break;
5541        case 17:
5542 -#line 264 "./configparser.y"
5543 +#line 273 "./configparser.y"
5544  {
5545    yygotominor.yy41 = (data_unset *)data_array_init();
5546    array_free(((data_array *)(yygotominor.yy41))->value);
5547    ((data_array *)(yygotominor.yy41))->value = yymsp[0].minor.yy40;
5548    yymsp[0].minor.yy40 = NULL;
5549  }
5550 -#line 987 "configparser.c"
5551 +#line 999 "configparser.c"
5552          break;
5553        case 18:
5554 -#line 270 "./configparser.y"
5555 +#line 279 "./configparser.y"
5556 +{
5557 +  yygotominor.yy40 = array_init();
5558 +}
5559 +#line 1006 "configparser.c"
5560 +  yy_destructor(8,&yymsp[-1].minor);
5561 +  yy_destructor(9,&yymsp[0].minor);
5562 +        break;
5563 +      case 19:
5564 +#line 282 "./configparser.y"
5565  {
5566    yygotominor.yy40 = yymsp[-1].minor.yy40;
5567    yymsp[-1].minor.yy40 = NULL;
5568  }
5569 -#line 995 "configparser.c"
5570 +#line 1016 "configparser.c"
5571    yy_destructor(8,&yymsp[-2].minor);
5572    yy_destructor(9,&yymsp[0].minor);
5573          break;
5574 -      case 19:
5575 -#line 275 "./configparser.y"
5576 +      case 20:
5577 +#line 287 "./configparser.y"
5578  {
5579    if (buffer_is_empty(yymsp[0].minor.yy41->key) ||
5580        NULL == array_get_element(yymsp[-2].minor.yy40, yymsp[0].minor.yy41->key->ptr)) {
5581 @@ -1014,37 +1035,37 @@
5582    yygotominor.yy40 = yymsp[-2].minor.yy40;
5583    yymsp[-2].minor.yy40 = NULL;
5584  }
5585 -#line 1017 "configparser.c"
5586 +#line 1038 "configparser.c"
5587    yy_destructor(10,&yymsp[-1].minor);
5588          break;
5589 -      case 20:
5590 -#line 292 "./configparser.y"
5591 +      case 21:
5592 +#line 304 "./configparser.y"
5593  {
5594    yygotominor.yy40 = yymsp[-1].minor.yy40;
5595    yymsp[-1].minor.yy40 = NULL;
5596  }
5597 -#line 1026 "configparser.c"
5598 +#line 1047 "configparser.c"
5599    yy_destructor(10,&yymsp[0].minor);
5600          break;
5601 -      case 21:
5602 -#line 297 "./configparser.y"
5603 +      case 22:
5604 +#line 309 "./configparser.y"
5605  {
5606    yygotominor.yy40 = array_init();
5607    array_insert_unique(yygotominor.yy40, yymsp[0].minor.yy41);
5608    yymsp[0].minor.yy41 = NULL;
5609  }
5610 -#line 1036 "configparser.c"
5611 +#line 1057 "configparser.c"
5612          break;
5613 -      case 22:
5614 -#line 303 "./configparser.y"
5615 +      case 23:
5616 +#line 315 "./configparser.y"
5617  {
5618    yygotominor.yy41 = yymsp[0].minor.yy41;
5619    yymsp[0].minor.yy41 = NULL;
5620  }
5621 -#line 1044 "configparser.c"
5622 +#line 1065 "configparser.c"
5623          break;
5624 -      case 23:
5625 -#line 307 "./configparser.y"
5626 +      case 24:
5627 +#line 319 "./configparser.y"
5628  {
5629    buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5630    buffer_free(yymsp[-2].minor.yy43);
5631 @@ -1053,27 +1074,27 @@
5632    yygotominor.yy41 = yymsp[0].minor.yy41;
5633    yymsp[0].minor.yy41 = NULL;
5634  }
5635 -#line 1056 "configparser.c"
5636 +#line 1077 "configparser.c"
5637    yy_destructor(11,&yymsp[-1].minor);
5638          break;
5639 -      case 24:
5640 -  yy_destructor(1,&yymsp[0].minor);
5641 -        break;
5642        case 25:
5643 +  yy_destructor(1,&yymsp[0].minor);
5644          break;
5645        case 26:
5646 -#line 319 "./configparser.y"
5647 +        break;
5648 +      case 27:
5649 +#line 331 "./configparser.y"
5650  {
5651    data_config *dc;
5652    dc = (data_config *)array_get_element(ctx->srv->config_context, "global");
5653    assert(dc);
5654    configparser_push(ctx, dc, 0);
5655  }
5656 -#line 1072 "configparser.c"
5657 +#line 1093 "configparser.c"
5658    yy_destructor(12,&yymsp[0].minor);
5659          break;
5660 -      case 27:
5661 -#line 326 "./configparser.y"
5662 +      case 28:
5663 +#line 338 "./configparser.y"
5664  {
5665    data_config *cur;
5666    
5667 @@ -1082,16 +1103,16 @@
5668  
5669    assert(cur && ctx->current);
5670  
5671 -  yygotominor.yy0 = cur;
5672 +  yygotominor.yy78 = cur;
5673  }
5674 -#line 1087 "configparser.c"
5675 +#line 1108 "configparser.c"
5676          /* No destructor defined for globalstart */
5677    yy_destructor(13,&yymsp[-2].minor);
5678          /* No destructor defined for metalines */
5679    yy_destructor(14,&yymsp[0].minor);
5680          break;
5681 -      case 28:
5682 -#line 337 "./configparser.y"
5683 +      case 29:
5684 +#line 349 "./configparser.y"
5685  {
5686    assert(yymsp[-3].minor.yy78->context_ndx < yymsp[0].minor.yy78->context_ndx);
5687    yymsp[0].minor.yy78->prev = yymsp[-3].minor.yy78;
5688 @@ -1100,20 +1121,20 @@
5689    yymsp[-3].minor.yy78 = NULL;
5690    yymsp[0].minor.yy78 = NULL;
5691  }
5692 -#line 1103 "configparser.c"
5693 +#line 1124 "configparser.c"
5694          /* No destructor defined for eols */
5695    yy_destructor(15,&yymsp[-1].minor);
5696          break;
5697 -      case 29:
5698 -#line 346 "./configparser.y"
5699 +      case 30:
5700 +#line 358 "./configparser.y"
5701  {
5702    yygotominor.yy78 = yymsp[0].minor.yy78;
5703    yymsp[0].minor.yy78 = NULL;
5704  }
5705 -#line 1113 "configparser.c"
5706 +#line 1134 "configparser.c"
5707          break;
5708 -      case 30:
5709 -#line 351 "./configparser.y"
5710 +      case 31:
5711 +#line 363 "./configparser.y"
5712  {
5713    data_config *cur;
5714    
5715 @@ -1124,14 +1145,14 @@
5716  
5717    yygotominor.yy78 = cur;
5718  }
5719 -#line 1127 "configparser.c"
5720 +#line 1148 "configparser.c"
5721          /* No destructor defined for context */
5722    yy_destructor(13,&yymsp[-2].minor);
5723          /* No destructor defined for metalines */
5724    yy_destructor(14,&yymsp[0].minor);
5725          break;
5726 -      case 31:
5727 -#line 362 "./configparser.y"
5728 +      case 32:
5729 +#line 374 "./configparser.y"
5730  {
5731    data_config *dc;
5732    buffer *b, *rvalue, *op;
5733 @@ -1266,45 +1287,45 @@
5734    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5735    yymsp[0].minor.yy41 = NULL;
5736  }
5737 -#line 1269 "configparser.c"
5738 +#line 1290 "configparser.c"
5739    yy_destructor(16,&yymsp[-6].minor);
5740    yy_destructor(18,&yymsp[-4].minor);
5741    yy_destructor(19,&yymsp[-2].minor);
5742          break;
5743 -      case 32:
5744 -#line 496 "./configparser.y"
5745 +      case 33:
5746 +#line 508 "./configparser.y"
5747  {
5748    yygotominor.yy27 = CONFIG_COND_EQ;
5749  }
5750 -#line 1279 "configparser.c"
5751 +#line 1300 "configparser.c"
5752    yy_destructor(20,&yymsp[0].minor);
5753          break;
5754 -      case 33:
5755 -#line 499 "./configparser.y"
5756 +      case 34:
5757 +#line 511 "./configparser.y"
5758  {
5759    yygotominor.yy27 = CONFIG_COND_MATCH;
5760  }
5761 -#line 1287 "configparser.c"
5762 +#line 1308 "configparser.c"
5763    yy_destructor(21,&yymsp[0].minor);
5764          break;
5765 -      case 34:
5766 -#line 502 "./configparser.y"
5767 +      case 35:
5768 +#line 514 "./configparser.y"
5769  {
5770    yygotominor.yy27 = CONFIG_COND_NE;
5771  }
5772 -#line 1295 "configparser.c"
5773 +#line 1316 "configparser.c"
5774    yy_destructor(22,&yymsp[0].minor);
5775          break;
5776 -      case 35:
5777 -#line 505 "./configparser.y"
5778 +      case 36:
5779 +#line 517 "./configparser.y"
5780  {
5781    yygotominor.yy27 = CONFIG_COND_NOMATCH;
5782  }
5783 -#line 1303 "configparser.c"
5784 +#line 1324 "configparser.c"
5785    yy_destructor(23,&yymsp[0].minor);
5786          break;
5787 -      case 36:
5788 -#line 509 "./configparser.y"
5789 +      case 37:
5790 +#line 521 "./configparser.y"
5791  {
5792    yygotominor.yy43 = NULL;
5793    if (ctx->ok) {
5794 @@ -1321,10 +1342,10 @@
5795    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5796    yymsp[0].minor.yy41 = NULL;
5797  }
5798 -#line 1324 "configparser.c"
5799 +#line 1345 "configparser.c"
5800          break;
5801 -      case 37:
5802 -#line 526 "./configparser.y"
5803 +      case 38:
5804 +#line 538 "./configparser.y"
5805  {
5806    if (ctx->ok) {
5807      if (0 != config_parse_file(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
5808 @@ -1334,11 +1355,11 @@
5809      yymsp[0].minor.yy43 = NULL;
5810    }
5811  }
5812 -#line 1337 "configparser.c"
5813 +#line 1358 "configparser.c"
5814    yy_destructor(24,&yymsp[-1].minor);
5815          break;
5816 -      case 38:
5817 -#line 536 "./configparser.y"
5818 +      case 39:
5819 +#line 548 "./configparser.y"
5820  {
5821    if (ctx->ok) {
5822      if (0 != config_parse_cmd(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
5823 @@ -1348,7 +1369,7 @@
5824      yymsp[0].minor.yy43 = NULL;
5825    }
5826  }
5827 -#line 1351 "configparser.c"
5828 +#line 1372 "configparser.c"
5829    yy_destructor(25,&yymsp[-1].minor);
5830          break;
5831    };
5832 @@ -1378,11 +1399,11 @@
5833    while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
5834    /* Here code is inserted which will be executed whenever the
5835    ** parser fails */
5836 -#line 125 "./configparser.y"
5837 +#line 107 "./configparser.y"
5838  
5839    ctx->ok = 0;
5840  
5841 -#line 1385 "configparser.c"
5842 +#line 1406 "configparser.c"
5843    configparserARG_STORE; /* Suppress warning about unused %extra_argument variable */
5844  }
5845  
5846 @@ -1489,7 +1510,7 @@
5847  #ifdef YYERRORSYMBOL
5848        /* A syntax error has occurred.
5849        ** The response to an error depends upon whether or not the
5850 -      ** grammar defines an error token "ERROR".  
5851 +      ** grammar defines an error token "ERROR".
5852        **
5853        ** This is what we do if the grammar does define ERROR:
5854        **
5855 --- ../lighttpd-1.4.11/src/configparser.y       2006-01-26 18:46:25.000000000 +0200
5856 +++ lighttpd-1.4.12/src/configparser.y  2006-07-16 00:26:04.000000000 +0300
5857 @@ -21,52 +21,34 @@
5858      dc->parent = ctx->current;
5859      array_insert_unique(dc->parent->childs, (data_unset *)dc);
5860    }
5861 -  array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
5862 +  buffer_ptr_append(ctx->configs_stack, (void *)ctx->current);
5863    ctx->current = dc;
5864  }
5865  
5866  static data_config *configparser_pop(config_t *ctx) {
5867    data_config *old = ctx->current;
5868 -  ctx->current = (data_config *) array_pop(ctx->configs_stack);
5869 +  ctx->current = (data_config *) buffer_ptr_pop(ctx->configs_stack);
5870    return old;
5871  }
5872  
5873  /* return a copied variable */
5874  static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
5875 -  if (strncmp(key->ptr, "env.", sizeof("env.") - 1) == 0) {
5876 -    char *env;
5877 -
5878 -    if (NULL != (env = getenv(key->ptr + 4))) {
5879 -      data_string *ds;
5880 -      ds = data_string_init();
5881 -      buffer_append_string(ds->value, env);
5882 -      return (data_unset *)ds;
5883 -    }
5884 -
5885 -    fprintf(stderr, "Undefined env variable: %s\n", key->ptr + 4);
5886 -    ctx->ok = 0;
5887 -
5888 -    return NULL;
5889 -  } else {
5890 -    data_unset *du;
5891 -    data_config *dc;
5892 +  data_unset *du;
5893 +  data_config *dc;
5894  
5895  #if 0
5896 -    fprintf(stderr, "get var %s\n", key->ptr);
5897 +  fprintf(stderr, "get var %s\n", key->ptr);
5898  #endif
5899 -    for (dc = ctx->current; dc; dc = dc->parent) {
5900 +  for (dc = ctx->current; dc; dc = dc->parent) {
5901  #if 0
5902 -      fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
5903 -      array_print(dc->value, 0);
5904 +    fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
5905 +    array_print(dc->value, 0);
5906  #endif
5907 -      if (NULL != (du = array_get_element(dc->value, key->ptr))) {
5908 -        return du->copy(du);
5909 -      }
5910 +    if (NULL != (du = array_get_element(dc->value, key->ptr))) {
5911 +      return du->copy(du);
5912      }
5913 -    fprintf(stderr, "Undefined config variable: %s\n", key->ptr);
5914 -    ctx->ok = 0;
5915 -    return NULL;
5916    }
5917 +  return NULL;
5918  }
5919  
5920  /* op1 is to be eat/return by this function, op1->key is not cared
5921 @@ -141,6 +123,7 @@
5922  %type       aelement               {data_unset *}
5923  %type       condline               {data_config *}
5924  %type       condlines              {data_config *}
5925 +%type       global                 {data_config *}
5926  %type       aelements              {array *}
5927  %type       array                  {array *}
5928  %type       key                    {buffer *}
5929 @@ -161,7 +144,12 @@
5930  
5931  varline ::= key(A) ASSIGN expression(B). {
5932    buffer_copy_string_buffer(B->key, A);
5933 -  if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
5934 +  if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
5935 +    fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
5936 +        ctx->current->context_ndx,
5937 +        ctx->current->key->ptr, A->ptr);
5938 +    ctx->ok = 0;
5939 +  } else if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
5940      array_insert_unique(ctx->current->value, B);
5941      B = NULL;
5942    } else {
5943 @@ -180,7 +168,12 @@
5944    array *vars = ctx->current->value;
5945    data_unset *du;
5946  
5947 -  if (NULL != (du = array_get_element(vars, A->ptr))) {
5948 +  if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
5949 +    fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
5950 +        ctx->current->context_ndx,
5951 +        ctx->current->key->ptr, A->ptr);
5952 +    ctx->ok = 0;
5953 +  } else if (NULL != (du = array_get_element(vars, A->ptr))) {
5954      /* exists in current block */
5955      du = configparser_merge_data(du, B);
5956      if (NULL == du) {
5957 @@ -190,6 +183,7 @@
5958        buffer_copy_string_buffer(du->key, A);
5959        array_replace(vars, du);
5960      }
5961 +    B->free(B);
5962    } else if (NULL != (du = configparser_get_variable(ctx, A))) {
5963      du = configparser_merge_data(du, B);
5964      if (NULL == du) {
5965 @@ -199,15 +193,13 @@
5966        buffer_copy_string_buffer(du->key, A);
5967        array_insert_unique(ctx->current->value, du);
5968      }
5969 +    B->free(B);
5970    } else {
5971 -    fprintf(stderr, "Undefined config variable in conditional %d %s: %s\n", 
5972 -            ctx->current->context_ndx,
5973 -            ctx->current->key->ptr, A->ptr);
5974 -    ctx->ok = 0;
5975 +    buffer_copy_string_buffer(B->key, A);
5976 +    array_insert_unique(ctx->current->value, B);
5977    }
5978    buffer_free(A);
5979    A = NULL;
5980 -  B->free(B);
5981    B = NULL;
5982  }
5983  
5984 @@ -239,7 +231,24 @@
5985  }
5986  
5987  value(A) ::= key(B). {
5988 -  A = configparser_get_variable(ctx, B);
5989 +  if (strncmp(B->ptr, "env.", sizeof("env.") - 1) == 0) {
5990 +    char *env;
5991 +
5992 +    if (NULL != (env = getenv(B->ptr + 4))) {
5993 +      data_string *ds;
5994 +      ds = data_string_init();
5995 +      buffer_append_string(ds->value, env);
5996 +      A = (data_unset *)ds;
5997 +    }
5998 +    else {
5999 +      A = NULL;
6000 +      fprintf(stderr, "Undefined env variable: %s\n", B->ptr + 4);
6001 +      ctx->ok = 0;
6002 +    }
6003 +  } else if (NULL == (A = configparser_get_variable(ctx, B))) {
6004 +    fprintf(stderr, "Undefined config variable: %s\n", B->ptr);
6005 +    ctx->ok = 0;
6006 +  }
6007    if (!A) {
6008      /* make a dummy so it won't crash */
6009      A = (data_unset *)data_string_init();
6010 @@ -267,6 +276,9 @@
6011    ((data_array *)(A))->value = B;
6012    B = NULL;
6013  }
6014 +array(A) ::= LPARAN RPARAN. {
6015 +  A = array_init();
6016 +}
6017  array(A) ::= LPARAN aelements(B) RPARAN. {
6018    A = B;
6019    B = NULL;
6020 --- ../lighttpd-1.4.11/src/connections-glue.c   2005-09-12 10:04:23.000000000 +0300
6021 +++ lighttpd-1.4.12/src/connections-glue.c      2006-07-16 00:26:03.000000000 +0300
6022 @@ -13,7 +13,7 @@
6023         case CON_STATE_REQUEST_END: return "req-end";
6024         case CON_STATE_RESPONSE_START: return "resp-start";
6025         case CON_STATE_RESPONSE_END: return "resp-end";
6026 -       default: return "(unknown)";    
6027 +       default: return "(unknown)";
6028         }
6029  }
6030  
6031 @@ -30,15 +30,15 @@
6032         case CON_STATE_REQUEST_END: return "Q";
6033         case CON_STATE_RESPONSE_START: return "s";
6034         case CON_STATE_RESPONSE_END: return "S";
6035 -       default: return "x";    
6036 +       default: return "x";
6037         }
6038  }
6039  
6040  int connection_set_state(server *srv, connection *con, connection_state_t state) {
6041         UNUSED(srv);
6042 -       
6043 +
6044         con->state = state;
6045 -       
6046 +
6047         return 0;
6048  }
6049  
6050 --- ../lighttpd-1.4.11/src/connections.c        2006-03-05 22:14:53.000000000 +0200
6051 +++ lighttpd-1.4.12/src/connections.c   2006-07-18 13:03:40.000000000 +0300
6052 @@ -2,7 +2,6 @@
6053  
6054  #include <stdlib.h>
6055  #include <stdio.h>
6056 -#include <unistd.h>
6057  #include <errno.h>
6058  #include <string.h>
6059  #include <fcntl.h>
6060 @@ -26,8 +25,8 @@
6061  #include "inet_ntop_cache.h"
6062  
6063  #ifdef USE_OPENSSL
6064 -# include <openssl/ssl.h> 
6065 -# include <openssl/err.h> 
6066 +# include <openssl/ssl.h>
6067 +# include <openssl/err.h>
6068  #endif
6069  
6070  #ifdef HAVE_SYS_FILIO_H
6071 @@ -35,15 +34,16 @@
6072  #endif
6073  
6074  #include "sys-socket.h"
6075 +#include "sys-files.h"
6076  
6077  typedef struct {
6078 -               PLUGIN_DATA;
6079 +       PLUGIN_DATA;
6080  } plugin_data;
6081  
6082  static connection *connections_get_new_connection(server *srv) {
6083         connections *conns = srv->conns;
6084         size_t i;
6085 -       
6086 +
6087         if (conns->size == 0) {
6088                 conns->size = 128;
6089                 conns->ptr = NULL;
6090 @@ -54,21 +54,14 @@
6091         } else if (conns->size == conns->used) {
6092                 conns->size += 128;
6093                 conns->ptr = realloc(conns->ptr, sizeof(*conns->ptr) * conns->size);
6094 -               
6095 +
6096                 for (i = conns->used; i < conns->size; i++) {
6097                         conns->ptr[i] = connection_init(srv);
6098                 }
6099         }
6100  
6101         connection_reset(srv, conns->ptr[conns->used]);
6102 -#if 0  
6103 -       fprintf(stderr, "%s.%d: add: ", __FILE__, __LINE__);
6104 -       for (i = 0; i < conns->used + 1; i++) {
6105 -               fprintf(stderr, "%d ", conns->ptr[i]->fd);
6106 -       }
6107 -       fprintf(stderr, "\n");
6108 -#endif 
6109 -       
6110 +
6111         conns->ptr[conns->used]->ndx = conns->used;
6112         return conns->ptr[conns->used++];
6113  }
6114 @@ -77,263 +70,134 @@
6115         size_t i;
6116         connections *conns = srv->conns;
6117         connection *temp;
6118 -       
6119 +
6120         if (con == NULL) return -1;
6121 -       
6122 +
6123         if (-1 == con->ndx) return -1;
6124 -       
6125 +
6126         i = con->ndx;
6127 -       
6128 +
6129         /* not last element */
6130 -       
6131 +
6132         if (i != conns->used - 1) {
6133                 temp = conns->ptr[i];
6134                 conns->ptr[i] = conns->ptr[conns->used - 1];
6135                 conns->ptr[conns->used - 1] = temp;
6136 -               
6137 +
6138                 conns->ptr[i]->ndx = i;
6139                 conns->ptr[conns->used - 1]->ndx = -1;
6140         }
6141 -       
6142 +
6143         conns->used--;
6144 -       
6145 +
6146         con->ndx = -1;
6147 -#if 0
6148 -       fprintf(stderr, "%s.%d: del: (%d)", __FILE__, __LINE__, conns->used);
6149 -       for (i = 0; i < conns->used; i++) {
6150 -               fprintf(stderr, "%d ", conns->ptr[i]->fd);
6151 -       }
6152 -       fprintf(stderr, "\n");
6153 -#endif 
6154 +
6155         return 0;
6156  }
6157  
6158  int connection_close(server *srv, connection *con) {
6159  #ifdef USE_OPENSSL
6160         server_socket *srv_sock = con->srv_socket;
6161 -#endif
6162 -       
6163 -#ifdef USE_OPENSSL
6164 +
6165         if (srv_sock->is_ssl) {
6166 -               if (con->ssl) SSL_free(con->ssl);
6167 -               con->ssl = NULL;
6168 +               if (con->sock->ssl) SSL_free(con->sock->ssl);
6169 +               con->sock->ssl = NULL;
6170         }
6171  #endif
6172 -       
6173 -       fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
6174 -       fdevent_unregister(srv->ev, con->fd);
6175 -#ifdef __WIN32
6176 -       if (closesocket(con->fd)) {
6177 -               log_error_write(srv, __FILE__, __LINE__, "sds",
6178 -                               "(warning) close:", con->fd, strerror(errno));
6179 -       }
6180 -#else
6181 -       if (close(con->fd)) {
6182 +
6183 +       fdevent_event_del(srv->ev, con->sock);
6184 +       fdevent_unregister(srv->ev, con->sock);
6185 +
6186 +       if (closesocket(con->sock->fd)) {
6187                 log_error_write(srv, __FILE__, __LINE__, "sds",
6188 -                               "(warning) close:", con->fd, strerror(errno));
6189 +                               "(warning) close:", con->sock->fd, strerror(errno));
6190         }
6191 -#endif
6192 -       
6193 +
6194         srv->cur_fds--;
6195 -#if 0
6196 -       log_error_write(srv, __FILE__, __LINE__, "sd",
6197 -                       "closed()", con->fd);
6198 -#endif
6199 -       
6200 +
6201         connection_del(srv, con);
6202         connection_set_state(srv, con, CON_STATE_CONNECT);
6203 -       
6204 +
6205         return 0;
6206  }
6207  
6208  #if 0
6209  static void dump_packet(const unsigned char *data, size_t len) {
6210         size_t i, j;
6211 -       
6212 +
6213         if (len == 0) return;
6214 -       
6215 +
6216         for (i = 0; i < len; i++) {
6217                 if (i % 16 == 0) fprintf(stderr, "  ");
6218 -               
6219 +
6220                 fprintf(stderr, "%02x ", data[i]);
6221 -               
6222 +
6223                 if ((i + 1) % 16 == 0) {
6224                         fprintf(stderr, "  ");
6225                         for (j = 0; j <= i % 16; j++) {
6226                                 unsigned char c;
6227 -                               
6228 +
6229                                 if (i-15+j >= len) break;
6230 -                               
6231 +
6232                                 c = data[i-15+j];
6233 -                               
6234 +
6235                                 fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
6236                         }
6237 -                       
6238 +
6239                         fprintf(stderr, "\n");
6240                 }
6241         }
6242 -       
6243 +
6244         if (len % 16 != 0) {
6245                 for (j = i % 16; j < 16; j++) {
6246                         fprintf(stderr, "   ");
6247                 }
6248 -               
6249 +
6250                 fprintf(stderr, "  ");
6251                 for (j = i & ~0xf; j < len; j++) {
6252                         unsigned char c;
6253 -                       
6254 +
6255                         c = data[j];
6256                         fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
6257                 }
6258                 fprintf(stderr, "\n");
6259         }
6260  }
6261 -#endif 
6262 -
6263 -static int connection_handle_read(server *srv, connection *con) {
6264 -       int len;
6265 -       buffer *b;
6266 -       int toread;
6267 -#ifdef USE_OPENSSL
6268 -       server_socket *srv_sock = con->srv_socket;
6269  #endif
6270  
6271 -       b = chunkqueue_get_append_buffer(con->read_queue);
6272 -       buffer_prepare_copy(b, 4096);
6273 -
6274 -#ifdef USE_OPENSSL
6275 -       if (srv_sock->is_ssl) {
6276 -               len = SSL_read(con->ssl, b->ptr, b->size - 1);
6277 -       } else {
6278 -               if (ioctl(con->fd, FIONREAD, &toread)) {
6279 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
6280 -                                       "unexpected end-of-file:",
6281 -                                       con->fd);
6282 -                       return -1;
6283 -               }
6284 -               buffer_prepare_copy(b, toread);
6285 +static network_status_t connection_handle_read(server *srv, connection *con) {
6286 +       off_t oldlen, newlen;
6287  
6288 -               len = read(con->fd, b->ptr, b->size - 1);
6289 -       }
6290 -#elif defined(__WIN32)
6291 -       len = recv(con->fd, b->ptr, b->size - 1, 0);
6292 -#else
6293 -       if (ioctl(con->fd, FIONREAD, &toread)) {
6294 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
6295 -                               "unexpected end-of-file:",
6296 -                               con->fd);
6297 -               return -1;
6298 -       }
6299 -       buffer_prepare_copy(b, toread);
6300 +       oldlen = chunkqueue_length(con->read_queue);
6301  
6302 -       len = read(con->fd, b->ptr, b->size - 1);
6303 -#endif
6304 -       
6305 -       if (len < 0) {
6306 +       switch(network_read_chunkqueue(srv, con, con->read_queue)) {
6307 +       case NETWORK_STATUS_SUCCESS:
6308 +               break;
6309 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
6310 +               con->is_readable = 0;
6311 +               return NETWORK_STATUS_WAIT_FOR_EVENT;
6312 +       case NETWORK_STATUS_INTERRUPTED:
6313 +               con->is_readable = 1;
6314 +               return NETWORK_STATUS_WAIT_FOR_EVENT;
6315 +       case NETWORK_STATUS_CONNECTION_CLOSE:
6316 +               /* pipelining */
6317 +               con->is_readable = 0;
6318 +               return NETWORK_STATUS_CONNECTION_CLOSE;
6319 +       case NETWORK_STATUS_FATAL_ERROR:
6320                 con->is_readable = 0;
6321 -               
6322 -#ifdef USE_OPENSSL
6323 -               if (srv_sock->is_ssl) {
6324 -                       int r, ssl_err;
6325 -                       
6326 -                       switch ((r = SSL_get_error(con->ssl, len))) {
6327 -                       case SSL_ERROR_WANT_READ:
6328 -                               return 0;
6329 -                       case SSL_ERROR_SYSCALL:
6330 -                               /**
6331 -                                * man SSL_get_error()
6332 -                                * 
6333 -                                * SSL_ERROR_SYSCALL
6334 -                                *   Some I/O error occurred.  The OpenSSL error queue may contain more 
6335 -                                *   information on the error.  If the error queue is empty (i.e.
6336 -                                *   ERR_get_error() returns 0), ret can be used to find out more about 
6337 -                                *   the error: If ret == 0, an EOF was observed that violates the
6338 -                                *   protocol.  If ret == -1, the underlying BIO reported an I/O error 
6339 -                                *   (for socket I/O on Unix systems, consult errno for details).
6340 -                                *
6341 -                                */
6342 -                               while((ssl_err = ERR_get_error())) {
6343 -                                       /* get all errors from the error-queue */
6344 -                                       log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:", 
6345 -                                                       r, ERR_error_string(ssl_err, NULL));
6346 -                               }
6347  
6348 -                               switch(errno) {
6349 -                               default:
6350 -                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", 
6351 -                                                       len, r, errno,
6352 -                                                       strerror(errno));
6353 -                                       break;
6354 -                               }
6355 -                               
6356 -                               break;
6357 -                       case SSL_ERROR_ZERO_RETURN:
6358 -                               /* clean shutdown on the remote side */
6359 -                               
6360 -                               if (r == 0) {
6361 -                                       /* FIXME: later */
6362 -                               }
6363 -                               
6364 -                               /* fall thourgh */
6365 -                       default:
6366 -                               while((ssl_err = ERR_get_error())) {
6367 -                                       /* get all errors from the error-queue */
6368 -                                       log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:", 
6369 -                                                       r, ERR_error_string(ssl_err, NULL));
6370 -                               }
6371 -                               break;
6372 -                       }
6373 -               } else {
6374 -                       if (errno == EAGAIN) return 0;
6375 -                       if (errno == EINTR) {
6376 -                               /* we have been interrupted before we could read */
6377 -                               con->is_readable = 1;
6378 -                               return 0;
6379 -                       }
6380 -               
6381 -                       if (errno != ECONNRESET) {
6382 -                               /* expected for keep-alive */
6383 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
6384 -                       }
6385 -               }
6386 -#else
6387 -               if (errno == EAGAIN) return 0;
6388 -               if (errno == EINTR) {
6389 -                       /* we have been interrupted before we could read */
6390 -                       con->is_readable = 1;
6391 -                       return 0;
6392 -               }
6393 -               
6394 -               if (errno != ECONNRESET) {
6395 -                       /* expected for keep-alive */
6396 -                       log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
6397 -               }
6398 -#endif
6399                 connection_set_state(srv, con, CON_STATE_ERROR);
6400 -               
6401 -               return -1;
6402 -       } else if (len == 0) {
6403 -               con->is_readable = 0;
6404 -               /* the other end close the connection -> KEEP-ALIVE */
6405 +               return NETWORK_STATUS_FATAL_ERROR;
6406 +       default:
6407 +               SEGFAULT();
6408 +               break;
6409 +       }
6410  
6411 -               /* pipelining */
6412 +       newlen = chunkqueue_length(con->read_queue);
6413  
6414 -               return -2;
6415 -       } else if ((size_t)len < b->size - 1) {
6416 -               /* we got less then expected, wait for the next fd-event */
6417 -               
6418 -               con->is_readable = 0;
6419 -       }
6420 -       
6421 -       b->used = len;
6422 -       b->ptr[b->used++] = '\0';
6423 -       
6424 -       con->bytes_read += len;
6425 -#if 0
6426 -       dump_packet(b->ptr, len);
6427 -#endif
6428 -       
6429 -       return 0;
6430 +       con->bytes_read += (newlen - oldlen);
6431 +
6432 +       return NETWORK_STATUS_SUCCESS;
6433  }
6434  
6435  static int connection_handle_write_prepare(server *srv, connection *con) {
6436 @@ -343,6 +207,7 @@
6437                 case HTTP_METHOD_GET:
6438                 case HTTP_METHOD_POST:
6439                 case HTTP_METHOD_HEAD:
6440 +                       /* webdav */
6441                 case HTTP_METHOD_PUT:
6442                 case HTTP_METHOD_MKCOL:
6443                 case HTTP_METHOD_DELETE:
6444 @@ -350,12 +215,14 @@
6445                 case HTTP_METHOD_MOVE:
6446                 case HTTP_METHOD_PROPFIND:
6447                 case HTTP_METHOD_PROPPATCH:
6448 +               case HTTP_METHOD_LOCK:
6449 +               case HTTP_METHOD_UNLOCK:
6450                         break;
6451                 case HTTP_METHOD_OPTIONS:
6452                         /*
6453                          * 400 is coming from the request-parser BEFORE uri.path is set
6454 -                        * 403 is from the response handler when noone else catched it 
6455 -                        * 
6456 +                        * 403 is from the response handler when noone else catched it
6457 +                        *
6458                          * */
6459                         if (con->uri.path->used &&
6460                             con->uri.path->ptr[0] != '*') {
6461 @@ -381,55 +248,60 @@
6462                         break;
6463                 }
6464         }
6465 -       
6466 +
6467         if (con->http_status == 0) {
6468                 con->http_status = 403;
6469         }
6470 -       
6471 +
6472         switch(con->http_status) {
6473         case 400: /* class: header + custom body */
6474         case 401:
6475         case 403:
6476         case 404:
6477         case 408:
6478 +       case 409:
6479 +       case 410:
6480         case 411:
6481         case 416:
6482         case 423:
6483         case 500:
6484         case 501:
6485 +       case 502:
6486         case 503:
6487 -       case 505: 
6488 +       case 504:
6489 +       case 505:
6490 +       case 509:
6491                 if (con->mode != DIRECT) break;
6492 -               
6493 +
6494                 con->file_finished = 0;
6495 -               
6496 +
6497                 buffer_reset(con->physical.path);
6498 -                               
6499 +
6500                 /* try to send static errorfile */
6501                 if (!buffer_is_empty(con->conf.errorfile_prefix)) {
6502                         stat_cache_entry *sce = NULL;
6503 -                       
6504 +
6505                         buffer_copy_string_buffer(con->physical.path, con->conf.errorfile_prefix);
6506                         buffer_append_string(con->physical.path, get_http_status_body_name(con->http_status));
6507 -                       
6508 +
6509                         if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
6510                                 con->file_finished = 1;
6511 -                               
6512 +
6513                                 http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
6514                                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
6515                         }
6516                 }
6517 -               
6518 -               if (!con->file_finished) {                      
6519 +
6520 +               if (!con->file_finished) {
6521                         buffer *b;
6522 -                       
6523 +
6524                         buffer_reset(con->physical.path);
6525 -                       
6526 +
6527                         con->file_finished = 1;
6528                         b = chunkqueue_get_append_buffer(con->write_queue);
6529 -                               
6530 +
6531                         /* build default error-page */
6532 -                       buffer_copy_string(b, 
6533 +                       buffer_copy_string(b,
6534                                            "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
6535                                            "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
6536                                            "         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
6537 @@ -439,7 +311,7 @@
6538                         buffer_append_long(b, con->http_status);
6539                         buffer_append_string(b, " - ");
6540                         buffer_append_string(b, get_http_status_name(con->http_status));
6541 -                       
6542 +
6543                         buffer_append_string(b,
6544                                              "</title>\n"
6545                                              " </head>\n"
6546 @@ -448,12 +320,12 @@
6547                         buffer_append_long(b, con->http_status);
6548                         buffer_append_string(b, " - ");
6549                         buffer_append_string(b, get_http_status_name(con->http_status));
6550 -                       
6551 -                       buffer_append_string(b,"</h1>\n" 
6552 +
6553 +                       buffer_append_string(b,"</h1>\n"
6554                                              " </body>\n"
6555                                              "</html>\n"
6556                                              );
6557 -                       
6558 +
6559                         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
6560                 }
6561                 /* fall through */
6562 @@ -463,10 +335,10 @@
6563         case 301:
6564         case 302:
6565                 break;
6566 -               
6567 +
6568         case 206: /* write_queue is already prepared */
6569                 con->file_finished = 1;
6570 -               
6571 +
6572                 break;
6573         case 205: /* class: header only */
6574         case 304:
6575 @@ -474,19 +346,19 @@
6576                 /* disable chunked encoding again as we have no body */
6577                 con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
6578                 chunkqueue_reset(con->write_queue);
6579 -               
6580 +
6581                 con->file_finished = 1;
6582                 break;
6583         }
6584 -       
6585 +
6586  
6587         if (con->file_finished) {
6588 -               /* we have all the content and chunked encoding is not used, set a content-length */ 
6589 -               
6590 -               if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) && 
6591 +               /* we have all the content and chunked encoding is not used, set a content-length */
6592 +
6593 +               if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) &&
6594                     (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) {
6595                         buffer_copy_off_t(srv->tmp_buf, chunkqueue_length(con->write_queue));
6596 -               
6597 +
6598                         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf));
6599                 }
6600         } else {
6601 @@ -495,77 +367,79 @@
6602                     ((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0)) {
6603                         con->keep_alive = 0;
6604                 }
6605 -               
6606 +
6607                 if (0 == (con->parsed_response & HTTP_CONNECTION)) {
6608                         /* (f)cgi did'nt send Connection: header
6609 -                        *                          
6610 +                        *
6611                          * shall we ?
6612                          */
6613                         if (((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) &&
6614                             (con->parsed_response & HTTP_CONTENT_LENGTH) == 0) {
6615                                 /* without content_length, no keep-alive */
6616 -                               
6617 +
6618                                 con->keep_alive = 0;
6619                         }
6620                 } else {
6621                         /* a subrequest disable keep-alive although the client wanted it */
6622                         if (con->keep_alive && !con->response.keep_alive) {
6623                                 con->keep_alive = 0;
6624 -                               
6625 +
6626                                 /* FIXME: we have to drop the Connection: Header from the subrequest */
6627                         }
6628                 }
6629         }
6630 -       
6631 +
6632         if (con->request.http_method == HTTP_METHOD_HEAD) {
6633                 chunkqueue_reset(con->write_queue);
6634         }
6635  
6636         http_response_write_header(srv, con);
6637 -               
6638 +
6639         return 0;
6640  }
6641  
6642  static int connection_handle_write(server *srv, connection *con) {
6643         switch(network_write_chunkqueue(srv, con, con->write_queue)) {
6644 -       case 0:
6645 +       case NETWORK_STATUS_SUCCESS:
6646                 if (con->file_finished) {
6647                         connection_set_state(srv, con, CON_STATE_RESPONSE_END);
6648                         joblist_append(srv, con);
6649                 }
6650                 break;
6651 -       case -1: /* error on our side */
6652 +       case NETWORK_STATUS_FATAL_ERROR: /* error on our side */
6653                 log_error_write(srv, __FILE__, __LINE__, "sd",
6654 -                               "connection closed: write failed on fd", con->fd);
6655 +                               "connection closed: write failed on fd", con->sock->fd);
6656                 connection_set_state(srv, con, CON_STATE_ERROR);
6657                 joblist_append(srv, con);
6658                 break;
6659 -       case -2: /* remote close */
6660 +       case NETWORK_STATUS_CONNECTION_CLOSE: /* remote close */
6661                 connection_set_state(srv, con, CON_STATE_ERROR);
6662                 joblist_append(srv, con);
6663                 break;
6664 -       case 1:
6665 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
6666                 con->is_writable = 0;
6667 -               
6668 +
6669                 /* not finished yet -> WRITE */
6670                 break;
6671 +       case NETWORK_STATUS_INTERRUPTED:
6672 +               con->is_writable = 1;
6673 +               break;
6674 +       case NETWORK_STATUS_UNSET:
6675 +               break;
6676         }
6677 -       
6678 +
6679         return 0;
6680  }
6681  
6682 -
6683 -
6684  connection *connection_init(server *srv) {
6685         connection *con;
6686 -       
6687 +
6688         UNUSED(srv);
6689  
6690         con = calloc(1, sizeof(*con));
6691 -               
6692 -       con->fd = 0;
6693 +
6694 +       con->sock = iosocket_init();
6695         con->ndx = -1;
6696 -       con->fde_ndx = -1;
6697         con->bytes_written = 0;
6698         con->bytes_read = 0;
6699         con->bytes_header = 0;
6700 @@ -573,32 +447,32 @@
6701  
6702  #define CLEAN(x) \
6703         con->x = buffer_init();
6704 -       
6705 +
6706         CLEAN(request.uri);
6707         CLEAN(request.request_line);
6708         CLEAN(request.request);
6709         CLEAN(request.pathinfo);
6710 -       
6711 +
6712         CLEAN(request.orig_uri);
6713 -       
6714 +
6715         CLEAN(uri.scheme);
6716         CLEAN(uri.authority);
6717         CLEAN(uri.path);
6718         CLEAN(uri.path_raw);
6719         CLEAN(uri.query);
6720 -       
6721 +
6722         CLEAN(physical.doc_root);
6723         CLEAN(physical.path);
6724         CLEAN(physical.basedir);
6725         CLEAN(physical.rel_path);
6726         CLEAN(physical.etag);
6727         CLEAN(parse_request);
6728 -       
6729 +
6730         CLEAN(authed_user);
6731         CLEAN(server_name);
6732         CLEAN(error_handler);
6733         CLEAN(dst_addr_buf);
6734 -       
6735 +
6736  #undef CLEAN
6737         con->write_queue = chunkqueue_init();
6738         con->read_queue = chunkqueue_init();
6739 @@ -608,26 +482,27 @@
6740         con->request.headers      = array_init();
6741         con->response.headers     = array_init();
6742         con->environment     = array_init();
6743 -       
6744 +
6745         /* init plugin specific connection structures */
6746 -       
6747 +
6748         con->plugin_ctx = calloc(1, (srv->plugins.used + 1) * sizeof(void *));
6749 -       
6750 +
6751         con->cond_cache = calloc(srv->config_context->used, sizeof(cond_cache_t));
6752         config_setup_connection(srv, con);
6753 -       
6754 +
6755         return con;
6756  }
6757  
6758  void connections_free(server *srv) {
6759         connections *conns = srv->conns;
6760 -       size_t i;       
6761 -       
6762 +       size_t i;
6763 +
6764         for (i = 0; i < conns->size; i++) {
6765                 connection *con = conns->ptr[i];
6766 -               
6767 +
6768                 connection_reset(srv, con);
6769 -               
6770 +               iosocket_free(con->sock);
6771 +
6772                 chunkqueue_free(con->write_queue);
6773                 chunkqueue_free(con->read_queue);
6774                 chunkqueue_free(con->request_content_queue);
6775 @@ -637,27 +512,27 @@
6776  
6777  #define CLEAN(x) \
6778         buffer_free(con->x);
6779 -               
6780 +
6781                 CLEAN(request.uri);
6782                 CLEAN(request.request_line);
6783                 CLEAN(request.request);
6784                 CLEAN(request.pathinfo);
6785 -               
6786 +
6787                 CLEAN(request.orig_uri);
6788 -               
6789 +
6790                 CLEAN(uri.scheme);
6791                 CLEAN(uri.authority);
6792                 CLEAN(uri.path);
6793                 CLEAN(uri.path_raw);
6794                 CLEAN(uri.query);
6795 -               
6796 +
6797                 CLEAN(physical.doc_root);
6798                 CLEAN(physical.path);
6799                 CLEAN(physical.basedir);
6800                 CLEAN(physical.etag);
6801                 CLEAN(physical.rel_path);
6802                 CLEAN(parse_request);
6803 -               
6804 +
6805                 CLEAN(authed_user);
6806                 CLEAN(server_name);
6807                 CLEAN(error_handler);
6808 @@ -665,97 +540,97 @@
6809  #undef CLEAN
6810                 free(con->plugin_ctx);
6811                 free(con->cond_cache);
6812 -               
6813 +
6814                 free(con);
6815         }
6816 -       
6817 +
6818         free(conns->ptr);
6819  }
6820  
6821  
6822  int connection_reset(server *srv, connection *con) {
6823         size_t i;
6824 -       
6825 +
6826         plugins_call_connection_reset(srv, con);
6827 -       
6828 +
6829         con->is_readable = 1;
6830         con->is_writable = 1;
6831         con->http_status = 0;
6832         con->file_finished = 0;
6833         con->file_started = 0;
6834         con->got_response = 0;
6835 -       
6836 +
6837         con->parsed_response = 0;
6838 -       
6839 +
6840         con->bytes_written = 0;
6841         con->bytes_written_cur_second = 0;
6842         con->bytes_read = 0;
6843         con->bytes_header = 0;
6844         con->loops_per_request = 0;
6845 -       
6846 +
6847         con->request.http_method = HTTP_METHOD_UNSET;
6848         con->request.http_version = HTTP_VERSION_UNSET;
6849 -       
6850 +
6851         con->request.http_if_modified_since = NULL;
6852         con->request.http_if_none_match = NULL;
6853 -       
6854 +
6855         con->response.keep_alive = 0;
6856         con->response.content_length = -1;
6857         con->response.transfer_encoding = 0;
6858 -       
6859 +
6860         con->mode = DIRECT;
6861 -       
6862 +
6863  #define CLEAN(x) \
6864         if (con->x) buffer_reset(con->x);
6865 -       
6866 +
6867         CLEAN(request.uri);
6868         CLEAN(request.request_line);
6869         CLEAN(request.pathinfo);
6870         CLEAN(request.request);
6871 -       
6872 +
6873         CLEAN(request.orig_uri);
6874 -       
6875 +
6876         CLEAN(uri.scheme);
6877         CLEAN(uri.authority);
6878         CLEAN(uri.path);
6879         CLEAN(uri.path_raw);
6880         CLEAN(uri.query);
6881 -       
6882 +
6883         CLEAN(physical.doc_root);
6884         CLEAN(physical.path);
6885         CLEAN(physical.basedir);
6886         CLEAN(physical.rel_path);
6887         CLEAN(physical.etag);
6888 -       
6889 +
6890         CLEAN(parse_request);
6891 -       
6892 +
6893         CLEAN(authed_user);
6894         CLEAN(server_name);
6895         CLEAN(error_handler);
6896 -#undef CLEAN   
6897 -       
6898 +#undef CLEAN
6899 +
6900  #define CLEAN(x) \
6901 -       if (con->x) con->x->used = 0;   
6902 -       
6903 +       if (con->x) con->x->used = 0;
6904 +
6905  #undef CLEAN
6906 -       
6907 +
6908  #define CLEAN(x) \
6909                 con->request.x = NULL;
6910 -       
6911 +
6912         CLEAN(http_host);
6913         CLEAN(http_range);
6914         CLEAN(http_content_type);
6915  #undef CLEAN
6916         con->request.content_length = 0;
6917 -       
6918 +
6919         array_reset(con->request.headers);
6920         array_reset(con->response.headers);
6921         array_reset(con->environment);
6922 -       
6923 +
6924         chunkqueue_reset(con->write_queue);
6925         chunkqueue_reset(con->request_content_queue);
6926  
6927 -       /* the plugins should cleanup themself */       
6928 +       /* the plugins should cleanup themself */
6929         for (i = 0; i < srv->plugins.used; i++) {
6930                 plugin *p = ((plugin **)(srv->plugins.ptr))[i];
6931                 plugin_data *pd = p->data;
6932 @@ -768,7 +643,7 @@
6933  
6934                 con->plugin_ctx[pd->id] = NULL;
6935         }
6936 -       
6937 +
6938  #if COND_RESULT_UNSET
6939         for (i = srv->config_context->used - 1; i >= 0; i --) {
6940                 con->cond_cache[i].result = COND_RESULT_UNSET;
6941 @@ -777,56 +652,56 @@
6942  #else
6943         memset(con->cond_cache, 0, sizeof(cond_cache_t) * srv->config_context->used);
6944  #endif
6945 -       
6946 +
6947         con->header_len = 0;
6948         con->in_error_handler = 0;
6949 -       
6950 +
6951         config_setup_connection(srv, con);
6952 -       
6953 +
6954         return 0;
6955  }
6956  
6957  /**
6958 - * 
6959 - * search for \r\n\r\n 
6960 - * 
6961 + *
6962 + * search for \r\n\r\n
6963 + *
6964   * this is a special 32bit version which is using a sliding window for
6965 - * the comparisions 
6966 - * 
6967 + * the comparisions
6968 + *
6969   * how it works:
6970 - * 
6971 + *
6972   * b:      'abcdefg'
6973   * rnrn:   'cdef'
6974 - * 
6975 + *
6976   * cmpbuf: abcd != cdef
6977   * cmpbuf: bcde != cdef
6978   * cmpbuf: cdef == cdef -> return &c
6979 - * 
6980 - * cmpbuf and rnrn are treated as 32bit uint and bit-ops are used to 
6981 + *
6982 + * cmpbuf and rnrn are treated as 32bit uint and bit-ops are used to
6983   * maintain cmpbuf and rnrn
6984 - * 
6985 + *
6986   */
6987  
6988  char *buffer_search_rnrn(buffer *b) {
6989         uint32_t cmpbuf, rnrn;
6990         char *cp;
6991         size_t i;
6992 -       
6993 +
6994         if (b->used < 4) return NULL;
6995 -       
6996 +
6997         rnrn = ('\r' << 24) | ('\n' << 16) |
6998                 ('\r' << 8) | ('\n' << 0);
6999 -       
7000 +
7001         cmpbuf = (b->ptr[0] << 24) | (b->ptr[1] << 16) |
7002                 (b->ptr[2] << 8) | (b->ptr[3] << 0);
7003 -               
7004 +
7005         cp = b->ptr + 4;
7006         for (i = 0; i < b->used - 4; i++) {
7007                 if (cmpbuf == rnrn) return cp - 4;
7008 -                       
7009 +
7010                 cmpbuf = (cmpbuf << 8 | *(cp++)) & 0xffffffff;
7011         }
7012 -       
7013 +
7014         return NULL;
7015  }
7016  /**
7017 @@ -840,22 +715,25 @@
7018         chunk *c;
7019         chunkqueue *cq = con->read_queue;
7020         chunkqueue *dst_cq = con->request_content_queue;
7021 -       
7022 +
7023         if (con->is_readable) {
7024                 con->read_idle_ts = srv->cur_ts;
7025 -       
7026 +
7027                 switch(connection_handle_read(srv, con)) {
7028 -               case -1:
7029 +               case NETWORK_STATUS_FATAL_ERROR:
7030                         return -1;
7031 -               case -2:
7032 +               case NETWORK_STATUS_CONNECTION_CLOSE:
7033                         /* remote side closed the connection
7034                          * if we still have content, handle it, if not leave here */
7035  
7036                         if (cq->first == cq->last &&
7037 -                           cq->first->mem->used == 0) {
7038 +                           (NULL == cq->first ||
7039 +                           cq->first->mem->used == 0)) {
7040  
7041                                 /* conn-closed, leave here */
7042                                 connection_set_state(srv, con, CON_STATE_ERROR);
7043 +
7044 +                               return 0;
7045                         }
7046                 default:
7047                         break;
7048 @@ -891,14 +769,14 @@
7049                         /* the last node was empty */
7050                         if (c->next == NULL) {
7051                                 cq->last = c;
7052 -                       } 
7053 +                       }
7054  
7055                         c = c->next;
7056                 } else {
7057                         c = c->next;
7058                 }
7059         }
7060 -       
7061 +
7062         /* nothing to handle */
7063         if (cq->first == NULL) return 0;
7064  
7065 @@ -906,25 +784,26 @@
7066         case CON_STATE_READ:
7067                 /* prepare con->request.request */
7068                 c = cq->first;
7069 -               
7070 +
7071                 /* check if we need the full package */
7072                 if (con->request.request->used == 0) {
7073                         buffer b;
7074 -                       
7075 +
7076                         b.ptr = c->mem->ptr + c->offset;
7077                         b.used = c->mem->used - c->offset;
7078 -                       
7079 +
7080                         if (NULL != (h_term = buffer_search_rnrn(&b))) {
7081                                 /* \r\n\r\n found
7082                                  * - copy everything incl. the terminator to request.request
7083                                  */
7084 -                               
7085 -                               buffer_copy_string_len(con->request.request, 
7086 -                                                      b.ptr, 
7087 +
7088 +                               buffer_copy_string_len(con->request.request,
7089 +                                                      b.ptr,
7090                                                        h_term - b.ptr + 4);
7091 -                               
7092 +
7093                                 /* the buffer has been read up to the terminator */
7094                                 c->offset += h_term - b.ptr + 4;
7095 +
7096                         } else {
7097                                 /* not found, copy everything */
7098                                 buffer_copy_string_len(con->request.request, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
7099 @@ -932,14 +811,14 @@
7100                         }
7101                 } else {
7102                         /* have to take care of overlapping header terminators */
7103 -                       
7104 +
7105                         size_t l = con->request.request->used - 2;
7106                         char *s  = con->request.request->ptr;
7107                         buffer b;
7108 -                       
7109 +
7110                         b.ptr = c->mem->ptr + c->offset;
7111                         b.used = c->mem->used - c->offset;
7112 -                       
7113 +
7114                         if (con->request.request->used - 1 > 3 &&
7115                             c->mem->used > 1 &&
7116                             s[l-2] == '\r' &&
7117 @@ -948,7 +827,7 @@
7118                             c->mem->ptr[0] == '\n') {
7119                                 buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 1);
7120                                 c->offset += 1;
7121 -                               
7122 +
7123                                 h_term = con->request.request->ptr;
7124                         } else if (con->request.request->used - 1 > 2 &&
7125                                    c->mem->used > 2 &&
7126 @@ -958,7 +837,7 @@
7127                                    c->mem->ptr[1] == '\n') {
7128                                 buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 2);
7129                                 c->offset += 2;
7130 -                               
7131 +
7132                                 h_term = con->request.request->ptr;
7133                         } else if (con->request.request->used - 1 > 1 &&
7134                                    c->mem->used > 3 &&
7135 @@ -968,17 +847,17 @@
7136                                    c->mem->ptr[2] == '\n') {
7137                                 buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 3);
7138                                 c->offset += 3;
7139 -                               
7140 +
7141                                 h_term = con->request.request->ptr;
7142                         } else if (NULL != (h_term = buffer_search_string_len(&b, "\r\n\r\n", 4))) {
7143                                 /* \r\n\r\n found
7144                                  * - copy everything incl. the terminator to request.request
7145                                  */
7146 -                               
7147 -                               buffer_append_string_len(con->request.request, 
7148 -                                                      c->mem->ptr + c->offset, 
7149 +
7150 +                               buffer_append_string_len(con->request.request,
7151 +                                                      c->mem->ptr + c->offset,
7152                                                        c->offset + h_term - b.ptr + 4);
7153 -                               
7154 +
7155                                 /* the buffer has been read up to the terminator */
7156                                 c->offset += h_term - b.ptr + 4;
7157                         } else {
7158 @@ -999,16 +878,16 @@
7159                         connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7160                 }
7161                 break;
7162 -       case CON_STATE_READ_POST: 
7163 +       case CON_STATE_READ_POST:
7164                 for (c = cq->first; c && (dst_cq->bytes_in != (off_t)con->request.content_length); c = c->next) {
7165                         off_t weWant, weHave, toRead;
7166 -                       
7167 +
7168                         weWant = con->request.content_length - dst_cq->bytes_in;
7169 -                       
7170 +
7171                         assert(c->mem->used);
7172 -                       
7173 +
7174                         weHave = c->mem->used - c->offset - 1;
7175 -                               
7176 +
7177                         toRead = weHave > weWant ? weWant : weHave;
7178  
7179                         /* the new way, copy everything into a chunkqueue whcih might use tempfiles */
7180 @@ -1017,13 +896,13 @@
7181                                 /* copy everything to max 1Mb sized tempfiles */
7182  
7183                                 /*
7184 -                                * if the last chunk is 
7185 +                                * if the last chunk is
7186                                  * - smaller than 1Mb (size < 1Mb)
7187                                  * - not read yet (offset == 0)
7188                                  * -> append to it
7189                                  * otherwise
7190 -                                * -> create a new chunk 
7191 -                                * 
7192 +                                * -> create a new chunk
7193 +                                *
7194                                  * */
7195  
7196                                 if (dst_cq->last &&
7197 @@ -1056,14 +935,14 @@
7198                                 /* we have a chunk, let's write to it */
7199  
7200                                 if (dst_c->file.fd == -1) {
7201 -                                       /* we don't have file to write to, 
7202 +                                       /* we don't have file to write to,
7203                                          * EACCES might be one reason.
7204                                          *
7205                                          * Instead of sending 500 we send 413 and say the request is too large
7206                                          *  */
7207  
7208                                         log_error_write(srv, __FILE__, __LINE__, "sbs",
7209 -                                                       "denying upload as opening to temp-file for upload failed:", 
7210 +                                                       "denying upload as opening to temp-file for upload failed:",
7211                                                         dst_c->file.name, strerror(errno));
7212  
7213                                         con->http_status = 413; /* Request-Entity too large */
7214 @@ -1074,15 +953,15 @@
7215                                 }
7216  
7217                                 if (toRead != write(dst_c->file.fd, c->mem->ptr + c->offset, toRead)) {
7218 -                                       /* write failed for some reason ... disk full ? */ 
7219 +                                       /* write failed for some reason ... disk full ? */
7220                                         log_error_write(srv, __FILE__, __LINE__, "sbs",
7221 -                                                       "denying upload as writing to file failed:", 
7222 +                                                       "denying upload as writing to file failed:",
7223                                                         dst_c->file.name, strerror(errno));
7224 -                                       
7225 +
7226                                         con->http_status = 413; /* Request-Entity too large */
7227                                         con->keep_alive = 0;
7228                                         connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7229 -                               
7230 +
7231                                         close(dst_c->file.fd);
7232                                         dst_c->file.fd = -1;
7233  
7234 @@ -1090,7 +969,7 @@
7235                                 }
7236  
7237                                 dst_c->file.length += toRead;
7238 -                                       
7239 +
7240                                 if (dst_cq->bytes_in + toRead == (off_t)con->request.content_length) {
7241                                         /* we read everything, close the chunk */
7242                                         close(dst_c->file.fd);
7243 @@ -1102,7 +981,7 @@
7244                                 b = chunkqueue_get_append_buffer(dst_cq);
7245                                 buffer_copy_string_len(b, c->mem->ptr + c->offset, toRead);
7246                         }
7247 -                       
7248 +
7249                         c->offset += toRead;
7250                         dst_cq->bytes_in += toRead;
7251                 }
7252 @@ -1111,7 +990,7 @@
7253                 if (dst_cq->bytes_in == (off_t)con->request.content_length) {
7254                         connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7255                 }
7256 -                       
7257 +
7258                 break;
7259         }
7260  
7261 @@ -1123,100 +1002,104 @@
7262  handler_t connection_handle_fdevent(void *s, void *context, int revents) {
7263         server     *srv = (server *)s;
7264         connection *con = context;
7265 -       
7266 +
7267         joblist_append(srv, con);
7268 -       
7269 +
7270         if (revents & FDEVENT_IN) {
7271                 con->is_readable = 1;
7272 -#if 0
7273 -               log_error_write(srv, __FILE__, __LINE__, "sd", "read-wait - done", con->fd);
7274 -#endif
7275         }
7276         if (revents & FDEVENT_OUT) {
7277                 con->is_writable = 1;
7278                 /* we don't need the event twice */
7279         }
7280 -       
7281 -       
7282 +
7283 +
7284         if (revents & ~(FDEVENT_IN | FDEVENT_OUT)) {
7285                 /* looks like an error */
7286 -                                               
7287 +
7288                 /* FIXME: revents = 0x19 still means that we should read from the queue */
7289                 if (revents & FDEVENT_HUP) {
7290                         if (con->state == CON_STATE_CLOSE) {
7291                                 con->close_timeout_ts = 0;
7292                         } else {
7293                                 /* sigio reports the wrong event here
7294 -                                * 
7295 -                                * there was no HUP at all 
7296 +                                *
7297 +                                * there was no HUP at all
7298                                  */
7299  #ifdef USE_LINUX_SIGIO
7300                                 if (srv->ev->in_sigio == 1) {
7301                                         log_error_write(srv, __FILE__, __LINE__, "sd",
7302 -                                               "connection closed: poll() -> HUP", con->fd);
7303 +                                               "connection closed: poll() -> HUP", con->sock->fd);
7304                                 } else {
7305                                         connection_set_state(srv, con, CON_STATE_ERROR);
7306                                 }
7307  #else
7308                                 connection_set_state(srv, con, CON_STATE_ERROR);
7309  #endif
7310 -                               
7311 +
7312                         }
7313                 } else if (revents & FDEVENT_ERR) {
7314  #ifndef USE_LINUX_SIGIO
7315                         log_error_write(srv, __FILE__, __LINE__, "sd",
7316 -                                       "connection closed: poll() -> ERR", con->fd);
7317 -#endif 
7318 +                                       "connection closed: poll() -> ERR", con->sock->fd);
7319 +#endif
7320                         connection_set_state(srv, con, CON_STATE_ERROR);
7321                 } else {
7322                         log_error_write(srv, __FILE__, __LINE__, "sd",
7323                                         "connection closed: poll() -> ???", revents);
7324 -               } 
7325 +               }
7326         }
7327 -       
7328 +
7329         if (con->state == CON_STATE_READ ||
7330             con->state == CON_STATE_READ_POST) {
7331                 connection_handle_read_state(srv, con);
7332 +               /**
7333 +                * if SSL_read() is not readin in the full packet we won't get
7334 +                * a fdevent as the low-level has already fetched everything.
7335 +                *
7336 +                * we have to call the state-engine to read the rest of the packet
7337 +                */
7338 +               if (con->is_readable) joblist_append(srv, con);
7339         }
7340 -       
7341 +
7342         if (con->state == CON_STATE_WRITE &&
7343             !chunkqueue_is_empty(con->write_queue) &&
7344             con->is_writable) {
7345 -               
7346 +
7347                 if (-1 == connection_handle_write(srv, con)) {
7348                         connection_set_state(srv, con, CON_STATE_ERROR);
7349 -                       
7350 +
7351                         log_error_write(srv, __FILE__, __LINE__, "ds",
7352 -                                       con->fd,
7353 +                                       con->sock->fd,
7354                                         "handle write failed.");
7355                 } else if (con->state == CON_STATE_WRITE) {
7356                         con->write_request_ts = srv->cur_ts;
7357                 }
7358         }
7359 -       
7360 +
7361         if (con->state == CON_STATE_CLOSE) {
7362                 /* flush the read buffers */
7363                 int b;
7364 -               
7365 -               if (ioctl(con->fd, FIONREAD, &b)) {
7366 +
7367 +               if (ioctl(con->sock->fd, FIONREAD, &b)) {
7368                         log_error_write(srv, __FILE__, __LINE__, "ss",
7369                                         "ioctl() failed", strerror(errno));
7370                 }
7371 -               
7372 +
7373                 if (b > 0) {
7374                         char buf[1024];
7375                         log_error_write(srv, __FILE__, __LINE__, "sdd",
7376 -                                       "CLOSE-read()", con->fd, b);
7377 -                       
7378 +                                       "CLOSE-read()", con->sock->fd, b);
7379 +
7380                         /* */
7381 -                       read(con->fd, buf, sizeof(buf));
7382 +                       read(con->sock->fd, buf, sizeof(buf));
7383                 } else {
7384                         /* nothing to read */
7385 -                       
7386 +
7387                         con->close_timeout_ts = 0;
7388                 }
7389         }
7390 -       
7391 +
7392         return HANDLER_FINISHED;
7393  }
7394  
7395 @@ -1229,63 +1112,68 @@
7396         sock_addr cnt_addr;
7397         socklen_t cnt_len;
7398         /* accept it and register the fd */
7399 -       
7400 +
7401         cnt_len = sizeof(cnt_addr);
7402  
7403 -       if (-1 == (cnt = accept(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {
7404 +       if (-1 == (cnt = accept(srv_socket->sock->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {
7405 +#ifdef _WIN32
7406 +               errno = WSAGetLastError();
7407 +#endif
7408                 if ((errno != EAGAIN) &&
7409 +                   (errno != EWOULDBLOCK) &&
7410                     (errno != EINTR)) {
7411 -                       log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), errno);
7412 +                       log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), srv_socket->sock->fd);
7413                 }
7414                 return NULL;
7415         } else {
7416                 connection *con;
7417 -               
7418 +
7419                 srv->cur_fds++;
7420 -               
7421 +
7422                 /* ok, we have the connection, register it */
7423  #if 0
7424                 log_error_write(srv, __FILE__, __LINE__, "sd",
7425                                 "appected()", cnt);
7426  #endif
7427                 srv->con_opened++;
7428 -               
7429 +
7430                 con = connections_get_new_connection(srv);
7431 -               
7432 -               con->fd = cnt;
7433 -               con->fde_ndx = -1;
7434 -#if 0          
7435 +               con->sock->fd = cnt;
7436 +               con->sock->fde_ndx = -1;
7437 +#if 0
7438                 gettimeofday(&(con->start_tv), NULL);
7439 -#endif         
7440 -               fdevent_register(srv->ev, con->fd, connection_handle_fdevent, con);
7441 -               
7442 +#endif
7443 +               fdevent_register(srv->ev, con->sock, connection_handle_fdevent, con);
7444 +
7445                 connection_set_state(srv, con, CON_STATE_REQUEST_START);
7446 -               
7447 +
7448                 con->connection_start = srv->cur_ts;
7449                 con->dst_addr = cnt_addr;
7450                 buffer_copy_string(con->dst_addr_buf, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
7451                 con->srv_socket = srv_socket;
7452 -               
7453 -               if (-1 == (fdevent_fcntl_set(srv->ev, con->fd))) {
7454 +
7455 +               if (-1 == (fdevent_fcntl_set(srv->ev, con->sock))) {
7456                         log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
7457 +                       connection_close(srv, con);
7458                         return NULL;
7459                 }
7460  #ifdef USE_OPENSSL
7461                 /* connect FD to SSL */
7462                 if (srv_socket->is_ssl) {
7463 -                       if (NULL == (con->ssl = SSL_new(srv_socket->ssl_ctx))) {
7464 -                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
7465 +                       if (NULL == (con->sock->ssl = SSL_new(srv_socket->ssl_ctx))) {
7466 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7467                                                 ERR_error_string(ERR_get_error(), NULL));
7468 -                               
7469 +                               connection_close(srv, con);
7470                                 return NULL;
7471                         }
7472 -                       
7473 -                       SSL_set_accept_state(con->ssl);
7474 +
7475 +                       SSL_set_accept_state(con->sock->ssl);
7476                         con->conf.is_ssl=1;
7477 -                       
7478 -                       if (1 != (SSL_set_fd(con->ssl, cnt))) {
7479 -                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
7480 +
7481 +                       if (1 != (SSL_set_fd(con->sock->ssl, cnt))) {
7482 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7483                                                 ERR_error_string(ERR_get_error(), NULL));
7484 +                               connection_close(srv, con);
7485                                 return NULL;
7486                         }
7487                 }
7488 @@ -1300,102 +1188,102 @@
7489  #ifdef USE_OPENSSL
7490         server_socket *srv_sock = con->srv_socket;
7491  #endif
7492 -       
7493 +
7494         if (srv->srvconf.log_state_handling) {
7495 -               log_error_write(srv, __FILE__, __LINE__, "sds", 
7496 -                               "state at start", 
7497 -                               con->fd,
7498 +               log_error_write(srv, __FILE__, __LINE__, "sds",
7499 +                               "state at start",
7500 +                               con->sock->fd,
7501                                 connection_get_state(con->state));
7502         }
7503  
7504         while (done == 0) {
7505                 size_t ostate = con->state;
7506                 int b;
7507 -               
7508 +
7509                 switch (con->state) {
7510                 case CON_STATE_REQUEST_START: /* transient */
7511                         if (srv->srvconf.log_state_handling) {
7512 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7513 -                                               "state for fd", con->fd, connection_get_state(con->state));
7514 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7515 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7516                         }
7517 -                       
7518 +
7519                         con->request_start = srv->cur_ts;
7520                         con->read_idle_ts = srv->cur_ts;
7521 -                       
7522 +
7523                         con->request_count++;
7524                         con->loops_per_request = 0;
7525 -                       
7526 +
7527                         connection_set_state(srv, con, CON_STATE_READ);
7528 -                       
7529 +
7530                         break;
7531                 case CON_STATE_REQUEST_END: /* transient */
7532                         if (srv->srvconf.log_state_handling) {
7533 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7534 -                                               "state for fd", con->fd, connection_get_state(con->state));
7535 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7536 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7537                         }
7538 -                       
7539 +
7540                         if (http_request_parse(srv, con)) {
7541                                 /* we have to read some data from the POST request */
7542 -                               
7543 +
7544                                 connection_set_state(srv, con, CON_STATE_READ_POST);
7545  
7546                                 break;
7547                         }
7548 -                       
7549 +
7550                         connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7551 -                       
7552 +
7553                         break;
7554                 case CON_STATE_HANDLE_REQUEST:
7555 -                       /* 
7556 +                       /*
7557                          * the request is parsed
7558 -                        * 
7559 +                        *
7560                          * decided what to do with the request
7561 -                        * - 
7562 -                        * 
7563 -                        * 
7564 +                        * -
7565 +                        *
7566 +                        *
7567                          */
7568 -                       
7569 +
7570                         if (srv->srvconf.log_state_handling) {
7571 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7572 -                                               "state for fd", con->fd, connection_get_state(con->state));
7573 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7574 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7575                         }
7576 -                       
7577 +
7578                         switch (r = http_response_prepare(srv, con)) {
7579                         case HANDLER_FINISHED:
7580                                 if (con->http_status == 404 ||
7581                                     con->http_status == 403) {
7582                                         /* 404 error-handler */
7583 -                                       
7584 -                                       if (con->in_error_handler == 0 && 
7585 +
7586 +                                       if (con->in_error_handler == 0 &&
7587                                             (!buffer_is_empty(con->conf.error_handler) ||
7588                                              !buffer_is_empty(con->error_handler))) {
7589                                                 /* call error-handler */
7590 -                                               
7591 +
7592                                                 con->error_handler_saved_status = con->http_status;
7593                                                 con->http_status = 0;
7594 -                                               
7595 +
7596                                                 if (buffer_is_empty(con->error_handler)) {
7597                                                         buffer_copy_string_buffer(con->request.uri, con->conf.error_handler);
7598                                                 } else {
7599                                                         buffer_copy_string_buffer(con->request.uri, con->error_handler);
7600                                                 }
7601                                                 buffer_reset(con->physical.path);
7602 -                                               
7603 +
7604                                                 con->in_error_handler = 1;
7605 -                                               
7606 +
7607                                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7608 -                                               
7609 +
7610                                                 done = -1;
7611                                                 break;
7612                                         } else if (con->in_error_handler) {
7613                                                 /* error-handler is a 404 */
7614 -                                               
7615 +
7616                                                 /* continue as normal, status is the same */
7617 -                                               log_error_write(srv, __FILE__, __LINE__, "sb", 
7618 +                                               log_error_write(srv, __FILE__, __LINE__, "sb",
7619                                                                 "Warning: Either the error-handler returned status 404 or the error-handler itself was not found:", con->request.uri);
7620 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
7621 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
7622                                                                 "returning the original status", con->error_handler_saved_status);
7623 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
7624 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
7625                                                                 "If this is a rails app: check your production.log");
7626                                                 con->http_status = con->error_handler_saved_status;
7627                                         }
7628 @@ -1403,73 +1291,73 @@
7629                                         /* error-handler is back and has generated content */
7630                                         /* if Status: was set, take it otherwise use 200 */
7631                                 }
7632 -                               
7633 +
7634                                 if (con->http_status == 0) con->http_status = 200;
7635 -                               
7636 +
7637                                 /* we have something to send, go on */
7638                                 connection_set_state(srv, con, CON_STATE_RESPONSE_START);
7639                                 break;
7640                         case HANDLER_WAIT_FOR_FD:
7641                                 srv->want_fds++;
7642 -                               
7643 +
7644                                 fdwaitqueue_append(srv, con);
7645 -                               
7646 +
7647                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7648 -                               
7649 +
7650                                 break;
7651                         case HANDLER_COMEBACK:
7652                                 done = -1;
7653                         case HANDLER_WAIT_FOR_EVENT:
7654                                 /* come back here */
7655                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7656 -                               
7657 +
7658                                 break;
7659                         case HANDLER_ERROR:
7660                                 /* something went wrong */
7661                                 connection_set_state(srv, con, CON_STATE_ERROR);
7662                                 break;
7663                         default:
7664 -                               log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->fd, r);
7665 +                               log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->sock->fd, r);
7666                                 break;
7667                         }
7668 -                       
7669 +
7670                         break;
7671                 case CON_STATE_RESPONSE_START:
7672 -                       /* 
7673 +                       /*
7674                          * the decision is done
7675                          * - create the HTTP-Response-Header
7676 -                        * 
7677 +                        *
7678                          */
7679 -                       
7680 +
7681                         if (srv->srvconf.log_state_handling) {
7682 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7683 -                                               "state for fd", con->fd, connection_get_state(con->state));
7684 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7685 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7686                         }
7687 -                       
7688 +
7689                         if (-1 == connection_handle_write_prepare(srv, con)) {
7690                                 connection_set_state(srv, con, CON_STATE_ERROR);
7691 -                               
7692 +
7693                                 break;
7694                         }
7695 -                       
7696 +
7697                         connection_set_state(srv, con, CON_STATE_WRITE);
7698                         break;
7699                 case CON_STATE_RESPONSE_END: /* transient */
7700                         /* log the request */
7701 -                       
7702 +
7703                         if (srv->srvconf.log_state_handling) {
7704 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7705 -                                               "state for fd", con->fd, connection_get_state(con->state));
7706 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7707 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7708                         }
7709 -                       
7710 +
7711                         plugins_call_handle_request_done(srv, con);
7712 -                       
7713 +
7714                         srv->con_written++;
7715 -                       
7716 +
7717                         if (con->keep_alive) {
7718                                 connection_set_state(srv, con, CON_STATE_REQUEST_START);
7719 -                               
7720 -#if 0                                  
7721 +
7722 +#if 0
7723                                 con->request_start = srv->cur_ts;
7724                                 con->read_idle_ts = srv->cur_ts;
7725  #endif
7726 @@ -1482,103 +1370,103 @@
7727                                         log_error_write(srv, __FILE__, __LINE__, "sd", "unhandling return value", r);
7728                                         break;
7729                                 }
7730 -                               
7731 +
7732  #ifdef USE_OPENSSL
7733                                 if (srv_sock->is_ssl) {
7734 -                                       switch (SSL_shutdown(con->ssl)) {
7735 +                                       switch (SSL_shutdown(con->sock->ssl)) {
7736                                         case 1:
7737                                                 /* done */
7738                                                 break;
7739                                         case 0:
7740 -                                               /* wait for fd-event 
7741 -                                                * 
7742 +                                               /* wait for fd-event
7743 +                                                *
7744                                                  * FIXME: wait for fdevent and call SSL_shutdown again
7745 -                                                * 
7746 +                                                *
7747                                                  */
7748 -                                               
7749 +
7750                                                 break;
7751                                         default:
7752 -                                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
7753 +                                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7754                                                                 ERR_error_string(ERR_get_error(), NULL));
7755                                         }
7756                                 }
7757  #endif
7758                                 connection_close(srv, con);
7759 -                               
7760 +
7761                                 srv->con_closed++;
7762                         }
7763 -                       
7764 +
7765                         connection_reset(srv, con);
7766 -                       
7767 +
7768                         break;
7769                 case CON_STATE_CONNECT:
7770                         if (srv->srvconf.log_state_handling) {
7771 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7772 -                                               "state for fd", con->fd, connection_get_state(con->state));
7773 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7774 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7775                         }
7776 -                       
7777 +
7778                         chunkqueue_reset(con->read_queue);
7779 -                       
7780 +
7781                         con->request_count = 0;
7782 -                       
7783 +
7784                         break;
7785                 case CON_STATE_CLOSE:
7786                         if (srv->srvconf.log_state_handling) {
7787 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7788 -                                               "state for fd", con->fd, connection_get_state(con->state));
7789 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7790 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7791                         }
7792 -                       
7793 +
7794                         if (con->keep_alive) {
7795 -                               if (ioctl(con->fd, FIONREAD, &b)) {
7796 +                               if (ioctl(con->sock->fd, FIONREAD, &b)) {
7797                                         log_error_write(srv, __FILE__, __LINE__, "ss",
7798                                                         "ioctl() failed", strerror(errno));
7799                                 }
7800                                 if (b > 0) {
7801                                         char buf[1024];
7802                                         log_error_write(srv, __FILE__, __LINE__, "sdd",
7803 -                                                       "CLOSE-read()", con->fd, b);
7804 -                                       
7805 +                                                       "CLOSE-read()", con->sock->fd, b);
7806 +
7807                                         /* */
7808 -                                       read(con->fd, buf, sizeof(buf));
7809 +                                       read(con->sock->fd, buf, sizeof(buf));
7810                                 } else {
7811                                         /* nothing to read */
7812 -                                       
7813 +
7814                                         con->close_timeout_ts = 0;
7815                                 }
7816                         } else {
7817                                 con->close_timeout_ts = 0;
7818                         }
7819 -                       
7820 +
7821                         if (srv->cur_ts - con->close_timeout_ts > 1) {
7822                                 connection_close(srv, con);
7823 -                               
7824 +
7825                                 if (srv->srvconf.log_state_handling) {
7826 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
7827 -                                                       "connection closed for fd", con->fd);
7828 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
7829 +                                                       "connection closed for fd", con->sock->fd);
7830                                 }
7831                         }
7832 -                       
7833 +
7834                         break;
7835                 case CON_STATE_READ_POST:
7836                 case CON_STATE_READ:
7837                         if (srv->srvconf.log_state_handling) {
7838 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7839 -                                               "state for fd", con->fd, connection_get_state(con->state));
7840 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7841 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7842                         }
7843 -                       
7844 +
7845                         connection_handle_read_state(srv, con);
7846                         break;
7847                 case CON_STATE_WRITE:
7848                         if (srv->srvconf.log_state_handling) {
7849 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7850 -                                               "state for fd", con->fd, connection_get_state(con->state));
7851 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7852 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7853                         }
7854 -                       
7855 +
7856                         /* only try to write if we have something in the queue */
7857                         if (!chunkqueue_is_empty(con->write_queue)) {
7858  #if 0
7859                                 log_error_write(srv, __FILE__, __LINE__, "dsd",
7860 -                                               con->fd,
7861 +                                               con->sock->fd,
7862                                                 "packets to write:",
7863                                                 con->write_queue->used);
7864  #endif
7865 @@ -1586,17 +1474,17 @@
7866                         if (!chunkqueue_is_empty(con->write_queue) && con->is_writable) {
7867                                 if (-1 == connection_handle_write(srv, con)) {
7868                                         log_error_write(srv, __FILE__, __LINE__, "ds",
7869 -                                                       con->fd,
7870 +                                                       con->sock->fd,
7871                                                         "handle write failed.");
7872                                         connection_set_state(srv, con, CON_STATE_ERROR);
7873                                 } else if (con->state == CON_STATE_WRITE) {
7874                                         con->write_request_ts = srv->cur_ts;
7875                                 }
7876                         }
7877 -                       
7878 +
7879                         break;
7880                 case CON_STATE_ERROR: /* transient */
7881 -                       
7882 +
7883                         /* even if the connection was drop we still have to write it to the access log */
7884                         if (con->http_status) {
7885                                 plugins_call_handle_request_done(srv, con);
7886 @@ -1604,28 +1492,28 @@
7887  #ifdef USE_OPENSSL
7888                         if (srv_sock->is_ssl) {
7889                                 int ret;
7890 -                               switch ((ret = SSL_shutdown(con->ssl))) {
7891 +                               switch ((ret = SSL_shutdown(con->sock->ssl))) {
7892                                 case 1:
7893                                         /* ok */
7894                                         break;
7895                                 case 0:
7896 -                                       SSL_shutdown(con->ssl);
7897 +                                       SSL_shutdown(con->sock->ssl);
7898                                         break;
7899                                 default:
7900 -                                       log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:", 
7901 -                                                       SSL_get_error(con->ssl, ret), 
7902 +                                       log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
7903 +                                                       SSL_get_error(con->sock->ssl, ret),
7904                                                         ERR_error_string(ERR_get_error(), NULL));
7905                                         return -1;
7906                                 }
7907                         }
7908  #endif
7909 -                       
7910 +
7911                         switch(con->mode) {
7912                         case DIRECT:
7913  #if 0
7914 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
7915 -                                               "emergency exit: direct", 
7916 -                                               con->fd);
7917 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
7918 +                                               "emergency exit: direct",
7919 +                                               con->sock->fd);
7920  #endif
7921                                 break;
7922                         default:
7923 @@ -1639,35 +1527,35 @@
7924                                 }
7925                                 break;
7926                         }
7927 -                       
7928 +
7929                         connection_reset(srv, con);
7930 -                       
7931 +
7932                         /* close the connection */
7933                         if ((con->keep_alive == 1) &&
7934 -                           (0 == shutdown(con->fd, SHUT_WR))) {
7935 +                           (0 == shutdown(con->sock->fd, SHUT_WR))) {
7936                                 con->close_timeout_ts = srv->cur_ts;
7937                                 connection_set_state(srv, con, CON_STATE_CLOSE);
7938 -                               
7939 +
7940                                 if (srv->srvconf.log_state_handling) {
7941 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
7942 -                                                       "shutdown for fd", con->fd);
7943 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
7944 +                                                       "shutdown for fd", con->sock->fd);
7945                                 }
7946                         } else {
7947                                 connection_close(srv, con);
7948                         }
7949 -                       
7950 +
7951                         con->keep_alive = 0;
7952 -                       
7953 +
7954                         srv->con_closed++;
7955 -                       
7956 +
7957                         break;
7958                 default:
7959 -                       log_error_write(srv, __FILE__, __LINE__, "sdd", 
7960 -                                       "unknown state:", con->fd, con->state);
7961 -                       
7962 +                       log_error_write(srv, __FILE__, __LINE__, "sdd",
7963 +                                       "unknown state:", con->sock->fd, con->state);
7964 +
7965                         break;
7966                 }
7967 -               
7968 +
7969                 if (done == -1) {
7970                         done = 0;
7971                 } else if (ostate == con->state) {
7972 @@ -1676,33 +1564,33 @@
7973         }
7974  
7975         if (srv->srvconf.log_state_handling) {
7976 -               log_error_write(srv, __FILE__, __LINE__, "sds", 
7977 -                               "state at exit:", 
7978 -                               con->fd,
7979 +               log_error_write(srv, __FILE__, __LINE__, "sds",
7980 +                               "state at exit:",
7981 +                               con->sock->fd,
7982                                 connection_get_state(con->state));
7983         }
7984 -       
7985 +
7986         switch(con->state) {
7987         case CON_STATE_READ_POST:
7988         case CON_STATE_READ:
7989         case CON_STATE_CLOSE:
7990 -               fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_IN);
7991 +               fdevent_event_add(srv->ev, con->sock, FDEVENT_IN);
7992                 break;
7993         case CON_STATE_WRITE:
7994 -               /* request write-fdevent only if we really need it 
7995 +               /* request write-fdevent only if we really need it
7996                  * - if we have data to write
7997 -                * - if the socket is not writable yet 
7998 +                * - if the socket is not writable yet
7999                  */
8000 -               if (!chunkqueue_is_empty(con->write_queue) && 
8001 +               if (!chunkqueue_is_empty(con->write_queue) &&
8002                     (con->is_writable == 0) &&
8003                     (con->traffic_limit_reached == 0)) {
8004 -                       fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_OUT);
8005 +                       fdevent_event_add(srv->ev, con->sock, FDEVENT_OUT);
8006                 } else {
8007 -                       fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
8008 +                       fdevent_event_del(srv->ev, con->sock);
8009                 }
8010                 break;
8011         default:
8012 -               fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
8013 +               fdevent_event_del(srv->ev, con->sock);
8014                 break;
8015         }
8016  
8017 --- ../lighttpd-1.4.11/src/crc32.h      2005-09-30 20:18:59.000000000 +0300
8018 +++ lighttpd-1.4.12/src/crc32.h 2006-07-16 00:26:04.000000000 +0300
8019 @@ -6,6 +6,7 @@
8020  #endif
8021  
8022  #include <sys/types.h>
8023 +#include <stdlib.h>
8024  
8025  #if defined HAVE_STDINT_H
8026  #include <stdint.h>
8027 @@ -13,6 +14,10 @@
8028  #include <inttypes.h>
8029  #endif
8030  
8031 +#ifdef _WIN32
8032 +#define uint32_t unsigned __int32
8033 +#endif
8034 +
8035  uint32_t generate_crc32c(char *string, size_t length);
8036  
8037  #endif
8038 --- ../lighttpd-1.4.11/src/data_array.c 2005-08-23 17:36:12.000000000 +0300
8039 +++ lighttpd-1.4.12/src/data_array.c    2006-07-16 00:26:04.000000000 +0300
8040 @@ -17,16 +17,16 @@
8041  
8042  static void data_array_free(data_unset *d) {
8043         data_array *ds = (data_array *)d;
8044 -       
8045 +
8046         buffer_free(ds->key);
8047         array_free(ds->value);
8048 -       
8049 +
8050         free(d);
8051  }
8052  
8053  static void data_array_reset(data_unset *d) {
8054         data_array *ds = (data_array *)d;
8055 -       
8056 +
8057         /* reused array elements */
8058         buffer_reset(ds->key);
8059         array_reset(ds->value);
8060 @@ -36,7 +36,7 @@
8061         UNUSED(dst);
8062  
8063         src->free(src);
8064 -       
8065 +
8066         return 0;
8067  }
8068  
8069 @@ -48,18 +48,18 @@
8070  
8071  data_array *data_array_init(void) {
8072         data_array *ds;
8073 -       
8074 +
8075         ds = calloc(1, sizeof(*ds));
8076 -       
8077 +
8078         ds->key = buffer_init();
8079         ds->value = array_init();
8080 -       
8081 +
8082         ds->copy = data_array_copy;
8083         ds->free = data_array_free;
8084         ds->reset = data_array_reset;
8085         ds->insert_dup = data_array_insert_dup;
8086         ds->print = data_array_print;
8087         ds->type = TYPE_ARRAY;
8088 -       
8089 +
8090         return ds;
8091  }
8092 --- ../lighttpd-1.4.11/src/data_config.c        2005-08-17 12:53:19.000000000 +0300
8093 +++ lighttpd-1.4.12/src/data_config.c   2006-07-16 00:26:03.000000000 +0300
8094 @@ -17,26 +17,26 @@
8095  
8096  static void data_config_free(data_unset *d) {
8097         data_config *ds = (data_config *)d;
8098 -       
8099 +
8100         buffer_free(ds->key);
8101         buffer_free(ds->op);
8102         buffer_free(ds->comp_key);
8103 -       
8104 +
8105         array_free(ds->value);
8106         array_free(ds->childs);
8107 -       
8108 +
8109         if (ds->string) buffer_free(ds->string);
8110  #ifdef HAVE_PCRE_H
8111         if (ds->regex) pcre_free(ds->regex);
8112         if (ds->regex_study) pcre_free(ds->regex_study);
8113  #endif
8114 -       
8115 +
8116         free(d);
8117  }
8118  
8119  static void data_config_reset(data_unset *d) {
8120         data_config *ds = (data_config *)d;
8121 -       
8122 +
8123         /* reused array elements */
8124         buffer_reset(ds->key);
8125         buffer_reset(ds->comp_key);
8126 @@ -45,9 +45,9 @@
8127  
8128  static int data_config_insert_dup(data_unset *dst, data_unset *src) {
8129         UNUSED(dst);
8130 -       
8131 +
8132         src->free(src);
8133 -       
8134 +
8135         return 0;
8136  }
8137  
8138 @@ -56,7 +56,7 @@
8139         array *a = (array *)ds->value;
8140         size_t i;
8141         size_t maxlen;
8142 -       
8143 +
8144         if (0 == ds->context_ndx) {
8145                 fprintf(stderr, "config {\n");
8146         }
8147 @@ -117,22 +117,22 @@
8148  
8149  data_config *data_config_init(void) {
8150         data_config *ds;
8151 -       
8152 +
8153         ds = calloc(1, sizeof(*ds));
8154 -       
8155 +
8156         ds->key = buffer_init();
8157         ds->op = buffer_init();
8158         ds->comp_key = buffer_init();
8159         ds->value = array_init();
8160         ds->childs = array_init();
8161         ds->childs->is_weakref = 1;
8162 -       
8163 +
8164         ds->copy = data_config_copy;
8165         ds->free = data_config_free;
8166         ds->reset = data_config_reset;
8167         ds->insert_dup = data_config_insert_dup;
8168         ds->print = data_config_print;
8169         ds->type = TYPE_CONFIG;
8170 -       
8171 +
8172         return ds;
8173  }
8174 --- ../lighttpd-1.4.11/src/data_count.c 2005-08-23 17:36:12.000000000 +0300
8175 +++ lighttpd-1.4.12/src/data_count.c    2006-07-16 00:26:03.000000000 +0300
8176 @@ -16,53 +16,53 @@
8177  
8178  static void data_count_free(data_unset *d) {
8179         data_count *ds = (data_count *)d;
8180 -       
8181 +
8182         buffer_free(ds->key);
8183 -       
8184 +
8185         free(d);
8186  }
8187  
8188  static void data_count_reset(data_unset *d) {
8189         data_count *ds = (data_count *)d;
8190 -       
8191 +
8192         buffer_reset(ds->key);
8193 -       
8194 +
8195         ds->count = 0;
8196  }
8197  
8198  static int data_count_insert_dup(data_unset *dst, data_unset *src) {
8199         data_count *ds_dst = (data_count *)dst;
8200         data_count *ds_src = (data_count *)src;
8201 -       
8202 +
8203         ds_dst->count += ds_src->count;
8204 -       
8205 +
8206         src->free(src);
8207 -       
8208 +
8209         return 0;
8210  }
8211  
8212  static void data_count_print(const data_unset *d, int depth) {
8213         data_count *ds = (data_count *)d;
8214         UNUSED(depth);
8215 -       
8216 +
8217         fprintf(stderr, "count(%d)", ds->count);
8218  }
8219  
8220  
8221  data_count *data_count_init(void) {
8222         data_count *ds;
8223 -       
8224 +
8225         ds = calloc(1, sizeof(*ds));
8226 -       
8227 +
8228         ds->key = buffer_init();
8229         ds->count = 1;
8230 -       
8231 +
8232         ds->copy = data_count_copy;
8233         ds->free = data_count_free;
8234         ds->reset = data_count_reset;
8235         ds->insert_dup = data_count_insert_dup;
8236         ds->print = data_count_print;
8237         ds->type = TYPE_COUNT;
8238 -       
8239 +
8240         return ds;
8241  }
8242 --- ../lighttpd-1.4.11/src/data_fastcgi.c       2005-08-23 17:36:12.000000000 +0300
8243 +++ lighttpd-1.4.12/src/data_fastcgi.c  2006-07-16 00:26:04.000000000 +0300
8244 @@ -17,53 +17,53 @@
8245  
8246  static void data_fastcgi_free(data_unset *d) {
8247         data_fastcgi *ds = (data_fastcgi *)d;
8248 -       
8249 +
8250         buffer_free(ds->key);
8251         buffer_free(ds->host);
8252 -       
8253 +
8254         free(d);
8255  }
8256  
8257  static void data_fastcgi_reset(data_unset *d) {
8258         data_fastcgi *ds = (data_fastcgi *)d;
8259 -       
8260 +
8261         buffer_reset(ds->key);
8262         buffer_reset(ds->host);
8263 -       
8264 +
8265  }
8266  
8267  static int data_fastcgi_insert_dup(data_unset *dst, data_unset *src) {
8268         UNUSED(dst);
8269  
8270         src->free(src);
8271 -       
8272 +
8273         return 0;
8274  }
8275  
8276  static void data_fastcgi_print(const data_unset *d, int depth) {
8277         data_fastcgi *ds = (data_fastcgi *)d;
8278         UNUSED(depth);
8279 -       
8280 +
8281         fprintf(stderr, "fastcgi(%s)", ds->host->ptr);
8282  }
8283  
8284  
8285  data_fastcgi *data_fastcgi_init(void) {
8286         data_fastcgi *ds;
8287 -       
8288 +
8289         ds = calloc(1, sizeof(*ds));
8290 -       
8291 +
8292         ds->key = buffer_init();
8293         ds->host = buffer_init();
8294         ds->port = 0;
8295         ds->is_disabled = 0;
8296 -       
8297 +
8298         ds->copy = data_fastcgi_copy;
8299         ds->free = data_fastcgi_free;
8300         ds->reset = data_fastcgi_reset;
8301         ds->insert_dup = data_fastcgi_insert_dup;
8302         ds->print = data_fastcgi_print;
8303         ds->type = TYPE_FASTCGI;
8304 -       
8305 +
8306         return ds;
8307  }
8308 --- ../lighttpd-1.4.11/src/data_integer.c       2005-08-23 17:36:12.000000000 +0300
8309 +++ lighttpd-1.4.12/src/data_integer.c  2006-07-16 00:26:03.000000000 +0300
8310 @@ -16,15 +16,15 @@
8311  
8312  static void data_integer_free(data_unset *d) {
8313         data_integer *ds = (data_integer *)d;
8314 -       
8315 +
8316         buffer_free(ds->key);
8317 -       
8318 +
8319         free(d);
8320  }
8321  
8322  static void data_integer_reset(data_unset *d) {
8323         data_integer *ds = (data_integer *)d;
8324 -       
8325 +
8326         /* reused integer elements */
8327         buffer_reset(ds->key);
8328         ds->value = 0;
8329 @@ -32,9 +32,9 @@
8330  
8331  static int data_integer_insert_dup(data_unset *dst, data_unset *src) {
8332         UNUSED(dst);
8333 -       
8334 +
8335         src->free(src);
8336 -       
8337 +
8338         return 0;
8339  }
8340  
8341 @@ -48,18 +48,18 @@
8342  
8343  data_integer *data_integer_init(void) {
8344         data_integer *ds;
8345 -       
8346 +
8347         ds = calloc(1, sizeof(*ds));
8348 -       
8349 +
8350         ds->key = buffer_init();
8351         ds->value = 0;
8352 -       
8353 +
8354         ds->copy = data_integer_copy;
8355         ds->free = data_integer_free;
8356         ds->reset = data_integer_reset;
8357         ds->insert_dup = data_integer_insert_dup;
8358         ds->print = data_integer_print;
8359         ds->type = TYPE_INTEGER;
8360 -       
8361 +
8362         return ds;
8363  }
8364 --- ../lighttpd-1.4.11/src/data_string.c        2005-08-23 17:36:12.000000000 +0300
8365 +++ lighttpd-1.4.12/src/data_string.c   2006-07-16 00:26:04.000000000 +0300
8366 @@ -17,16 +17,16 @@
8367  
8368  static void data_string_free(data_unset *d) {
8369         data_string *ds = (data_string *)d;
8370 -       
8371 +
8372         buffer_free(ds->key);
8373         buffer_free(ds->value);
8374 -       
8375 +
8376         free(d);
8377  }
8378  
8379  static void data_string_reset(data_unset *d) {
8380         data_string *ds = (data_string *)d;
8381 -       
8382 +
8383         /* reused array elements */
8384         buffer_reset(ds->key);
8385         buffer_reset(ds->value);
8386 @@ -35,23 +35,23 @@
8387  static int data_string_insert_dup(data_unset *dst, data_unset *src) {
8388         data_string *ds_dst = (data_string *)dst;
8389         data_string *ds_src = (data_string *)src;
8390 -       
8391 +
8392         if (ds_dst->value->used) {
8393                 buffer_append_string(ds_dst->value, ", ");
8394                 buffer_append_string_buffer(ds_dst->value, ds_src->value);
8395         } else {
8396                 buffer_copy_string_buffer(ds_dst->value, ds_src->value);
8397         }
8398 -       
8399 +
8400         src->free(src);
8401 -       
8402 +
8403         return 0;
8404  }
8405  
8406  static int data_response_insert_dup(data_unset *dst, data_unset *src) {
8407         data_string *ds_dst = (data_string *)dst;
8408         data_string *ds_src = (data_string *)src;
8409 -       
8410 +
8411         if (ds_dst->value->used) {
8412                 buffer_append_string(ds_dst->value, "\r\n");
8413                 buffer_append_string_buffer(ds_dst->value, ds_dst->key);
8414 @@ -60,9 +60,9 @@
8415         } else {
8416                 buffer_copy_string_buffer(ds_dst->value, ds_src->value);
8417         }
8418 -       
8419 +
8420         src->free(src);
8421 -       
8422 +
8423         return 0;
8424  }
8425  
8426 @@ -77,28 +77,28 @@
8427  
8428  data_string *data_string_init(void) {
8429         data_string *ds;
8430 -       
8431 +
8432         ds = calloc(1, sizeof(*ds));
8433         assert(ds);
8434 -       
8435 +
8436         ds->key = buffer_init();
8437         ds->value = buffer_init();
8438 -       
8439 +
8440         ds->copy = data_string_copy;
8441         ds->free = data_string_free;
8442         ds->reset = data_string_reset;
8443         ds->insert_dup = data_string_insert_dup;
8444         ds->print = data_string_print;
8445         ds->type = TYPE_STRING;
8446 -       
8447 +
8448         return ds;
8449  }
8450  
8451  data_string *data_response_init(void) {
8452         data_string *ds;
8453 -       
8454 +
8455         ds = data_string_init();
8456         ds->insert_dup = data_response_insert_dup;
8457 -       
8458 +
8459         return ds;
8460  }
8461 --- ../lighttpd-1.4.11/src/etag.c       2005-08-11 01:26:40.000000000 +0300
8462 +++ lighttpd-1.4.12/src/etag.c  2006-07-18 13:03:40.000000000 +0300
8463 @@ -4,7 +4,7 @@
8464  #include "etag.h"
8465  
8466  int etag_is_equal(buffer *etag, const char *matches) {
8467 -       if (0 == strcmp(etag->ptr, matches)) return 1;
8468 +       if (buffer_is_equal_string(etag, matches, strlen(matches))) return 1;
8469         return 0;
8470  }
8471  
8472 @@ -14,19 +14,19 @@
8473         buffer_append_off_t(etag, st->st_size);
8474         buffer_append_string_len(etag, CONST_STR_LEN("-"));
8475         buffer_append_long(etag, st->st_mtime);
8476 -       
8477 +
8478         return 0;
8479  }
8480  
8481  int etag_mutate(buffer *mut, buffer *etag) {
8482         size_t h, i;
8483 -       
8484 +
8485         for (h=0, i=0; i < etag->used; ++i) h = (h<<5)^(h>>27)^(etag->ptr[i]);
8486 -       
8487 +
8488         buffer_reset(mut);
8489         buffer_copy_string_len(mut, CONST_STR_LEN("\""));
8490         buffer_append_long(mut, h);
8491         buffer_append_string_len(mut, CONST_STR_LEN("\""));
8492 -       
8493 +
8494         return 0;
8495  }
8496 --- ../lighttpd-1.4.11/src/etag.h       2005-08-11 01:26:40.000000000 +0300
8497 +++ lighttpd-1.4.12/src/etag.h  2006-07-16 00:26:03.000000000 +0300
8498 @@ -3,13 +3,12 @@
8499  
8500  #include <sys/types.h>
8501  #include <sys/stat.h>
8502 -#include <unistd.h>
8503  
8504  #include "buffer.h"
8505  
8506  int etag_is_equal(buffer *etag, const char *matches);
8507  int etag_create(buffer *etag, struct stat *st);
8508  int etag_mutate(buffer *mut, buffer *etag);
8509 -       
8510 +
8511  
8512  #endif
8513 --- ../lighttpd-1.4.11/src/fastcgi.h    2005-08-11 01:26:40.000000000 +0300
8514 +++ lighttpd-1.4.12/src/fastcgi.h       2006-07-16 00:26:03.000000000 +0300
8515 @@ -1,4 +1,4 @@
8516 -/* 
8517 +/*
8518   * fastcgi.h --
8519   *
8520   *     Defines for the FastCGI protocol.
8521 @@ -123,7 +123,7 @@
8522  
8523  
8524  typedef struct {
8525 -    unsigned char type;    
8526 +    unsigned char type;
8527      unsigned char reserved[7];
8528  } FCGI_UnknownTypeBody;
8529  
8530 --- ../lighttpd-1.4.11/src/fdevent.c    2005-11-15 10:51:05.000000000 +0200
8531 +++ lighttpd-1.4.12/src/fdevent.c       2006-07-18 13:03:40.000000000 +0300
8532 @@ -2,7 +2,6 @@
8533  
8534  #include "settings.h"
8535  
8536 -#include <unistd.h>
8537  #include <stdlib.h>
8538  #include <string.h>
8539  #include <errno.h>
8540 @@ -11,60 +10,116 @@
8541  
8542  #include "fdevent.h"
8543  #include "buffer.h"
8544 +#include "log.h"
8545 +
8546 +#include "sys-socket.h"
8547 +
8548 +fdevent_revent *fdevent_revent_init(void) {
8549 +       STRUCT_INIT(fdevent_revent, revent);
8550 +
8551 +       return revent;
8552 +}
8553 +
8554 +void fdevent_revent_free(fdevent_revent *revent) {
8555 +       if (!revent) return;
8556 +
8557 +       free(revent);
8558 +}
8559 +
8560 +fdevent_revents *fdevent_revents_init(void) {
8561 +       STRUCT_INIT(fdevent_revents, revents);
8562 +
8563 +       return revents;
8564 +}
8565 +
8566 +void fdevent_revents_reset(fdevent_revents *revents) {
8567 +       if (!revents) return;
8568 +
8569 +       revents->used = 0;
8570 +}
8571 +
8572 +void fdevent_revents_add(fdevent_revents *revents, int fd, int events) {
8573 +       fdevent_revent *revent;
8574 +
8575 +       if (revents->used == revents->size) {
8576 +               /* resize the events-array */
8577 +               revents->ptr = realloc(revents->ptr, (revents->size + 1) * sizeof(*(revents->ptr)));
8578 +               revents->ptr[revents->size++] = fdevent_revent_init();
8579 +       }
8580 +
8581 +       revent = revents->ptr[revents->used++];
8582 +       revent->fd = fd;
8583 +       revent->revents = events;
8584 +}
8585 +
8586 +void fdevent_revents_free(fdevent_revents *revents) {
8587 +       size_t i;
8588 +       
8589 +       if (!revents) return;
8590 +
8591 +       if (revents->size) {
8592 +               for (i = 0; i < revents->size; i++) {
8593 +                       fdevent_revent_free(revents->ptr[i]);
8594 +               }
8595 +
8596 +               free(revents->ptr);
8597 +       }
8598 +       free(revents);
8599 +}
8600  
8601  fdevents *fdevent_init(size_t maxfds, fdevent_handler_t type) {
8602         fdevents *ev;
8603 -       
8604 +
8605         ev = calloc(1, sizeof(*ev));
8606         ev->fdarray = calloc(maxfds, sizeof(*ev->fdarray));
8607         ev->maxfds = maxfds;
8608 -       
8609 +
8610         switch(type) {
8611         case FDEVENT_HANDLER_POLL:
8612                 if (0 != fdevent_poll_init(ev)) {
8613 -                       fprintf(stderr, "%s.%d: event-handler poll failed\n", 
8614 +                       fprintf(stderr, "%s.%d: event-handler poll failed\n",
8615                                 __FILE__, __LINE__);
8616 -                       
8617 +
8618                         return NULL;
8619                 }
8620                 break;
8621         case FDEVENT_HANDLER_SELECT:
8622                 if (0 != fdevent_select_init(ev)) {
8623 -                       fprintf(stderr, "%s.%d: event-handler select failed\n", 
8624 +                       fprintf(stderr, "%s.%d: event-handler select failed\n",
8625                                 __FILE__, __LINE__);
8626                         return NULL;
8627                 }
8628                 break;
8629         case FDEVENT_HANDLER_LINUX_RTSIG:
8630                 if (0 != fdevent_linux_rtsig_init(ev)) {
8631 -                       fprintf(stderr, "%s.%d: event-handler linux-rtsig failed, try to set server.event-handler = \"poll\" or \"select\"\n", 
8632 +                       fprintf(stderr, "%s.%d: event-handler linux-rtsig failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8633                                 __FILE__, __LINE__);
8634                         return NULL;
8635                 }
8636                 break;
8637         case FDEVENT_HANDLER_LINUX_SYSEPOLL:
8638                 if (0 != fdevent_linux_sysepoll_init(ev)) {
8639 -                       fprintf(stderr, "%s.%d: event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"\n", 
8640 +                       fprintf(stderr, "%s.%d: event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8641                                 __FILE__, __LINE__);
8642                         return NULL;
8643                 }
8644                 break;
8645         case FDEVENT_HANDLER_SOLARIS_DEVPOLL:
8646                 if (0 != fdevent_solaris_devpoll_init(ev)) {
8647 -                       fprintf(stderr, "%s.%d: event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"\n", 
8648 +                       fprintf(stderr, "%s.%d: event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8649                                 __FILE__, __LINE__);
8650                         return NULL;
8651                 }
8652                 break;
8653         case FDEVENT_HANDLER_FREEBSD_KQUEUE:
8654                 if (0 != fdevent_freebsd_kqueue_init(ev)) {
8655 -                       fprintf(stderr, "%s.%d: event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"\n", 
8656 +                       fprintf(stderr, "%s.%d: event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8657                                 __FILE__, __LINE__);
8658                         return NULL;
8659                 }
8660                 break;
8661         default:
8662 -               fprintf(stderr, "%s.%d: event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"\n", 
8663 +               fprintf(stderr, "%s.%d: event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"\n",
8664                         __FILE__, __LINE__);
8665                 return NULL;
8666         }
8667 @@ -75,28 +130,29 @@
8668  void fdevent_free(fdevents *ev) {
8669         size_t i;
8670         if (!ev) return;
8671 -       
8672 +
8673         if (ev->free) ev->free(ev);
8674 -       
8675 +
8676         for (i = 0; i < ev->maxfds; i++) {
8677                 if (ev->fdarray[i]) free(ev->fdarray[i]);
8678         }
8679 -       
8680 +
8681         free(ev->fdarray);
8682         free(ev);
8683  }
8684  
8685  int fdevent_reset(fdevents *ev) {
8686         if (ev->reset) return ev->reset(ev);
8687 -       
8688 +
8689         return 0;
8690  }
8691  
8692  fdnode *fdnode_init() {
8693         fdnode *fdn;
8694 -       
8695 +
8696         fdn = calloc(1, sizeof(*fdn));
8697         fdn->fd = -1;
8698 +
8699         return fdn;
8700  }
8701  
8702 @@ -104,48 +160,40 @@
8703         free(fdn);
8704  }
8705  
8706 -int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx) {
8707 +int fdevent_register(fdevents *ev, iosocket *sock, fdevent_handler handler, void *ctx) {
8708         fdnode *fdn;
8709 -       
8710 +
8711         fdn = fdnode_init();
8712         fdn->handler = handler;
8713 -       fdn->fd      = fd;
8714 +       fdn->fd      = sock->fd;
8715         fdn->ctx     = ctx;
8716 -       
8717 -       ev->fdarray[fd] = fdn;
8718 +
8719 +       ev->fdarray[sock->fd] = fdn;
8720  
8721         return 0;
8722  }
8723  
8724 -int fdevent_unregister(fdevents *ev, int fd) {
8725 +int fdevent_unregister(fdevents *ev, iosocket *sock) {
8726         fdnode *fdn;
8727          if (!ev) return 0;
8728 -       fdn = ev->fdarray[fd];
8729 -       
8730 +       fdn = ev->fdarray[sock->fd];
8731 +
8732         fdnode_free(fdn);
8733 -       
8734 -       ev->fdarray[fd] = NULL;
8735 -       
8736 +
8737 +       ev->fdarray[sock->fd] = NULL;
8738 +
8739         return 0;
8740  }
8741  
8742 -int fdevent_event_del(fdevents *ev, int *fde_ndx, int fd) {
8743 -       int fde = fde_ndx ? *fde_ndx : -1;
8744 -       
8745 -       if (ev->event_del) fde = ev->event_del(ev, fde, fd);
8746 -       
8747 -       if (fde_ndx) *fde_ndx = fde;
8748 -       
8749 +int fdevent_event_del(fdevents *ev, iosocket *sock) {
8750 +       if (ev->event_del) ev->event_del(ev, sock);
8751 +
8752         return 0;
8753  }
8754  
8755 -int fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int events) {
8756 -       int fde = fde_ndx ? *fde_ndx : -1;
8757 -       
8758 -       if (ev->event_add) fde = ev->event_add(ev, fde, fd, events);
8759 -       
8760 -       if (fde_ndx) *fde_ndx = fde;
8761 -       
8762 +int fdevent_event_add(fdevents *ev, iosocket *sock, int events) {
8763 +       if (ev->event_add) ev->event_add(ev, sock, events);
8764 +
8765         return 0;
8766  }
8767  
8768 @@ -154,49 +202,41 @@
8769         return ev->poll(ev, timeout_ms);
8770  }
8771  
8772 -int fdevent_event_get_revent(fdevents *ev, size_t ndx) {
8773 -       if (ev->event_get_revent == NULL) SEGFAULT();
8774 -       
8775 -       return ev->event_get_revent(ev, ndx);
8776 -}
8777 +int fdevent_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
8778 +       size_t i;
8779  
8780 -int fdevent_event_get_fd(fdevents *ev, size_t ndx) {
8781 -       if (ev->event_get_fd == NULL) SEGFAULT();
8782 -       
8783 -       return ev->event_get_fd(ev, ndx);
8784 -}
8785 +       if (ev->get_revents == NULL) SEGFAULT();
8786  
8787 -fdevent_handler fdevent_get_handler(fdevents *ev, int fd) {
8788 -       if (ev->fdarray[fd] == NULL) SEGFAULT();
8789 -       if (ev->fdarray[fd]->fd != fd) SEGFAULT();
8790 -       
8791 -       return ev->fdarray[fd]->handler;
8792 -}
8793 +       fdevent_revents_reset(revents);
8794  
8795 -void * fdevent_get_context(fdevents *ev, int fd) {
8796 -       if (ev->fdarray[fd] == NULL) SEGFAULT();
8797 -       if (ev->fdarray[fd]->fd != fd) SEGFAULT();
8798 -       
8799 -       return ev->fdarray[fd]->ctx;
8800 +       ev->get_revents(ev, event_count, revents);
8801 +
8802 +       /* patch the event handlers */
8803 +       for (i = 0; i < event_count; i++) {
8804 +               fdevent_revent *r = revents->ptr[i];
8805 +
8806 +               r->handler = ev->fdarray[r->fd]->handler;
8807 +               r->context = ev->fdarray[r->fd]->ctx;
8808 +       }
8809 +
8810 +       return 0;
8811  }
8812  
8813 -int fdevent_fcntl_set(fdevents *ev, int fd) {
8814 +int fdevent_fcntl_set(fdevents *ev, iosocket *sock) {
8815 +#ifdef _WIN32
8816 +       int i = 1;
8817 +#endif
8818  #ifdef FD_CLOEXEC
8819         /* close fd on exec (cgi) */
8820 -       fcntl(fd, F_SETFD, FD_CLOEXEC);
8821 +       fcntl(sock->fd, F_SETFD, FD_CLOEXEC);
8822  #endif
8823 -       if ((ev) && (ev->fcntl_set)) return ev->fcntl_set(ev, fd);
8824 -#ifdef O_NONBLOCK      
8825 -       return fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
8826 +       if ((ev) && (ev->fcntl_set)) return ev->fcntl_set(ev, sock->fd);
8827 +#ifdef O_NONBLOCK
8828 +       return fcntl(sock->fd, F_SETFL, O_NONBLOCK | O_RDWR);
8829 +#elif defined _WIN32
8830 +       return ioctlsocket(sock->fd, FIONBIO, &i);
8831  #else
8832         return 0;
8833  #endif
8834  }
8835  
8836 -
8837 -int fdevent_event_next_fdndx(fdevents *ev, int ndx) {
8838 -       if (ev->event_next_fdndx) return ev->event_next_fdndx(ev, ndx);
8839 -       
8840 -       return -1;
8841 -}
8842 -
8843 --- ../lighttpd-1.4.11/src/fdevent.h    2005-09-27 11:26:33.000000000 +0300
8844 +++ lighttpd-1.4.12/src/fdevent.h       2006-07-18 13:03:40.000000000 +0300
8845 @@ -7,6 +7,9 @@
8846  #include "settings.h"
8847  #include "bitset.h"
8848  
8849 +#include "iosocket.h"
8850 +#include "array-static.h"
8851 +
8852  /* select event-system */
8853  
8854  #if defined(HAVE_EPOLL_CTL) && defined(HAVE_SYS_EPOLL_H)
8855 @@ -17,13 +20,13 @@
8856  # include <sys/epoll.h>
8857  #endif
8858  
8859 -/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes 
8860 +/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes
8861   * under /usr/include/sys/ */
8862  #if defined HAVE_POLL && (defined(HAVE_SYS_POLL_H) || defined(HAVE_POLL_H))
8863  # define USE_POLL
8864  # ifdef HAVE_POLL_H
8865  #  include <poll.h>
8866 -# else 
8867 +# else
8868  #  include <sys/poll.h>
8869  # endif
8870  # if defined HAVE_SIGTIMEDWAIT && defined(__linux__)
8871 @@ -31,9 +34,11 @@
8872  #  include <signal.h>
8873  # endif
8874  #endif
8875 -
8876 +#ifdef _WIN32
8877 +# define HAVE_SELECT
8878 +#endif
8879  #if defined HAVE_SELECT
8880 -# ifdef __WIN32
8881 +# ifdef _WIN32
8882  #  include <winsock2.h>
8883  # endif
8884  # define USE_SELECT
8885 @@ -67,14 +72,14 @@
8886  #define FDEVENT_HUP    BV(4)
8887  #define FDEVENT_NVAL   BV(5)
8888  
8889 -typedef enum { FD_EVENT_TYPE_UNSET = -1, 
8890 -               FD_EVENT_TYPE_CONNECTION, 
8891 -               FD_EVENT_TYPE_FCGI_CONNECTION, 
8892 -               FD_EVENT_TYPE_DIRWATCH, 
8893 -               FD_EVENT_TYPE_CGI_CONNECTION 
8894 +typedef enum { FD_EVENT_TYPE_UNSET = -1,
8895 +               FD_EVENT_TYPE_CONNECTION,
8896 +               FD_EVENT_TYPE_FCGI_CONNECTION,
8897 +               FD_EVENT_TYPE_DIRWATCH,
8898 +               FD_EVENT_TYPE_CGI_CONNECTION
8899  } fd_event_t;
8900  
8901 -typedef enum { FDEVENT_HANDLER_UNSET, 
8902 +typedef enum { FDEVENT_HANDLER_UNSET,
8903                 FDEVENT_HANDLER_SELECT,
8904                 FDEVENT_HANDLER_POLL,
8905                 FDEVENT_HANDLER_LINUX_RTSIG,
8906 @@ -86,7 +91,7 @@
8907  
8908  /**
8909   * a mapping from fd to connection structure
8910 - * 
8911 + *
8912   */
8913  typedef struct {
8914         int fd;                  /**< the fd */
8915 @@ -96,43 +101,51 @@
8916         int revents;
8917  } fd_conn;
8918  
8919 +ARRAY_STATIC_DEF(fd_conn_buffer, fd_conn, );
8920 +
8921 +/**
8922 + * revents
8923 + */
8924  typedef struct {
8925 -       fd_conn *ptr;
8926 -       
8927 -       size_t size;
8928 -       size_t used;
8929 -} fd_conn_buffer;
8930 +       int fd;
8931 +       int revents;
8932 +
8933 +       fdevent_handler handler;
8934 +       void *context;
8935 +} fdevent_revent;
8936 +
8937 +ARRAY_STATIC_DEF(fdevent_revents, fdevent_revent, );
8938  
8939  /**
8940   * array of unused fd's
8941 - * 
8942 + *
8943   */
8944  
8945  typedef struct _fdnode {
8946 -       fdevent_handler handler;
8947 -       void *ctx;
8948 -       int fd;
8949 -       
8950 +       fdevent_handler handler; /* who handles the events for this fd */
8951 +       void *ctx;               /* opaque pointer which is passed as 3rd parameter to the handler */
8952 +       int fd;                  /* fd */
8953 +
8954         struct _fdnode *prev, *next;
8955  } fdnode;
8956  
8957  typedef struct {
8958         int *ptr;
8959 -       
8960 +
8961         size_t used;
8962         size_t size;
8963  } buffer_int;
8964  
8965  /**
8966   * fd-event handler for select(), poll() and rt-signals on Linux 2.4
8967 - * 
8968 + *
8969   */
8970  typedef struct fdevents {
8971         fdevent_handler_t type;
8972 -       
8973 -       fdnode **fdarray;
8974 +
8975 +       fdnode **fdarray; /* a list of fdnodes */
8976         size_t maxfds;
8977 -       
8978 +
8979  #ifdef USE_LINUX_SIGIO
8980         int in_sigio;
8981         int signum;
8982 @@ -146,21 +159,21 @@
8983  #endif
8984  #ifdef USE_POLL
8985         struct pollfd *pollfds;
8986 -       
8987 +
8988         size_t size;
8989         size_t used;
8990 -       
8991 +
8992         buffer_int unused;
8993  #endif
8994  #ifdef USE_SELECT
8995         fd_set select_read;
8996         fd_set select_write;
8997         fd_set select_error;
8998 -       
8999 +
9000         fd_set select_set_read;
9001         fd_set select_set_write;
9002         fd_set select_set_error;
9003 -       
9004 +
9005         int select_max_fd;
9006  #endif
9007  #ifdef USE_SOLARIS_DEVPOLL
9008 @@ -177,16 +190,13 @@
9009  #endif
9010         int (*reset)(struct fdevents *ev);
9011         void (*free)(struct fdevents *ev);
9012 -       
9013 -       int (*event_add)(struct fdevents *ev, int fde_ndx, int fd, int events);
9014 -       int (*event_del)(struct fdevents *ev, int fde_ndx, int fd);
9015 -       int (*event_get_revent)(struct fdevents *ev, size_t ndx);
9016 -       int (*event_get_fd)(struct fdevents *ev, size_t ndx);
9017 -       
9018 -       int (*event_next_fdndx)(struct fdevents *ev, int ndx);
9019 -       
9020 +
9021 +       int (*event_add)(struct fdevents *ev, iosocket *sock, int events);
9022 +       int (*event_del)(struct fdevents *ev, iosocket *sock);
9023 +       int (*get_revents)(struct fdevents *ev, size_t event_count, fdevent_revents *revents);
9024 +
9025         int (*poll)(struct fdevents *ev, int timeout_ms);
9026 -       
9027 +
9028         int (*fcntl_set)(struct fdevents *ev, int fd);
9029  } fdevents;
9030  
9031 @@ -194,22 +204,44 @@
9032  int fdevent_reset(fdevents *ev);
9033  void fdevent_free(fdevents *ev);
9034  
9035 -int fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int events);
9036 -int fdevent_event_del(fdevents *ev, int *fde_ndx, int fd);
9037 -int fdevent_event_get_revent(fdevents *ev, size_t ndx);
9038 -int fdevent_event_get_fd(fdevents *ev, size_t ndx);
9039 -fdevent_handler fdevent_get_handler(fdevents *ev, int fd);
9040 -void * fdevent_get_context(fdevents *ev, int fd);
9041 +/**
9042 + * call the plugin for the number of available events
9043 + */
9044 +int fdevent_poll(fdevents *ev, int timeout_ms);
9045 +/**
9046 + * get all available events
9047 + */
9048 +int fdevent_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents);
9049  
9050 -int fdevent_event_next_fdndx(fdevents *ev, int ndx);
9051 +/**
9052 + * add or remove a fd to the handled-pool
9053 + */
9054 +int fdevent_register(fdevents *ev, iosocket *sock, fdevent_handler handler, void *ctx);
9055 +int fdevent_unregister(fdevents *ev, iosocket *sock);
9056  
9057 -int fdevent_poll(fdevents *ev, int timeout_ms);
9058 +/**
9059 + * add a event to a registered fd
9060 + */
9061 +int fdevent_event_add(fdevents *ev, iosocket *sock, int events);
9062 +int fdevent_event_del(fdevents *ev, iosocket *sock);
9063 +
9064 +/**
9065 + * set non-blocking
9066 + */
9067 +int fdevent_fcntl_set(fdevents *ev, iosocket *sock);
9068 +
9069 +fdevent_revents *fdevent_revents_init(void);
9070 +void fdevent_revents_reset(fdevent_revents *revents);
9071 +void fdevent_revents_add(fdevent_revents *revents, int fd, int events);
9072 +void fdevent_revents_free(fdevent_revents *revents);
9073  
9074 -int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx);
9075 -int fdevent_unregister(fdevents *ev, int fd);
9076 +fdevent_revent *fdevent_revent_init(void);
9077 +void fdevent_revent_free(fdevent_revent *revent);
9078  
9079 -int fdevent_fcntl_set(fdevents *ev, int fd);
9080  
9081 +/**
9082 + * plugin init
9083 + */
9084  int fdevent_select_init(fdevents *ev);
9085  int fdevent_poll_init(fdevents *ev);
9086  int fdevent_linux_rtsig_init(fdevents *ev);
9087 --- ../lighttpd-1.4.11/src/fdevent_freebsd_kqueue.c     2005-09-01 10:46:24.000000000 +0300
9088 +++ lighttpd-1.4.12/src/fdevent_freebsd_kqueue.c        2006-07-16 00:26:03.000000000 +0300
9089 @@ -1,6 +1,5 @@
9090  #include <sys/types.h>
9091  
9092 -#include <unistd.h>
9093  #include <stdlib.h>
9094  #include <stdio.h>
9095  #include <string.h>
9096 @@ -48,7 +47,7 @@
9097  
9098                 return -1;
9099         }
9100 -       
9101 +
9102         return -1;
9103  }
9104  
9105 @@ -65,7 +64,7 @@
9106  
9107         ts.tv_sec  = 0;
9108         ts.tv_nsec = 0;
9109 -       
9110 +
9111         ret = kevent(ev->kq_fd,
9112                      &kev, 1,
9113                      NULL, 0,
9114 @@ -77,7 +76,7 @@
9115  
9116                 return -1;
9117         }
9118 -       
9119 +
9120         if (filter == EVFILT_READ) {
9121                 bitset_set_bit(ev->kq_bevents, fd);
9122         } else {
9123 @@ -124,7 +123,7 @@
9124         } else if (e == EVFILT_WRITE) {
9125                 events |= FDEVENT_OUT;
9126         }
9127 -       
9128 +
9129         e = ev->kq_results[ndx].flags;
9130  
9131         if (e & EV_EOF) {
9132 @@ -152,10 +151,10 @@
9133         if (-1 == (ev->kq_fd = kqueue())) {
9134                 fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9135                         __FILE__, __LINE__, strerror(errno));
9136 -               
9137 +
9138                 return -1;
9139         }
9140 -       
9141 +
9142         return 0;
9143  }
9144  
9145 @@ -186,7 +185,7 @@
9146         if (-1 == (ev->kq_fd = kqueue())) {
9147                 fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9148                         __FILE__, __LINE__, strerror(errno));
9149 -               
9150 +
9151                 return -1;
9152         }
9153  
9154 --- ../lighttpd-1.4.11/src/fdevent_linux_rtsig.c        2005-11-21 19:56:11.000000000 +0200
9155 +++ lighttpd-1.4.12/src/fdevent_linux_rtsig.c   2006-07-18 13:03:40.000000000 +0300
9156 @@ -1,6 +1,5 @@
9157  #include <sys/types.h>
9158  
9159 -#include <unistd.h>
9160  #include <stdlib.h>
9161  #include <stdio.h>
9162  #include <string.h>
9163 @@ -14,6 +13,8 @@
9164  #include "fdevent.h"
9165  #include "settings.h"
9166  #include "buffer.h"
9167 +#include "sys-process.h"
9168 +#include "log.h"
9169  
9170  #ifdef USE_LINUX_SIGIO
9171  static void fdevent_linux_rtsig_free(fdevents *ev) {
9172 @@ -24,21 +25,21 @@
9173  }
9174  
9175  
9176 -static int fdevent_linux_rtsig_event_del(fdevents *ev, int fde_ndx, int fd) {
9177 -       if (fde_ndx < 0) return -1;
9178 -       
9179 -       if ((size_t)fde_ndx >= ev->used) {
9180 -               fprintf(stderr, "%s.%d: del! out of range %d %zu\n", __FILE__, __LINE__, fde_ndx, ev->used);
9181 +static int fdevent_linux_rtsig_event_del(fdevents *ev, iosocket *sock) {
9182 +       if (sock->fde_ndx < 0) return -1;
9183 +
9184 +       if ((size_t)sock->fde_ndx >= ev->used) {
9185 +               TRACE("del! out of range %d %zu\n", sock->fde_ndx, ev->used);
9186                 SEGFAULT();
9187         }
9188 -       
9189 -       if (ev->pollfds[fde_ndx].fd == fd) {
9190 -               size_t k = fde_ndx;
9191 -               
9192 +
9193 +       if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9194 +               size_t k = sock->fde_ndx;
9195 +
9196                 ev->pollfds[k].fd = -1;
9197  
9198 -               bitset_clear_bit(ev->sigbset, fd);
9199 -               
9200 +               bitset_clear_bit(ev->sigbset, sock->fd);
9201 +
9202                 if (ev->unused.size == 0) {
9203                         ev->unused.size = 16;
9204                         ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size);
9205 @@ -46,53 +47,54 @@
9206                         ev->unused.size += 16;
9207                         ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
9208                 }
9209 -               
9210 +
9211                 ev->unused.ptr[ev->unused.used++] = k;
9212         } else {
9213 -               fprintf(stderr, "%s.%d: del! %d %d\n", __FILE__, __LINE__, ev->pollfds[fde_ndx].fd, fd);
9214 -               
9215 +               fprintf(stderr, "%s.%d: del! %d %d\n", __FILE__, __LINE__, ev->pollfds[sock->fde_ndx].fd, sock->fd);
9216 +
9217                 SEGFAULT();
9218         }
9219 -       
9220 -       return -1;
9221 +       sock->fde_ndx = -1;
9222 +
9223 +       return 0;
9224  }
9225  
9226  #if 0
9227  static int fdevent_linux_rtsig_event_compress(fdevents *ev) {
9228         size_t j;
9229 -       
9230 +
9231         if (ev->used == 0) return 0;
9232         if (ev->unused.used != 0) return 0;
9233 -       
9234 +
9235         for (j = ev->used - 1; j + 1 > 0; j--) {
9236                 if (ev->pollfds[j].fd == -1) ev->used--;
9237         }
9238 -       
9239 -       
9240 +
9241 +
9242         return 0;
9243  }
9244  #endif
9245  
9246 -static int fdevent_linux_rtsig_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9247 +static int fdevent_linux_rtsig_event_add(fdevents *ev, iosocket *sock, int events) {
9248         /* known index */
9249 -       if (fde_ndx != -1) {
9250 -               if (ev->pollfds[fde_ndx].fd == fd) {
9251 -                       ev->pollfds[fde_ndx].events = events;
9252 -                       
9253 -                       return fde_ndx;
9254 +       if (sock->fde_ndx != -1) {
9255 +               if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9256 +                       ev->pollfds[sock->fde_ndx].events = events;
9257 +
9258 +                       return sock->fde_ndx;
9259                 }
9260 -               fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, fde_ndx, ev->pollfds[fde_ndx].fd);
9261 +               fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, sock->fde_ndx, ev->pollfds[sock->fde_ndx].fd);
9262                 SEGFAULT();
9263         }
9264 -       
9265 +
9266         if (ev->unused.used > 0) {
9267                 int k = ev->unused.ptr[--ev->unused.used];
9268 -               
9269 -               ev->pollfds[k].fd = fd;
9270 +
9271 +               ev->pollfds[k].fd = sock->fd;
9272                 ev->pollfds[k].events = events;
9273  
9274 -               bitset_set_bit(ev->sigbset, fd);
9275 -               
9276 +               bitset_set_bit(ev->sigbset, sock->fd);
9277 +
9278                 return k;
9279         } else {
9280                 if (ev->size == 0) {
9281 @@ -102,12 +104,12 @@
9282                         ev->size += 16;
9283                         ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
9284                 }
9285 -               
9286 -               ev->pollfds[ev->used].fd = fd;
9287 +
9288 +               ev->pollfds[ev->used].fd = sock->fd;
9289                 ev->pollfds[ev->used].events = events;
9290  
9291 -               bitset_set_bit(ev->sigbset, fd);
9292 -       
9293 +               bitset_set_bit(ev->sigbset, sock->fd);
9294 +
9295                 return ev->used++;
9296         }
9297  }
9298 @@ -115,20 +117,20 @@
9299  static int fdevent_linux_rtsig_poll(fdevents *ev, int timeout_ms) {
9300         struct timespec ts;
9301         int r;
9302 -       
9303 +
9304  #if 0
9305         fdevent_linux_rtsig_event_compress(ev);
9306  #endif
9307 -       
9308 +
9309         ev->in_sigio = 1;
9310 -               
9311 +
9312         ts.tv_sec =  timeout_ms / 1000;
9313         ts.tv_nsec = (timeout_ms % 1000) * 1000000;
9314         r = sigtimedwait(&(ev->sigset), &(ev->siginfo), &(ts));
9315 -               
9316 -       if (r == -1) { 
9317 +
9318 +       if (r == -1) {
9319                 if (errno == EAGAIN) return 0;
9320 -               return r; 
9321 +               return r;
9322         } else if (r == SIGIO) {
9323                 struct sigaction act;
9324  
9325 @@ -140,7 +142,7 @@
9326                 /* re-enable the signal queue */
9327                 act.sa_handler = SIG_DFL;
9328                 sigaction(ev->signum, &act, NULL);
9329 -               
9330 +
9331                 ev->in_sigio = 0;
9332                 r = poll(ev->pollfds, ev->used, timeout_ms);
9333  
9334 @@ -156,97 +158,67 @@
9335         }
9336  }
9337  
9338 -static int fdevent_linux_rtsig_event_get_revent(fdevents *ev, size_t ndx) {
9339 +static int fdevent_linux_rtsig_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9340         if (ev->in_sigio == 1) {
9341 -#  if 0
9342 -               if (ev->siginfo.si_band == POLLERR) {
9343 -                       fprintf(stderr, "event: %d %02lx %02x %s\n", ev->siginfo.si_fd, ev->siginfo.si_band, errno, strerror(errno));
9344 -               }
9345 -#  endif               
9346 -               if (ndx != 0) {
9347 -                       fprintf(stderr, "+\n");
9348 -                       return 0;
9349 -               }
9350 -               
9351 -               return ev->siginfo.si_band & 0x3f;
9352 +               /* only one event */
9353 +
9354 +               fdevent_revents_add(revents, ev->siginfo.si_fd, ev->siginfo.si_band & 0x3f);
9355         } else {
9356 -               if (ndx >= ev->used) {
9357 -                       fprintf(stderr, "%s.%d: event: %zu %zu\n", __FILE__, __LINE__, ndx, ev->used);
9358 -                       return 0;
9359 +               size_t ndx;
9360 +
9361 +               for (ndx = 0; ndx < ev->used; ndx++) {
9362 +                       if (ev->pollfds[ndx].revents) {
9363 +                               fdevent_revents_add(revents, ev->pollfds[ndx].fd, ev->pollfds[ndx].revents);
9364 +                       }
9365                 }
9366 -               return ev->pollfds[ndx].revents;
9367         }
9368 -}
9369  
9370 -static int fdevent_linux_rtsig_event_get_fd(fdevents *ev, size_t ndx) {
9371 -       if (ev->in_sigio == 1) {
9372 -               return ev->siginfo.si_fd;
9373 -       } else {
9374 -               return ev->pollfds[ndx].fd;
9375 -       }
9376 +       return 0;
9377  }
9378  
9379  static int fdevent_linux_rtsig_fcntl_set(fdevents *ev, int fd) {
9380         static pid_t pid = 0;
9381 -       
9382 +
9383         if (pid == 0) pid = getpid();
9384 -       
9385 +
9386         if (-1 == fcntl(fd, F_SETSIG, ev->signum)) return -1;
9387 -       
9388 +
9389         if (-1 == fcntl(fd, F_SETOWN, (int) pid)) return -1;
9390 -       
9391 +
9392         return fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK | O_RDWR);
9393  }
9394  
9395  
9396 -static int fdevent_linux_rtsig_event_next_fdndx(fdevents *ev, int ndx) {
9397 -       if (ev->in_sigio == 1) {
9398 -               if (ndx < 0) return 0;
9399 -               return -1;
9400 -       } else {
9401 -               size_t i;
9402 -               
9403 -               i = (ndx < 0) ? 0 : ndx + 1;
9404 -               for (; i < ev->used; i++) {
9405 -                       if (ev->pollfds[i].revents) break;
9406 -               }
9407 -               
9408 -               return i;
9409 -       }
9410 -}
9411 -
9412  int fdevent_linux_rtsig_init(fdevents *ev) {
9413         ev->type = FDEVENT_HANDLER_LINUX_RTSIG;
9414  #define SET(x) \
9415         ev->x = fdevent_linux_rtsig_##x;
9416 -       
9417 +
9418         SET(free);
9419         SET(poll);
9420 -       
9421 +
9422         SET(event_del);
9423         SET(event_add);
9424 -       
9425 -       SET(event_next_fdndx);
9426 +
9427         SET(fcntl_set);
9428 -       SET(event_get_fd);
9429 -       SET(event_get_revent);
9430 -       
9431 +       SET(get_revents);
9432 +
9433         ev->signum = SIGRTMIN + 1;
9434 -       
9435 +
9436         sigemptyset(&(ev->sigset));
9437         sigaddset(&(ev->sigset), ev->signum);
9438         sigaddset(&(ev->sigset), SIGIO);
9439         if (-1 == sigprocmask(SIG_BLOCK, &(ev->sigset), NULL)) {
9440                 fprintf(stderr, "%s.%d: sigprocmask failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9441                         __FILE__, __LINE__, strerror(errno));
9442 -               
9443 +
9444                 return -1;
9445         }
9446 -       
9447 +
9448         ev->in_sigio = 1;
9449  
9450         ev->sigbset = bitset_init(ev->maxfds);
9451 -       
9452 +
9453         return 0;
9454  }
9455  #else
9456 --- ../lighttpd-1.4.11/src/fdevent_linux_sysepoll.c     2005-09-30 20:29:27.000000000 +0300
9457 +++ lighttpd-1.4.12/src/fdevent_linux_sysepoll.c        2006-07-18 13:03:40.000000000 +0300
9458 @@ -1,6 +1,5 @@
9459  #include <sys/types.h>
9460  
9461 -#include <unistd.h>
9462  #include <stdlib.h>
9463  #include <stdio.h>
9464  #include <string.h>
9465 @@ -11,6 +10,9 @@
9466  #include "fdevent.h"
9467  #include "settings.h"
9468  #include "buffer.h"
9469 +#include "log.h"
9470 +
9471 +#include "sys-files.h"
9472  
9473  #ifdef USE_LINUX_EPOLL
9474  static void fdevent_linux_sysepoll_free(fdevents *ev) {
9475 @@ -18,38 +20,40 @@
9476         free(ev->epoll_events);
9477  }
9478  
9479 -static int fdevent_linux_sysepoll_event_del(fdevents *ev, int fde_ndx, int fd) {
9480 +static int fdevent_linux_sysepoll_event_del(fdevents *ev, iosocket *sock) {
9481         struct epoll_event ep;
9482 -       
9483 -       if (fde_ndx < 0) return -1;
9484 -       
9485 +
9486 +       if (sock->fde_ndx < 0) return -1;
9487 +
9488         memset(&ep, 0, sizeof(ep));
9489 -       
9490 -       ep.data.fd = fd;
9491 +
9492 +       ep.data.fd = sock->fd;
9493         ep.data.ptr = NULL;
9494 -       
9495 -       if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fd, &ep)) {
9496 +
9497 +       if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, sock->fd, &ep)) {
9498                 fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n", __FILE__, __LINE__, strerror(errno));
9499 -               
9500 +
9501                 SEGFAULT();
9502 -               
9503 +
9504                 return 0;
9505         }
9506 -       
9507 -       
9508 -       return -1;
9509 +
9510 +       sock->fde_ndx = -1;
9511 +
9512 +       return 0;
9513  }
9514  
9515 -static int fdevent_linux_sysepoll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9516 +static int fdevent_linux_sysepoll_event_add(fdevents *ev, iosocket *sock, int events) {
9517         struct epoll_event ep;
9518         int add = 0;
9519 -       
9520 -       if (fde_ndx == -1) add = 1;
9521 -       
9522 +
9523 +       /* a new fd */
9524 +       if (sock->fde_ndx == -1) add = 1;
9525 +
9526         memset(&ep, 0, sizeof(ep));
9527 -       
9528 +
9529         ep.events = 0;
9530 -       
9531 +
9532         if (events & FDEVENT_IN)  ep.events |= EPOLLIN;
9533         if (events & FDEVENT_OUT) ep.events |= EPOLLOUT;
9534  
9535 @@ -60,73 +64,61 @@
9536          * sent.
9537          *
9538          */
9539 -       
9540 +
9541         ep.events |= EPOLLERR | EPOLLHUP /* | EPOLLET */;
9542 -       
9543 +
9544         ep.data.ptr = NULL;
9545 -       ep.data.fd = fd;
9546 -       
9547 -       if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, fd, &ep)) {
9548 +       ep.data.fd = sock->fd;
9549 +
9550 +       if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, sock->fd, &ep)) {
9551                 fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n", __FILE__, __LINE__, strerror(errno));
9552 -               
9553 +
9554                 SEGFAULT();
9555 -               
9556 +
9557                 return 0;
9558         }
9559 -       
9560 -       return fd;
9561 +
9562 +       sock->fde_ndx = sock->fd;
9563 +
9564 +       return 0;
9565  }
9566  
9567  static int fdevent_linux_sysepoll_poll(fdevents *ev, int timeout_ms) {
9568         return epoll_wait(ev->epoll_fd, ev->epoll_events, ev->maxfds, timeout_ms);
9569  }
9570  
9571 -static int fdevent_linux_sysepoll_event_get_revent(fdevents *ev, size_t ndx) {
9572 -       int events = 0, e;
9573 -       
9574 -       e = ev->epoll_events[ndx].events;
9575 -       if (e & EPOLLIN) events |= FDEVENT_IN;
9576 -       if (e & EPOLLOUT) events |= FDEVENT_OUT;
9577 -       if (e & EPOLLERR) events |= FDEVENT_ERR;
9578 -       if (e & EPOLLHUP) events |= FDEVENT_HUP;
9579 -       if (e & EPOLLPRI) events |= FDEVENT_PRI;
9580 -       
9581 -       return e;
9582 -}
9583 -
9584 -static int fdevent_linux_sysepoll_event_get_fd(fdevents *ev, size_t ndx) {
9585 -# if 0
9586 -       fprintf(stderr, "%s.%d: %d, %d\n", __FILE__, __LINE__, ndx, ev->epoll_events[ndx].data.fd);
9587 -# endif
9588 -       
9589 -       return ev->epoll_events[ndx].data.fd;
9590 -}
9591 -
9592 -static int fdevent_linux_sysepoll_event_next_fdndx(fdevents *ev, int ndx) {
9593 -       size_t i;
9594 -       
9595 -       UNUSED(ev);
9596 +static int fdevent_linux_sysepoll_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9597 +       size_t ndx;
9598 +
9599 +       for (ndx = 0; ndx < event_count; ndx++) {
9600 +               int events = 0, e;
9601 +
9602 +               e = ev->epoll_events[ndx].events;
9603 +               if (e & EPOLLIN) events |= FDEVENT_IN;
9604 +               if (e & EPOLLOUT) events |= FDEVENT_OUT;
9605 +               if (e & EPOLLERR) events |= FDEVENT_ERR;
9606 +               if (e & EPOLLHUP) events |= FDEVENT_HUP;
9607 +               if (e & EPOLLPRI) events |= FDEVENT_PRI;
9608  
9609 -       i = (ndx < 0) ? 0 : ndx + 1;
9610 -       
9611 -       return i;
9612 +               fdevent_revents_add(revents, ev->epoll_events[ndx].data.fd, e);
9613 +       }
9614 +
9615 +       return 0;
9616  }
9617  
9618  int fdevent_linux_sysepoll_init(fdevents *ev) {
9619         ev->type = FDEVENT_HANDLER_LINUX_SYSEPOLL;
9620  #define SET(x) \
9621         ev->x = fdevent_linux_sysepoll_##x;
9622 -       
9623 +
9624         SET(free);
9625         SET(poll);
9626 -       
9627 +
9628         SET(event_del);
9629         SET(event_add);
9630 -       
9631 -       SET(event_next_fdndx);
9632 -       SET(event_get_fd);
9633 -       SET(event_get_revent);
9634 -       
9635 +
9636 +       SET(get_revents);
9637 +
9638         if (-1 == (ev->epoll_fd = epoll_create(ev->maxfds))) {
9639                 fprintf(stderr, "%s.%d: epoll_create failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9640                         __FILE__, __LINE__, strerror(errno));
9641 @@ -154,7 +146,7 @@
9642  
9643         fprintf(stderr, "%s.%d: linux-sysepoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
9644                 __FILE__, __LINE__);
9645 -       
9646 +
9647         return -1;
9648  }
9649  #endif
9650 --- ../lighttpd-1.4.11/src/fdevent_poll.c       2005-11-18 13:59:16.000000000 +0200
9651 +++ lighttpd-1.4.12/src/fdevent_poll.c  2006-07-18 13:03:40.000000000 +0300
9652 @@ -1,6 +1,5 @@
9653  #include <sys/types.h>
9654  
9655 -#include <unistd.h>
9656  #include <stdlib.h>
9657  #include <stdio.h>
9658  #include <string.h>
9659 @@ -11,6 +10,7 @@
9660  #include "fdevent.h"
9661  #include "settings.h"
9662  #include "buffer.h"
9663 +#include "log.h"
9664  
9665  #ifdef USE_POLL
9666  static void fdevent_poll_free(fdevents *ev) {
9667 @@ -18,21 +18,21 @@
9668         if (ev->unused.ptr) free(ev->unused.ptr);
9669  }
9670  
9671 -static int fdevent_poll_event_del(fdevents *ev, int fde_ndx, int fd) {
9672 -       if (fde_ndx < 0) return -1;
9673 -       
9674 -       if ((size_t)fde_ndx >= ev->used) {
9675 -               fprintf(stderr, "%s.%d: del! out of range %d %zd\n", __FILE__, __LINE__, fde_ndx, ev->used);
9676 +static int fdevent_poll_event_del(fdevents *ev, iosocket *sock) {
9677 +       if (sock->fde_ndx < 0) return -1;
9678 +
9679 +       if ((size_t)sock->fde_ndx >= ev->used) {
9680 +               fprintf(stderr, "%s.%d: del! out of range %d %zd\n", __FILE__, __LINE__, sock->fde_ndx, ev->used);
9681                 SEGFAULT();
9682         }
9683 -       
9684 -       if (ev->pollfds[fde_ndx].fd == fd) {
9685 -               size_t k = fde_ndx;
9686 -               
9687 +
9688 +       if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9689 +               size_t k = sock->fde_ndx;
9690 +
9691                 ev->pollfds[k].fd = -1;
9692                 /* ev->pollfds[k].events = 0; */
9693                 /* ev->pollfds[k].revents = 0; */
9694 -               
9695 +
9696                 if (ev->unused.size == 0) {
9697                         ev->unused.size = 16;
9698                         ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size);
9699 @@ -40,48 +40,51 @@
9700                         ev->unused.size += 16;
9701                         ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
9702                 }
9703 -               
9704 +
9705                 ev->unused.ptr[ev->unused.used++] = k;
9706         } else {
9707                 SEGFAULT();
9708         }
9709 -       
9710 -       return -1;
9711 +
9712 +       sock->fde_ndx = -1;
9713 +
9714 +       return 0;
9715  }
9716  
9717  #if 0
9718  static int fdevent_poll_event_compress(fdevents *ev) {
9719         size_t j;
9720 -       
9721 +
9722         if (ev->used == 0) return 0;
9723         if (ev->unused.used != 0) return 0;
9724 -       
9725 +
9726         for (j = ev->used - 1; j + 1 > 0 && ev->pollfds[j].fd == -1; j--) ev->used--;
9727 -       
9728 +
9729         return 0;
9730  }
9731  #endif
9732  
9733 -static int fdevent_poll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9734 -       /* known index */
9735 -       
9736 -       if (fde_ndx != -1) {
9737 -               if (ev->pollfds[fde_ndx].fd == fd) {
9738 -                       ev->pollfds[fde_ndx].events = events;
9739 -                       
9740 -                       return fde_ndx;
9741 +static int fdevent_poll_event_add(fdevents *ev, iosocket *sock, int events) {
9742 +       if (sock->fde_ndx != -1) {
9743 +               /* this fd was already added, just change the requested events */
9744 +
9745 +               if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9746 +                       ev->pollfds[sock->fde_ndx].events = events;
9747 +
9748 +                       return sock->fde_ndx;
9749                 }
9750 -               fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, fde_ndx, ev->pollfds[fde_ndx].fd);
9751 +               fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, sock->fde_ndx, ev->pollfds[sock->fde_ndx].fd);
9752                 SEGFAULT();
9753         }
9754 -       
9755 +
9756         if (ev->unused.used > 0) {
9757                 int k = ev->unused.ptr[--ev->unused.used];
9758 -               
9759 -               ev->pollfds[k].fd = fd;
9760 +
9761 +               ev->pollfds[k].fd = sock->fd;
9762                 ev->pollfds[k].events = events;
9763 -               
9764 -               return k;
9765 +
9766 +               sock->fde_ndx = k;
9767 +
9768         } else {
9769                 if (ev->size == 0) {
9770                         ev->size = 16;
9771 @@ -90,12 +93,13 @@
9772                         ev->size += 16;
9773                         ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
9774                 }
9775 -               
9776 -               ev->pollfds[ev->used].fd = fd;
9777 +
9778 +               ev->pollfds[ev->used].fd = sock->fd;
9779                 ev->pollfds[ev->used].events = events;
9780 -               
9781 -               return ev->used++;
9782 +
9783 +               sock->fde_ndx = ev->used++;
9784         }
9785 +       return 0;
9786  }
9787  
9788  static int fdevent_poll_poll(fdevents *ev, int timeout_ms) {
9789 @@ -105,71 +109,38 @@
9790         return poll(ev->pollfds, ev->used, timeout_ms);
9791  }
9792  
9793 -static int fdevent_poll_event_get_revent(fdevents *ev, size_t ndx) {
9794 -       int r, poll_r;
9795 -       if (ndx >= ev->used) {
9796 -               fprintf(stderr, "%s.%d: dying because: event: %zd >= %zd\n", __FILE__, __LINE__, ndx, ev->used);
9797 -               
9798 -               SEGFAULT();
9799 -               
9800 -               return 0;
9801 -       }
9802 -       
9803 -       if (ev->pollfds[ndx].revents & POLLNVAL) {
9804 -               /* should never happen */
9805 -               SEGFAULT();
9806 -       }
9807 +static int fdevent_poll_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9808 +       size_t ndx;
9809  
9810 -       r = 0;
9811 -       poll_r = ev->pollfds[ndx].revents;
9812 +       for (ndx = 0; ndx < ev->used; ndx++) {
9813 +               if (ev->pollfds[ndx].revents) {
9814 +                       if (ev->pollfds[ndx].revents & POLLNVAL) {
9815 +                               /* should never happen */
9816 +                               SEGFAULT();
9817 +                       }
9818  
9819 -       /* map POLL* to FDEVEN_* */
9820 -
9821 -       if (poll_r & POLLIN) r |= FDEVENT_IN;
9822 -       if (poll_r & POLLOUT) r |= FDEVENT_OUT;
9823 -       if (poll_r & POLLERR) r |= FDEVENT_ERR;
9824 -       if (poll_r & POLLHUP) r |= FDEVENT_HUP;
9825 -       if (poll_r & POLLNVAL) r |= FDEVENT_NVAL;
9826 -       if (poll_r & POLLPRI) r |= FDEVENT_PRI;
9827 -       
9828 -       return ev->pollfds[ndx].revents;
9829 -}
9830 -
9831 -static int fdevent_poll_event_get_fd(fdevents *ev, size_t ndx) {
9832 -       return ev->pollfds[ndx].fd;
9833 -}
9834 -
9835 -static int fdevent_poll_event_next_fdndx(fdevents *ev, int ndx) {
9836 -       size_t i;
9837 -       
9838 -       i = (ndx < 0) ? 0 : ndx + 1;
9839 -       for (; i < ev->used; i++) {
9840 -               if (ev->pollfds[i].revents) break;
9841 +                       fdevent_revents_add(revents, ev->pollfds[ndx].fd, ev->pollfds[ndx].revents);
9842 +               }
9843         }
9844 -       
9845 -       return i;
9846 +
9847 +       return 0;
9848  }
9849  
9850  int fdevent_poll_init(fdevents *ev) {
9851         ev->type = FDEVENT_HANDLER_POLL;
9852  #define SET(x) \
9853         ev->x = fdevent_poll_##x;
9854 -       
9855 +
9856         SET(free);
9857         SET(poll);
9858 -       
9859 +
9860         SET(event_del);
9861         SET(event_add);
9862 -       
9863 -       SET(event_next_fdndx);
9864 -       SET(event_get_fd);
9865 -       SET(event_get_revent);
9866 -       
9867 -       return 0;
9868 -}
9869 -
9870  
9871 +       SET(get_revents);
9872  
9873 +       return 0;
9874 +}
9875  
9876  #else
9877  int fdevent_poll_init(fdevents *ev) {
9878 --- ../lighttpd-1.4.11/src/fdevent_select.c     2005-08-31 11:12:46.000000000 +0300
9879 +++ lighttpd-1.4.12/src/fdevent_select.c        2006-07-18 13:03:40.000000000 +0300
9880 @@ -1,18 +1,19 @@
9881 -#include <sys/time.h>
9882  #include <sys/types.h>
9883  
9884 -#include <unistd.h>
9885  #include <stdlib.h>
9886  #include <string.h>
9887  #include <errno.h>
9888  #include <signal.h>
9889  #include <fcntl.h>
9890  #include <assert.h>
9891 +#include <stdio.h>
9892  
9893  #include "fdevent.h"
9894  #include "settings.h"
9895  #include "buffer.h"
9896  
9897 +#include "sys-socket.h"
9898 +
9899  #ifdef USE_SELECT
9900  
9901  static int fdevent_select_reset(fdevents *ev) {
9902 @@ -24,101 +25,98 @@
9903         return 0;
9904  }
9905  
9906 -static int fdevent_select_event_del(fdevents *ev, int fde_ndx, int fd) {
9907 -       if (fde_ndx < 0) return -1;
9908 +static int fdevent_select_event_del(fdevents *ev, iosocket *sock) {
9909 +       if (sock->fde_ndx < 0) return -1;
9910  
9911 -       FD_CLR(fd, &(ev->select_set_read));
9912 -       FD_CLR(fd, &(ev->select_set_write));
9913 -       FD_CLR(fd, &(ev->select_set_error));
9914 +       FD_CLR(sock->fd, &(ev->select_set_read));
9915 +       FD_CLR(sock->fd, &(ev->select_set_write));
9916 +       FD_CLR(sock->fd, &(ev->select_set_error));
9917  
9918 -       return -1;
9919 -}
9920 +       /* mark the fdevent as deleted */
9921 +       sock->fde_ndx = -1;
9922  
9923 -static int fdevent_select_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9924 -       UNUSED(fde_ndx);
9925 +       return 0;
9926 +}
9927  
9928 +static int fdevent_select_event_add(fdevents *ev, iosocket *sock, int events) {
9929         /* we should be protected by max-fds, but you never know */
9930 -       assert(fd < FD_SETSIZE);
9931 +#ifndef _WIN32
9932 +       assert(sock->fd < FD_SETSIZE);
9933 +#endif
9934  
9935         if (events & FDEVENT_IN) {
9936 -               FD_SET(fd, &(ev->select_set_read));
9937 -               FD_CLR(fd, &(ev->select_set_write));
9938 +               FD_SET(sock->fd, &(ev->select_set_read));
9939 +               FD_CLR(sock->fd, &(ev->select_set_write));
9940         }
9941         if (events & FDEVENT_OUT) {
9942 -               FD_CLR(fd, &(ev->select_set_read));
9943 -               FD_SET(fd, &(ev->select_set_write));
9944 +               FD_CLR(sock->fd, &(ev->select_set_read));
9945 +               FD_SET(sock->fd, &(ev->select_set_write));
9946         }
9947 -       FD_SET(fd, &(ev->select_set_error));
9948 -       
9949 -       if (fd > ev->select_max_fd) ev->select_max_fd = fd;
9950 -       
9951 -       return fd;
9952 +       FD_SET(sock->fd, &(ev->select_set_error));
9953 +
9954 +       /* we need this for the poll */
9955 +       if (sock->fd > ev->select_max_fd) ev->select_max_fd = sock->fd;
9956 +
9957 +       /* mark fd as added */
9958 +       sock->fde_ndx = sock->fd;
9959 +
9960 +       return 0;
9961  }
9962  
9963  static int fdevent_select_poll(fdevents *ev, int timeout_ms) {
9964         struct timeval tv;
9965 -       
9966 +
9967         tv.tv_sec =  timeout_ms / 1000;
9968         tv.tv_usec = (timeout_ms % 1000) * 1000;
9969 -       
9970 +
9971         ev->select_read = ev->select_set_read;
9972         ev->select_write = ev->select_set_write;
9973         ev->select_error = ev->select_set_error;
9974 -       
9975 +
9976         return select(ev->select_max_fd + 1, &(ev->select_read), &(ev->select_write), &(ev->select_error), &tv);
9977  }
9978  
9979 -static int fdevent_select_event_get_revent(fdevents *ev, size_t ndx) {
9980 -       int revents = 0;
9981 -       
9982 -       if (FD_ISSET(ndx, &(ev->select_read))) {
9983 -               revents |= FDEVENT_IN;
9984 +/**
9985 + * scan the fdset for events 
9986 + */
9987 +static int fdevent_select_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9988 +
9989 +       int ndx = 0;
9990 +
9991 +       for (ndx = 0; ndx < ev->select_max_fd; ndx++) {
9992 +               int events = 0;
9993 +
9994 +               if (FD_ISSET(ndx, &(ev->select_read))) {
9995 +                       events |= FDEVENT_IN;
9996 +               }
9997 +               if (FD_ISSET(ndx, &(ev->select_write))) {
9998 +                       events |= FDEVENT_OUT;
9999 +               }
10000 +               if (FD_ISSET(ndx, &(ev->select_error))) {
10001 +                       events |= FDEVENT_ERR;
10002 +               }
10003 +
10004 +               if (events) {
10005 +                       fdevent_revents_add(revents, ndx, events);
10006 +               }
10007         }
10008 -       if (FD_ISSET(ndx, &(ev->select_write))) {
10009 -               revents |= FDEVENT_OUT;
10010 -       }
10011 -       if (FD_ISSET(ndx, &(ev->select_error))) {
10012 -               revents |= FDEVENT_ERR;
10013 -       }
10014 -       
10015 -       return revents;
10016 -}
10017 -
10018 -static int fdevent_select_event_get_fd(fdevents *ev, size_t ndx) {
10019 -       UNUSED(ev);
10020 -
10021 -       return ndx;
10022 -}
10023  
10024 -static int fdevent_select_event_next_fdndx(fdevents *ev, int ndx) {
10025 -       int i;
10026 -       
10027 -       i = (ndx < 0) ? 0 : ndx + 1;
10028 -       
10029 -       for (; i < ev->select_max_fd + 1; i++) {
10030 -               if (FD_ISSET(i, &(ev->select_read))) break;
10031 -               if (FD_ISSET(i, &(ev->select_write))) break;
10032 -               if (FD_ISSET(i, &(ev->select_error))) break;
10033 -       }
10034 -       
10035 -       return i;
10036 +       return 0;
10037  }
10038  
10039  int fdevent_select_init(fdevents *ev) {
10040         ev->type = FDEVENT_HANDLER_SELECT;
10041  #define SET(x) \
10042         ev->x = fdevent_select_##x;
10043 -       
10044 +
10045         SET(reset);
10046         SET(poll);
10047 -       
10048 +
10049         SET(event_del);
10050         SET(event_add);
10051 -       
10052 -       SET(event_next_fdndx);
10053 -       SET(event_get_fd);
10054 -       SET(event_get_revent);
10055 -       
10056 +
10057 +       SET(get_revents);
10058 +
10059         return 0;
10060  }
10061  
10062 --- ../lighttpd-1.4.11/src/fdevent_solaris_devpoll.c    2005-09-01 10:45:26.000000000 +0300
10063 +++ lighttpd-1.4.12/src/fdevent_solaris_devpoll.c       2006-07-16 00:26:03.000000000 +0300
10064 @@ -1,6 +1,5 @@
10065  #include <sys/types.h>
10066  
10067 -#include <unistd.h>
10068  #include <stdlib.h>
10069  #include <stdio.h>
10070  #include <string.h>
10071 @@ -23,55 +22,55 @@
10072  
10073  static int fdevent_solaris_devpoll_event_del(fdevents *ev, int fde_ndx, int fd) {
10074         struct pollfd pfd;
10075 -               
10076 +
10077         if (fde_ndx < 0) return -1;
10078 -       
10079 +
10080         pfd.fd = fd;
10081         pfd.events = POLLREMOVE;
10082         pfd.revents = 0;
10083 -       
10084 +
10085         if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
10086 -               fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n", 
10087 -                       __FILE__, __LINE__, 
10088 +               fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
10089 +                       __FILE__, __LINE__,
10090                         fd, strerror(errno));
10091 -               
10092 +
10093                 return -1;
10094         }
10095 -       
10096 +
10097         return -1;
10098  }
10099  
10100  static int fdevent_solaris_devpoll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
10101         struct pollfd pfd;
10102         int add = 0;
10103 -               
10104 +
10105         if (fde_ndx == -1) add = 1;
10106 -       
10107 +
10108         pfd.fd = fd;
10109         pfd.events = events;
10110         pfd.revents = 0;
10111 -       
10112 +
10113         if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
10114 -               fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n", 
10115 -                       __FILE__, __LINE__, 
10116 +               fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
10117 +                       __FILE__, __LINE__,
10118                         fd, strerror(errno));
10119 -               
10120 +
10121                 return -1;
10122         }
10123 -       
10124 +
10125         return fd;
10126  }
10127  
10128  static int fdevent_solaris_devpoll_poll(fdevents *ev, int timeout_ms) {
10129         struct dvpoll dopoll;
10130         int ret;
10131 -       
10132 +
10133         dopoll.dp_timeout = timeout_ms;
10134         dopoll.dp_nfds = ev->maxfds;
10135         dopoll.dp_fds = ev->devpollfds;
10136 -       
10137 +
10138         ret = ioctl(ev->devpoll_fd, DP_POLL, &dopoll);
10139 -       
10140 +
10141         return ret;
10142  }
10143  
10144 @@ -85,11 +84,11 @@
10145  
10146  static int fdevent_solaris_devpoll_event_next_fdndx(fdevents *ev, int last_ndx) {
10147         size_t i;
10148 -       
10149 +
10150         UNUSED(ev);
10151  
10152         i = (last_ndx < 0) ? 0 : last_ndx + 1;
10153 -       
10154 +
10155         return i;
10156  }
10157  
10158 @@ -117,20 +116,20 @@
10159         ev->type = FDEVENT_HANDLER_SOLARIS_DEVPOLL;
10160  #define SET(x) \
10161         ev->x = fdevent_solaris_devpoll_##x;
10162 -       
10163 +
10164         SET(free);
10165         SET(poll);
10166         SET(reset);
10167 -       
10168 +
10169         SET(event_del);
10170         SET(event_add);
10171 -       
10172 +
10173         SET(event_next_fdndx);
10174         SET(event_get_fd);
10175         SET(event_get_revent);
10176 -       
10177 +
10178         ev->devpollfds = malloc(sizeof(*ev->devpollfds) * ev->maxfds);
10179 -       
10180 +
10181         if ((ev->devpoll_fd = open("/dev/poll", O_RDWR)) < 0) {
10182                 fprintf(stderr, "%s.%d: opening /dev/poll failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
10183                         __FILE__, __LINE__, strerror(errno));
10184 @@ -152,7 +151,7 @@
10185  
10186         fprintf(stderr, "%s.%d: solaris-devpoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
10187                         __FILE__, __LINE__);
10188 -       
10189 +
10190         return -1;
10191  }
10192  #endif
10193 --- ../lighttpd-1.4.11/src/http-header-glue.c   2006-02-08 15:31:36.000000000 +0200
10194 +++ lighttpd-1.4.12/src/http-header-glue.c      2006-07-18 13:03:40.000000000 +0300
10195 @@ -45,20 +45,20 @@
10196  #   ifdef HAVE_STRUCT_SOCKADDR_STORAGE
10197  static size_t get_sa_len(const struct sockaddr *addr) {
10198         switch (addr->sa_family) {
10199 -               
10200 +
10201  #    ifdef AF_INET
10202         case AF_INET:
10203                 return (sizeof (struct sockaddr_in));
10204  #    endif
10205 -               
10206 +
10207  #    ifdef AF_INET6
10208         case AF_INET6:
10209                 return (sizeof (struct sockaddr_in6));
10210  #    endif
10211 -               
10212 +
10213         default:
10214                 return (sizeof (struct sockaddr));
10215 -               
10216 +
10217         }
10218  }
10219  #    define SA_LEN(addr)   (get_sa_len(addr))
10220 @@ -74,7 +74,7 @@
10221  
10222  int response_header_insert(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
10223         data_string *ds;
10224 -       
10225 +
10226         UNUSED(srv);
10227  
10228         if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
10229 @@ -82,32 +82,32 @@
10230         }
10231         buffer_copy_string_len(ds->key, key, keylen);
10232         buffer_copy_string_len(ds->value, value, vallen);
10233 -       
10234 +
10235         array_insert_unique(con->response.headers, (data_unset *)ds);
10236 -       
10237 +
10238         return 0;
10239  }
10240  
10241  int response_header_overwrite(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
10242         data_string *ds;
10243 -       
10244 +
10245         UNUSED(srv);
10246  
10247         /* if there already is a key by this name overwrite the value */
10248         if (NULL != (ds = (data_string *)array_get_element(con->response.headers, key))) {
10249                 buffer_copy_string(ds->value, value);
10250 -               
10251 +
10252                 return 0;
10253         }
10254 -       
10255 +
10256         return response_header_insert(srv, con, key, keylen, value, vallen);
10257  }
10258  
10259  int http_response_redirect_to_directory(server *srv, connection *con) {
10260         buffer *o;
10261 -       
10262 +
10263         o = buffer_init();
10264 -       
10265 +
10266         if (con->conf.is_ssl) {
10267                 buffer_copy_string(o, "https://");
10268         } else {
10269 @@ -123,36 +123,36 @@
10270  #endif
10271                 sock_addr our_addr;
10272                 socklen_t our_addr_len;
10273 -               
10274 +
10275                 our_addr_len = sizeof(our_addr);
10276 -               
10277 -               if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
10278 +
10279 +               if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
10280                         con->http_status = 500;
10281 -                       
10282 +
10283                         log_error_write(srv, __FILE__, __LINE__, "ss",
10284                                         "can't get sockname", strerror(errno));
10285 -                       
10286 +
10287                         buffer_free(o);
10288                         return 0;
10289                 }
10290 -               
10291 -               
10292 +
10293 +
10294                 /* Lookup name: secondly try to get hostname for bind address */
10295                 switch(our_addr.plain.sa_family) {
10296  #ifdef HAVE_IPV6
10297                 case AF_INET6:
10298 -                       if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6), 
10299 -                                            SA_LEN((const struct sockaddr *)&our_addr.ipv6), 
10300 +                       if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6),
10301 +                                            SA_LEN((const struct sockaddr *)&our_addr.ipv6),
10302                                              hbuf, sizeof(hbuf), NULL, 0, 0)) {
10303 -                               
10304 +
10305                                 char dst[INET6_ADDRSTRLEN];
10306 -                               
10307 +
10308                                 log_error_write(srv, __FILE__, __LINE__,
10309                                                 "SSSS", "NOTICE: getnameinfo failed: ",
10310                                                 strerror(errno), ", using ip-address instead");
10311 -                               
10312 -                               buffer_append_string(o, 
10313 -                                                    inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr, 
10314 +
10315 +                               buffer_append_string(o,
10316 +                                                    inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr,
10317                                                                dst, sizeof(dst)));
10318                         } else {
10319                                 buffer_append_string(o, hbuf);
10320 @@ -164,7 +164,7 @@
10321                                 log_error_write(srv, __FILE__, __LINE__,
10322                                                 "SdSS", "NOTICE: gethostbyaddr failed: ",
10323                                                 h_errno, ", using ip-address instead");
10324 -                               
10325 +
10326                                 buffer_append_string(o, inet_ntoa(our_addr.ipv4.sin_addr));
10327                         } else {
10328                                 buffer_append_string(o, he->h_name);
10329 @@ -173,12 +173,12 @@
10330                 default:
10331                         log_error_write(srv, __FILE__, __LINE__,
10332                                         "S", "ERROR: unsupported address-type");
10333 -                       
10334 +
10335                         buffer_free(o);
10336                         return -1;
10337                 }
10338 -               
10339 -               if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) || 
10340 +
10341 +               if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) ||
10342                       (con->conf.is_ssl == 1 && srv->srvconf.port == 443))) {
10343                         buffer_append_string(o, ":");
10344                         buffer_append_long(o, srv->srvconf.port);
10345 @@ -190,41 +190,41 @@
10346                 buffer_append_string(o, "?");
10347                 buffer_append_string_buffer(o, con->uri.query);
10348         }
10349 -       
10350 +
10351         response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(o));
10352 -       
10353 +
10354         con->http_status = 301;
10355         con->file_finished = 1;
10356 -       
10357 +
10358         buffer_free(o);
10359 -       
10360 +
10361         return 0;
10362  }
10363  
10364  buffer * strftime_cache_get(server *srv, time_t last_mod) {
10365         struct tm *tm;
10366         size_t i;
10367 -               
10368 +
10369         for (i = 0; i < FILE_CACHE_MAX; i++) {
10370                 /* found cache-entry */
10371                 if (srv->mtime_cache[i].mtime == last_mod) return srv->mtime_cache[i].str;
10372 -                               
10373 +
10374                 /* found empty slot */
10375                 if (srv->mtime_cache[i].mtime == 0) break;
10376         }
10377 -       
10378 +
10379         if (i == FILE_CACHE_MAX) {
10380                 i = 0;
10381         }
10382 -               
10383 +
10384         srv->mtime_cache[i].mtime = last_mod;
10385         buffer_prepare_copy(srv->mtime_cache[i].str, 1024);
10386         tm = gmtime(&(srv->mtime_cache[i].mtime));
10387 -       srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr, 
10388 +       srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr,
10389                                                  srv->mtime_cache[i].str->size - 1,
10390                                                  "%a, %d %b %Y %H:%M:%S GMT", tm);
10391         srv->mtime_cache[i].str->used++;
10392 -       
10393 +
10394         return srv->mtime_cache[i].str;
10395  }
10396  
10397 @@ -239,56 +239,60 @@
10398          *    request. That is, if no entity tags match, then the server MUST NOT
10399          *    return a 304 (Not Modified) response.
10400          */
10401 -       
10402 +
10403         /* last-modified handling */
10404         if (con->request.http_if_none_match) {
10405                 if (etag_is_equal(con->physical.etag, con->request.http_if_none_match)) {
10406 -                       if (con->request.http_method == HTTP_METHOD_GET || 
10407 +                       if (con->request.http_method == HTTP_METHOD_GET ||
10408                             con->request.http_method == HTTP_METHOD_HEAD) {
10409 -                               
10410 +
10411                                 /* check if etag + last-modified */
10412                                 if (con->request.http_if_modified_since) {
10413                                         size_t used_len;
10414                                         char *semicolon;
10415 -                                       
10416 +
10417                                         if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
10418                                                 used_len = strlen(con->request.http_if_modified_since);
10419                                         } else {
10420                                                 used_len = semicolon - con->request.http_if_modified_since;
10421                                         }
10422 -                                       
10423 +
10424                                         if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
10425                                                 con->http_status = 304;
10426                                                 return HANDLER_FINISHED;
10427                                         } else {
10428 +#ifdef HAVE_STRPTIME
10429                                                 char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
10430 +                                               time_t t_header, t_file;
10431 +                                               struct tm tm;
10432  
10433 -                                               /* convert to timestamp */
10434 -                                               if (used_len < sizeof(buf)) {
10435 -                                                       time_t t_header, t_file;
10436 -                                                       struct tm tm;
10437 -                                                       
10438 -                                                       strncpy(buf, con->request.http_if_modified_since, used_len);
10439 -                                                       buf[used_len] = '\0';
10440 -                                                       
10441 -                                                       strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10442 -                                                       t_header = mktime(&tm);
10443 -                                                       
10444 -                                                       strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10445 -                                                       t_file = mktime(&tm);
10446 -
10447 -                                                       if (t_file > t_header) {
10448 -                                                               con->http_status = 304;
10449 -                                                               return HANDLER_FINISHED;
10450 -                                                       }
10451 -                                               } else {
10452 -                                                       log_error_write(srv, __FILE__, __LINE__, "ssdd", 
10453 -                                                                       "DEBUG: Last-Modified check failed as the received timestamp was too long:", 
10454 +                                               /* check if we can safely copy the string */
10455 +                                               if (used_len >= sizeof(buf)) {
10456 +                                                       log_error_write(srv, __FILE__, __LINE__, "ssdd",
10457 +                                                                       "DEBUG: Last-Modified check failed as the received timestamp was too long:",
10458                                                                         con->request.http_if_modified_since, used_len, sizeof(buf) - 1);
10459 -                                                       
10460 +
10461                                                         con->http_status = 412;
10462                                                         return HANDLER_FINISHED;
10463                                                 }
10464 +
10465 +
10466 +                                               strncpy(buf, con->request.http_if_modified_since, used_len);
10467 +                                               buf[used_len] = '\0';
10468 +
10469 +                                               strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10470 +                                               t_header = mktime(&tm);
10471 +
10472 +                                               strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10473 +                                               t_file = mktime(&tm);
10474 +
10475 +                                               if (t_file > t_header) return HANDLER_GO_ON;
10476 +
10477 +                                               con->http_status = 304;
10478 +                                               return HANDLER_FINISHED;
10479 +#else
10480 +                        return HANDLER_GO_ON;
10481 +#endif
10482                                         }
10483                                 } else {
10484                                         con->http_status = 304;
10485 @@ -302,16 +306,41 @@
10486         } else if (con->request.http_if_modified_since) {
10487                 size_t used_len;
10488                 char *semicolon;
10489 -               
10490 +
10491                 if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
10492                         used_len = strlen(con->request.http_if_modified_since);
10493                 } else {
10494                         used_len = semicolon - con->request.http_if_modified_since;
10495                 }
10496 -               
10497 +
10498                 if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
10499                         con->http_status = 304;
10500                         return HANDLER_FINISHED;
10501 +               } else {
10502 +#ifdef HAVE_STRPTIME
10503 +                       char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
10504 +                       time_t t_header, t_file;
10505 +                       struct tm tm;
10506 +
10507 +                       /* convert to timestamp */
10508 +                       if (used_len >= sizeof(buf)) return HANDLER_GO_ON;
10509 +
10510 +                       strncpy(buf, con->request.http_if_modified_since, used_len);
10511 +                       buf[used_len] = '\0';
10512 +
10513 +                       strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10514 +                       t_header = mktime(&tm);
10515 +
10516 +                       strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10517 +                       t_file = mktime(&tm);
10518 +
10519 +                       if (t_file > t_header) return HANDLER_GO_ON;
10520 +
10521 +                       con->http_status = 304;
10522 +                       return HANDLER_FINISHED;
10523 +#else
10524 +            return HANDLER_GO_ON;
10525 +#endif
10526                 }
10527         }
10528  
10529 --- ../lighttpd-1.4.11/src/http_auth.c  2006-02-01 13:02:52.000000000 +0200
10530 +++ lighttpd-1.4.12/src/http_auth.c     2006-07-18 13:03:40.000000000 +0300
10531 @@ -22,7 +22,6 @@
10532  #include <string.h>
10533  #include <time.h>
10534  #include <errno.h>
10535 -#include <unistd.h>
10536  #include <ctype.h>
10537  
10538  #include "server.h"
10539 @@ -31,23 +30,14 @@
10540  #include "http_auth_digest.h"
10541  #include "stream.h"
10542  
10543 +#include "sys-strings.h"
10544 +
10545  #ifdef USE_OPENSSL
10546  # include <openssl/md5.h>
10547  #else
10548  # include "md5.h"
10549  #endif
10550  
10551 -
10552 -#ifdef USE_PAM
10553 -#include <security/pam_appl.h>
10554 -#include <security/pam_misc.h>
10555 -
10556 -static struct pam_conv conv = {
10557 -       misc_conv,
10558 -               NULL
10559 -};
10560 -#endif
10561 -
10562  handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s);
10563  
10564  static const char base64_pad = '=';
10565 @@ -75,25 +65,25 @@
10566         unsigned char *result;
10567         int ch, j = 0, k;
10568         size_t i;
10569 -       
10570 +
10571         size_t in_len = strlen(in);
10572 -       
10573 +
10574         buffer_prepare_copy(out, in_len);
10575 -       
10576 +
10577         result = (unsigned char *)out->ptr;
10578 -       
10579 +
10580         ch = in[0];
10581         /* run through the whole string, converting as we go */
10582         for (i = 0; i < in_len; i++) {
10583                 ch = in[i];
10584 -               
10585 +
10586                 if (ch == '\0') break;
10587 -               
10588 +
10589                 if (ch == base64_pad) break;
10590 -               
10591 +
10592                 ch = base64_reverse_table[ch];
10593                 if (ch < 0) continue;
10594 -               
10595 +
10596                 switch(i % 4) {
10597                 case 0:
10598                         result[j] = ch << 2;
10599 @@ -125,168 +115,168 @@
10600                 }
10601         }
10602         result[k] = '\0';
10603 -       
10604 +
10605         out->used = k;
10606 -       
10607 +
10608         return result;
10609  }
10610  
10611  static int http_auth_get_password(server *srv, mod_auth_plugin_data *p, buffer *username, buffer *realm, buffer *password) {
10612         int ret = -1;
10613 -       
10614 +
10615         if (!username->used|| !realm->used) return -1;
10616 -       
10617 +
10618         if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
10619                 stream f;
10620                 char * f_line;
10621 -               
10622 +
10623                 if (buffer_is_empty(p->conf.auth_htdigest_userfile)) return -1;
10624 -               
10625 +
10626                 if (0 != stream_open(&f, p->conf.auth_htdigest_userfile)) {
10627                         log_error_write(srv, __FILE__, __LINE__, "sbss", "opening digest-userfile", p->conf.auth_htdigest_userfile, "failed:", strerror(errno));
10628 -                       
10629 +
10630                         return -1;
10631                 }
10632 -               
10633 +
10634                 f_line = f.start;
10635 -               
10636 +
10637                 while (f_line - f.start != f.size) {
10638                         char *f_user, *f_pwd, *e, *f_realm;
10639                         size_t u_len, pwd_len, r_len;
10640 -                       
10641 +
10642                         f_user = f_line;
10643 -                       
10644 -                       /* 
10645 +
10646 +                       /*
10647                          * htdigest format
10648 -                        * 
10649 -                        * user:realm:md5(user:realm:password) 
10650 +                        *
10651 +                        * user:realm:md5(user:realm:password)
10652                          */
10653 -                       
10654 +
10655                         if (NULL == (f_realm = memchr(f_user, ':', f.size - (f_user - f.start) ))) {
10656 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
10657 -                                               "parsed error in", p->conf.auth_htdigest_userfile, 
10658 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
10659 +                                               "parsed error in", p->conf.auth_htdigest_userfile,
10660                                                 "expected 'username:realm:hashed password'");
10661 -                               
10662 +
10663                                 stream_close(&f);
10664 -                               
10665 +
10666                                 return -1;
10667                         }
10668 -                       
10669 +
10670                         if (NULL == (f_pwd = memchr(f_realm + 1, ':', f.size - (f_realm + 1 - f.start)))) {
10671 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
10672 -                                               "parsed error in", p->conf.auth_plain_userfile, 
10673 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
10674 +                                               "parsed error in", p->conf.auth_plain_userfile,
10675                                                 "expected 'username:realm:hashed password'");
10676 -                               
10677 +
10678                                 stream_close(&f);
10679 -                               
10680 +
10681                                 return -1;
10682                         }
10683 -                       
10684 +
10685                         /* get pointers to the fields */
10686 -                       u_len = f_realm - f_user; 
10687 +                       u_len = f_realm - f_user;
10688                         f_realm++;
10689                         r_len = f_pwd - f_realm;
10690                         f_pwd++;
10691 -                       
10692 +
10693                         if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
10694                                 pwd_len = e - f_pwd;
10695                         } else {
10696                                 pwd_len = f.size - (f_pwd - f.start);
10697                         }
10698 -                       
10699 +
10700                         if (username->used - 1 == u_len &&
10701                             (realm->used - 1 == r_len) &&
10702                             (0 == strncmp(username->ptr, f_user, u_len)) &&
10703                             (0 == strncmp(realm->ptr, f_realm, r_len))) {
10704                                 /* found */
10705 -                               
10706 +
10707                                 buffer_copy_string_len(password, f_pwd, pwd_len);
10708 -                               
10709 +
10710                                 ret = 0;
10711                                 break;
10712                         }
10713 -                       
10714 +
10715                         /* EOL */
10716                         if (!e) break;
10717 -                       
10718 +
10719                         f_line = e + 1;
10720                 }
10721 -               
10722 +
10723                 stream_close(&f);
10724         } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD ||
10725                    p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
10726                 stream f;
10727                 char * f_line;
10728                 buffer *auth_fn;
10729 -               
10730 +
10731                 auth_fn = (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) ? p->conf.auth_htpasswd_userfile : p->conf.auth_plain_userfile;
10732 -               
10733 +
10734                 if (buffer_is_empty(auth_fn)) return -1;
10735 -               
10736 +
10737                 if (0 != stream_open(&f, auth_fn)) {
10738 -                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
10739 +                       log_error_write(srv, __FILE__, __LINE__, "sbss",
10740                                         "opening plain-userfile", auth_fn, "failed:", strerror(errno));
10741 -                       
10742 +
10743                         return -1;
10744                 }
10745 -               
10746 +
10747                 f_line = f.start;
10748 -               
10749 +
10750                 while (f_line - f.start != f.size) {
10751                         char *f_user, *f_pwd, *e;
10752                         size_t u_len, pwd_len;
10753 -                       
10754 +
10755                         f_user = f_line;
10756 -                       
10757 -                       /* 
10758 +
10759 +                       /*
10760                          * htpasswd format
10761 -                        * 
10762 +                        *
10763                          * user:crypted passwd
10764                          */
10765 -                       
10766 +
10767                         if (NULL == (f_pwd = memchr(f_user, ':', f.size - (f_user - f.start) ))) {
10768 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
10769 -                                               "parsed error in", auth_fn, 
10770 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
10771 +                                               "parsed error in", auth_fn,
10772                                                 "expected 'username:hashed password'");
10773 -                               
10774 +
10775                                 stream_close(&f);
10776 -                               
10777 +
10778                                 return -1;
10779                         }
10780 -                       
10781 +
10782                         /* get pointers to the fields */
10783 -                       u_len = f_pwd - f_user; 
10784 +                       u_len = f_pwd - f_user;
10785                         f_pwd++;
10786 -                       
10787 +
10788                         if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
10789                                 pwd_len = e - f_pwd;
10790                         } else {
10791                                 pwd_len = f.size - (f_pwd - f.start);
10792                         }
10793 -                       
10794 +
10795                         if (username->used - 1 == u_len &&
10796                             (0 == strncmp(username->ptr, f_user, u_len))) {
10797                                 /* found */
10798 -                               
10799 +
10800                                 buffer_copy_string_len(password, f_pwd, pwd_len);
10801 -                               
10802 +
10803                                 ret = 0;
10804                                 break;
10805                         }
10806 -                       
10807 +
10808                         /* EOL */
10809                         if (!e) break;
10810 -                       
10811 +
10812                         f_line = e + 1;
10813                 }
10814 -               
10815 +
10816                 stream_close(&f);
10817         } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
10818                 ret = 0;
10819         } else {
10820                 return -1;
10821         }
10822 -       
10823 +
10824         return ret;
10825  }
10826  
10827 @@ -296,7 +286,7 @@
10828         int username_len;
10829         data_string *require;
10830         array *req;
10831 -       
10832 +
10833         UNUSED(group);
10834         UNUSED(host);
10835  
10836 @@ -304,12 +294,12 @@
10837         /* search auth-directives for path */
10838         for (i = 0; i < p->conf.auth_require->used; i++) {
10839                 if (p->conf.auth_require->data[i]->key->used == 0) continue;
10840 -               
10841 +
10842                 if (0 == strncmp(url, p->conf.auth_require->data[i]->key->ptr, p->conf.auth_require->data[i]->key->used - 1)) {
10843                         break;
10844                 }
10845         }
10846 -       
10847 +
10848         if (i == p->conf.auth_require->used) {
10849                 return -1;
10850         }
10851 @@ -317,72 +307,72 @@
10852         req = ((data_array *)(p->conf.auth_require->data[i]))->value;
10853  
10854         require = (data_string *)array_get_element(req, "require");
10855 -       
10856 +
10857         /* if we get here, the user we got a authed user */
10858 -       if (0 == strcmp(require->value->ptr, "valid-user")) {
10859 +       if (buffer_is_equal_string(require->value, CONST_STR_LEN("valid-user"))) {
10860                 return 0;
10861         }
10862 -       
10863 +
10864         /* user=name1|group=name3|host=name4 */
10865 -       
10866 +
10867         /* seperate the string by | */
10868  #if 0
10869         log_error_write(srv, __FILE__, __LINE__, "sb", "rules", require->value);
10870 -#endif 
10871 -       
10872 +#endif
10873 +
10874         username_len = username ? strlen(username) : 0;
10875 -       
10876 +
10877         r = rules = require->value->ptr;
10878 -       
10879 +
10880         while (1) {
10881                 const char *eq;
10882                 const char *k, *v, *e;
10883                 int k_len, v_len, r_len;
10884 -               
10885 +
10886                 e = strchr(r, '|');
10887 -               
10888 +
10889                 if (e) {
10890                         r_len = e - r;
10891                 } else {
10892                         r_len = strlen(rules) - (r - rules);
10893                 }
10894 -               
10895 +
10896                 /* from r to r + r_len is a rule */
10897 -               
10898 +
10899                 if (0 == strncmp(r, "valid-user", r_len)) {
10900 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
10901 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
10902                                         "parsing the 'require' section in 'auth.require' failed: valid-user cannot be combined with other require rules",
10903                                         require->value);
10904                         return -1;
10905                 }
10906 -               
10907 +
10908                 /* search for = in the rules */
10909                 if (NULL == (eq = strchr(r, '='))) {
10910 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
10911 -                                       "parsing the 'require' section in 'auth.require' failed: a = is missing", 
10912 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
10913 +                                       "parsing the 'require' section in 'auth.require' failed: a = is missing",
10914                                         require->value);
10915                         return -1;
10916                 }
10917 -               
10918 +
10919                 /* = out of range */
10920                 if (eq > r + r_len) {
10921 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
10922 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
10923                                         "parsing the 'require' section in 'auth.require' failed: = out of range",
10924                                         require->value);
10925 -                       
10926 +
10927                         return -1;
10928                 }
10929 -               
10930 +
10931                 /* the part before the = is user|group|host */
10932 -               
10933 +
10934                 k = r;
10935                 k_len = eq - r;
10936                 v = eq + 1;
10937                 v_len = r_len - k_len - 1;
10938 -               
10939 +
10940                 if (k_len == 4) {
10941                         if (0 == strncmp(k, "user", k_len)) {
10942 -                               if (username && 
10943 +                               if (username &&
10944                                     username_len == v_len &&
10945                                     0 == strncmp(username, v, v_len)) {
10946                                         return 0;
10947 @@ -404,19 +394,19 @@
10948                         log_error_write(srv, __FILE__, __LINE__, "s", "unknown  key");
10949                         return -1;
10950                 }
10951 -               
10952 +
10953                 if (!e) break;
10954                 r = e + 1;
10955         }
10956 -       
10957 +
10958         log_error_write(srv, __FILE__, __LINE__, "s", "nothing matched");
10959 -       
10960 +
10961         return -1;
10962  }
10963  
10964  /**
10965 - * 
10966 - * 
10967 + *
10968 + *
10969   * @param password password-string from the auth-backend
10970   * @param pw       password-string from the client
10971   */
10972 @@ -426,16 +416,16 @@
10973         UNUSED(req);
10974  
10975         if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
10976 -               /* 
10977 +               /*
10978                  * htdigest format
10979 -                * 
10980 -                * user:realm:md5(user:realm:password) 
10981 +                *
10982 +                * user:realm:md5(user:realm:password)
10983                  */
10984 -               
10985 +
10986                 MD5_CTX Md5Ctx;
10987                 HASH HA1;
10988                 char a1[256];
10989 -               
10990 +
10991                 MD5_Init(&Md5Ctx);
10992                 MD5_Update(&Md5Ctx, (unsigned char *)username->ptr, username->used - 1);
10993                 MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
10994 @@ -443,24 +433,24 @@
10995                 MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
10996                 MD5_Update(&Md5Ctx, (unsigned char *)pw, strlen(pw));
10997                 MD5_Final(HA1, &Md5Ctx);
10998 -               
10999 +
11000                 CvtHex(HA1, a1);
11001 -               
11002 -               if (0 == strcmp(password->ptr, a1)) {
11003 +
11004 +               if (buffer_is_equal_string(password, a1, strlen(a1))) {
11005                         return 0;
11006                 }
11007 -       } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) { 
11008 -#ifdef HAVE_CRYPT      
11009 +       } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) {
11010 +#ifdef HAVE_CRYPT
11011                 char salt[32];
11012                 char *crypted;
11013                 size_t salt_len = 0;
11014 -               /* 
11015 +               /*
11016                  * htpasswd format
11017 -                * 
11018 +                *
11019                  * user:crypted password
11020                  */
11021  
11022 -               /* 
11023 +               /*
11024                  *  Algorithm      Salt
11025                  *  CRYPT_STD_DES   2-character (Default)
11026                  *  CRYPT_EXT_DES   9-character
11027 @@ -478,7 +468,7 @@
11028                         salt_len = 2;
11029                 } else if (password->ptr[0] == '$' && password->ptr[2] == '$') {
11030                         char *dollar = NULL;
11031 -               
11032 +
11033                         if (NULL == (dollar = strchr(password->ptr + 3, '$'))) {
11034                                 fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
11035                                 return -1;
11036 @@ -495,48 +485,21 @@
11037                 strncpy(salt, password->ptr, salt_len);
11038  
11039                 salt[salt_len] = '\0';
11040 -               
11041 +
11042                 crypted = crypt(pw, salt);
11043  
11044 -               if (0 == strcmp(password->ptr, crypted)) {
11045 +               if (buffer_is_equal_string(password, crypted, strlen(crypted))) {
11046                         return 0;
11047                 } else {
11048                         fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
11049                 }
11050 -       
11051 -#endif 
11052 -       } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) { 
11053 -               if (0 == strcmp(password->ptr, pw)) {
11054 -                       return 0;
11055 -               }
11056 -       } else if (p->conf.auth_backend == AUTH_BACKEND_PAM) { 
11057 -#ifdef USE_PAM
11058 -               pam_handle_t *pamh=NULL;
11059 -               int retval;
11060 -               
11061 -               retval = pam_start("lighttpd", username->ptr, &conv, &pamh);
11062 -               
11063 -               if (retval == PAM_SUCCESS)
11064 -                       retval = pam_authenticate(pamh, 0);    /* is user really user? */
11065 -               
11066 -               if (retval == PAM_SUCCESS)
11067 -                       retval = pam_acct_mgmt(pamh, 0);       /* permitted access? */
11068 -               
11069 -               /* This is where we have been authorized or not. */
11070 -               
11071 -               if (pam_end(pamh,retval) != PAM_SUCCESS) {     /* close Linux-PAM */
11072 -                       pamh = NULL;
11073 -                       log_error_write(srv, __FILE__, __LINE__, "s", "failed to release authenticator");
11074 -               }
11075 -               
11076 -               if (retval == PAM_SUCCESS) {
11077 -                       log_error_write(srv, __FILE__, __LINE__, "s", "Authenticated");
11078 +
11079 +#endif
11080 +       } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
11081 +               if (buffer_is_equal_string(password, pw, strlen(pw))) {
11082                         return 0;
11083 -               } else {
11084 -                       log_error_write(srv, __FILE__, __LINE__, "s", "Not Authenticated");
11085                 }
11086 -#endif
11087 -       } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) { 
11088 +       } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
11089  #ifdef USE_LDAP
11090                 LDAP *ldap;
11091                 LDAPMessage *lm, *first;
11092 @@ -544,45 +507,45 @@
11093                 int ret;
11094                 char *attrs[] = { LDAP_NO_ATTRS, NULL };
11095                 size_t i;
11096 -               
11097 +
11098                 /* for now we stay synchronous */
11099 -               
11100 -               /* 
11101 +
11102 +               /*
11103                  * 1. connect anonymously (done in plugin init)
11104                  * 2. get DN for uid = username
11105                  * 3. auth against ldap server
11106                  * 4. (optional) check a field
11107                  * 5. disconnect
11108 -                * 
11109 +                *
11110                  */
11111 -               
11112 +
11113                 /* check username
11114 -                * 
11115 +                *
11116                  * we have to protect us againt username which modifies out filter in
11117                  * a unpleasant way
11118                  */
11119 -               
11120 +
11121                 for (i = 0; i < username->used - 1; i++) {
11122                         char c = username->ptr[i];
11123 -                       
11124 +
11125                         if (!isalpha(c) &&
11126                             !isdigit(c)) {
11127 -                               
11128 -                               log_error_write(srv, __FILE__, __LINE__, "sbd", 
11129 +
11130 +                               log_error_write(srv, __FILE__, __LINE__, "sbd",
11131                                         "ldap: invalid character (a-zA-Z0-9 allowed) in username:", username, i);
11132 -                               
11133 +
11134                                 return -1;
11135                         }
11136                 }
11137 -               
11138 -               
11139 -               
11140 +
11141 +
11142 +
11143                 /* build filter */
11144                 buffer_copy_string_buffer(p->ldap_filter, p->conf.ldap_filter_pre);
11145                 buffer_append_string_buffer(p->ldap_filter, username);
11146                 buffer_append_string_buffer(p->ldap_filter, p->conf.ldap_filter_post);
11147 -               
11148 -               
11149 +
11150 +
11151                 /* 2. */
11152                 if (p->conf.ldap == NULL ||
11153                     LDAP_SUCCESS != (ret = ldap_search_s(p->conf.ldap, p->conf.auth_ldap_basedn->ptr, LDAP_SCOPE_SUBTREE, p->ldap_filter->ptr, attrs, 0, &lm))) {
11154 @@ -590,71 +553,71 @@
11155                                 return -1;
11156                         if (LDAP_SUCCESS != (ret = ldap_search_s(p->conf.ldap, p->conf.auth_ldap_basedn->ptr, LDAP_SCOPE_SUBTREE, p->ldap_filter->ptr, attrs, 0, &lm))) {
11157  
11158 -                       log_error_write(srv, __FILE__, __LINE__, "sssb", 
11159 +                       log_error_write(srv, __FILE__, __LINE__, "sssb",
11160                                         "ldap:", ldap_err2string(ret), "filter:", p->ldap_filter);
11161 -                       
11162 +
11163                         return -1;
11164                         }
11165                 }
11166 -               
11167 +
11168                 if (NULL == (first = ldap_first_entry(p->conf.ldap, lm))) {
11169                         log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
11170 -                       
11171 +
11172                         ldap_msgfree(lm);
11173 -                       
11174 +
11175                         return -1;
11176                 }
11177 -               
11178 +
11179                 if (NULL == (dn = ldap_get_dn(p->conf.ldap, first))) {
11180                         log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
11181 -                       
11182 +
11183                         ldap_msgfree(lm);
11184 -                       
11185 +
11186                         return -1;
11187                 }
11188 -               
11189 +
11190                 ldap_msgfree(lm);
11191 -               
11192 -               
11193 +
11194 +
11195                 /* 3. */
11196                 if (NULL == (ldap = ldap_init(p->conf.auth_ldap_hostname->ptr, LDAP_PORT))) {
11197                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno));
11198                         return -1;
11199                 }
11200 -               
11201 +
11202                 ret = LDAP_VERSION3;
11203                 if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) {
11204                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
11205 -                       
11206 +
11207                         ldap_unbind_s(ldap);
11208 -                       
11209 +
11210                         return -1;
11211                 }
11212 -               
11213 +
11214                 if (p->conf.auth_ldap_starttls == 1) {
11215                         if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(ldap, NULL,  NULL))) {
11216                                 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
11217 -               
11218 +
11219                                 ldap_unbind_s(ldap);
11220 -                               
11221 +
11222                                 return -1;
11223                         }
11224                 }
11225  
11226 -               
11227 +
11228                 if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(ldap, dn, pw))) {
11229                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
11230 -                       
11231 +
11232                         ldap_unbind_s(ldap);
11233 -                       
11234 +
11235                         return -1;
11236                 }
11237 -               
11238 +
11239                 /* 5. */
11240                 ldap_unbind_s(ldap);
11241 -               
11242 +
11243                 /* everything worked, good, access granted */
11244 -               
11245 +
11246                 return 0;
11247  #endif
11248         }
11249 @@ -664,65 +627,65 @@
11250  int http_auth_basic_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) {
11251         buffer *username, *password;
11252         char *pw;
11253 -       
11254 +
11255         data_string *realm;
11256 -       
11257 +
11258         realm = (data_string *)array_get_element(req, "realm");
11259 -       
11260 +
11261         username = buffer_init();
11262         password = buffer_init();
11263 -       
11264 +
11265         base64_decode(username, realm_str);
11266 -       
11267 +
11268         /* r2 == user:password */
11269         if (NULL == (pw = strchr(username->ptr, ':'))) {
11270                 buffer_free(username);
11271 -               
11272 +
11273                 log_error_write(srv, __FILE__, __LINE__, "sb", ": is missing in", username);
11274 -               
11275 +
11276                 return 0;
11277         }
11278 -       
11279 +
11280         *pw++ = '\0';
11281 -       
11282 +
11283         username->used = pw - username->ptr;
11284 -       
11285 +
11286         /* copy password to r1 */
11287         if (http_auth_get_password(srv, p, username, realm->value, password)) {
11288                 buffer_free(username);
11289                 buffer_free(password);
11290 -               
11291 +
11292                 log_error_write(srv, __FILE__, __LINE__, "s", "get_password failed");
11293 -               
11294 +
11295                 return 0;
11296         }
11297 -       
11298 +
11299         /* password doesn't match */
11300         if (http_auth_basic_password_compare(srv, p, req, username, realm->value, password, pw)) {
11301                 log_error_write(srv, __FILE__, __LINE__, "sbb", "password doesn't match for", con->uri.path, username);
11302 -               
11303 +
11304                 buffer_free(username);
11305                 buffer_free(password);
11306 -               
11307 +
11308                 return 0;
11309         }
11310 -       
11311 +
11312         /* value is our allow-rules */
11313         if (http_auth_match_rules(srv, p, url->ptr, username->ptr, NULL, NULL)) {
11314                 buffer_free(username);
11315                 buffer_free(password);
11316 -               
11317 +
11318                 log_error_write(srv, __FILE__, __LINE__, "s", "rules didn't match");
11319 -               
11320 +
11321                 return 0;
11322         }
11323 -       
11324 +
11325         /* remember the username */
11326         buffer_copy_string_buffer(p->auth_user, username);
11327 -       
11328 +
11329         buffer_free(username);
11330         buffer_free(password);
11331 -       
11332 +
11333         return 1;
11334  }
11335  
11336 @@ -735,7 +698,7 @@
11337  int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) {
11338         char a1[256];
11339         char a2[256];
11340 -       
11341 +
11342         char *username;
11343         char *realm;
11344         char *nonce;
11345 @@ -745,18 +708,18 @@
11346         char *cnonce;
11347         char *nc;
11348         char *respons;
11349 -       
11350 +
11351         char *e, *c;
11352         const char *m = NULL;
11353         int i;
11354         buffer *password, *b, *username_buf, *realm_buf;
11355 -       
11356 +
11357         MD5_CTX Md5Ctx;
11358         HASH HA1;
11359         HASH HA2;
11360         HASH RespHash;
11361         HASHHEX HA2Hex;
11362 -       
11363 +
11364  
11365         /* init pointers */
11366  #define S(x) \
11367 @@ -771,11 +734,11 @@
11368                 { S("cnonce=") },
11369                 { S("nc=") },
11370                 { S("response=") },
11371 -               
11372 +
11373                 { NULL, 0, NULL }
11374         };
11375  #undef S
11376 -       
11377 +
11378         dkv[0].ptr = &username;
11379         dkv[1].ptr = &realm;
11380         dkv[2].ptr = &nonce;
11381 @@ -786,24 +749,24 @@
11382         dkv[7].ptr = &nc;
11383         dkv[8].ptr = &respons;
11384         dkv[9].ptr = NULL;
11385 -       
11386 +
11387         UNUSED(req);
11388 -       
11389 +
11390         for (i = 0; dkv[i].key; i++) {
11391                 *(dkv[i].ptr) = NULL;
11392         }
11393 -       
11394 -       
11395 +
11396 +
11397         if (p->conf.auth_backend != AUTH_BACKEND_HTDIGEST &&
11398             p->conf.auth_backend != AUTH_BACKEND_PLAIN) {
11399 -               log_error_write(srv, __FILE__, __LINE__, "s", 
11400 +               log_error_write(srv, __FILE__, __LINE__, "s",
11401                                 "digest: unsupported backend (only htdigest or plain)");
11402 -               
11403 +
11404                 return -1;
11405         }
11406 -       
11407 +
11408         b = buffer_init_string(realm_str);
11409 -       
11410 +
11411         /* parse credentials from client */
11412         for (c = b->ptr; *c; c++) {
11413                 /* skip whitespaces */
11414 @@ -812,18 +775,18 @@
11415  
11416                 for (i = 0; dkv[i].key; i++) {
11417                         if ((0 == strncmp(c, dkv[i].key, dkv[i].key_len))) {
11418 -                               if ((c[dkv[i].key_len] == '"') && 
11419 +                               if ((c[dkv[i].key_len] == '"') &&
11420                                     (NULL != (e = strchr(c + dkv[i].key_len + 1, '"')))) {
11421                                         /* value with "..." */
11422                                         *(dkv[i].ptr) = c + dkv[i].key_len + 1;
11423                                         c = e;
11424 -       
11425 +
11426                                         *e = '\0';
11427                                 } else if (NULL != (e = strchr(c + dkv[i].key_len, ','))) {
11428                                         /* value without "...", terminated by ',' */
11429                                         *(dkv[i].ptr) = c + dkv[i].key_len;
11430                                         c = e;
11431 -                                       
11432 +
11433                                         *e = '\0';
11434                                 } else {
11435                                         /* value without "...", terminated by EOL */
11436 @@ -833,7 +796,7 @@
11437                         }
11438                 }
11439         }
11440 -       
11441 +
11442         if (p->conf.auth_debug > 1) {
11443                 log_error_write(srv, __FILE__, __LINE__, "ss", "username", username);
11444                 log_error_write(srv, __FILE__, __LINE__, "ss", "realm", realm);
11445 @@ -845,22 +808,22 @@
11446                 log_error_write(srv, __FILE__, __LINE__, "ss", "nc", nc);
11447                 log_error_write(srv, __FILE__, __LINE__, "ss", "response", respons);
11448         }
11449 -       
11450 +
11451         /* check if everything is transmitted */
11452 -       if (!username || 
11453 +       if (!username ||
11454             !realm ||
11455             !nonce ||
11456             !uri ||
11457             (qop && (!nc || !cnonce)) ||
11458             !respons ) {
11459                 /* missing field */
11460 -               
11461 -               log_error_write(srv, __FILE__, __LINE__, "s", 
11462 +
11463 +               log_error_write(srv, __FILE__, __LINE__, "s",
11464                                 "digest: missing field");
11465                 return -1;
11466         }
11467  
11468 -       m = get_http_method_name(con->request.http_method);     
11469 +       m = get_http_method_name(con->request.http_method);
11470  
11471         /* password-string == HA1 */
11472         password = buffer_init();
11473 @@ -873,10 +836,10 @@
11474                 buffer_free(realm_buf);
11475                 return 0;
11476         }
11477 -       
11478 +
11479         buffer_free(username_buf);
11480         buffer_free(realm_buf);
11481 -       
11482 +
11483         if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
11484                 /* generate password from plain-text */
11485                 MD5_Init(&Md5Ctx);
11486 @@ -890,16 +853,16 @@
11487                 /* HA1 */
11488                 /* transform the 32-byte-hex-md5 to a 16-byte-md5 */
11489                 for (i = 0; i < HASHLEN; i++) {
11490 -                       HA1[i] = hex2int(password->ptr[i*2]) << 4; 
11491 -                       HA1[i] |= hex2int(password->ptr[i*2+1]); 
11492 +                       HA1[i] = hex2int(password->ptr[i*2]) << 4;
11493 +                       HA1[i] |= hex2int(password->ptr[i*2+1]);
11494                 }
11495         } else {
11496                 /* we already check that above */
11497                 SEGFAULT();
11498         }
11499 -       
11500 +
11501         buffer_free(password);
11502 -       
11503 +
11504         if (algorithm &&
11505             strcasecmp(algorithm, "md5-sess") == 0) {
11506                 MD5_Init(&Md5Ctx);
11507 @@ -910,9 +873,9 @@
11508                 MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce));
11509                 MD5_Final(HA1, &Md5Ctx);
11510         }
11511 -       
11512 +
11513         CvtHex(HA1, a1);
11514 -       
11515 +
11516         /* calculate H(A2) */
11517         MD5_Init(&Md5Ctx);
11518         MD5_Update(&Md5Ctx, (unsigned char *)m, strlen(m));
11519 @@ -924,7 +887,7 @@
11520         }
11521         MD5_Final(HA2, &Md5Ctx);
11522         CvtHex(HA2, HA2Hex);
11523 -       
11524 +
11525         /* calculate response */
11526         MD5_Init(&Md5Ctx);
11527         MD5_Update(&Md5Ctx, (unsigned char *)a1, HASHHEXLEN);
11528 @@ -942,39 +905,39 @@
11529         MD5_Update(&Md5Ctx, (unsigned char *)HA2Hex, HASHHEXLEN);
11530         MD5_Final(RespHash, &Md5Ctx);
11531         CvtHex(RespHash, a2);
11532 -       
11533 +
11534         if (0 != strcmp(a2, respons)) {
11535                 /* digest not ok */
11536 -               
11537 +
11538                 if (p->conf.auth_debug) {
11539 -                       log_error_write(srv, __FILE__, __LINE__, "sss", 
11540 +                       log_error_write(srv, __FILE__, __LINE__, "sss",
11541                                 "digest: digest mismatch", a2, respons);
11542                 }
11543 -               
11544 -               log_error_write(srv, __FILE__, __LINE__, "sss", 
11545 +
11546 +               log_error_write(srv, __FILE__, __LINE__, "sss",
11547                                 "digest: auth failed for", username, "wrong password");
11548 -               
11549 +
11550                 buffer_free(b);
11551                 return 0;
11552         }
11553 -       
11554 +
11555         /* value is our allow-rules */
11556         if (http_auth_match_rules(srv, p, url->ptr, username, NULL, NULL)) {
11557                 buffer_free(b);
11558 -               
11559 -               log_error_write(srv, __FILE__, __LINE__, "s", 
11560 +
11561 +               log_error_write(srv, __FILE__, __LINE__, "s",
11562                                 "digest: rules did match");
11563 -               
11564 +
11565                 return 0;
11566         }
11567 -       
11568 +
11569         /* remember the username */
11570         buffer_copy_string(p->auth_user, username);
11571 -       
11572 +
11573         buffer_free(b);
11574 -       
11575 +
11576         if (p->conf.auth_debug) {
11577 -               log_error_write(srv, __FILE__, __LINE__, "s", 
11578 +               log_error_write(srv, __FILE__, __LINE__, "s",
11579                                 "digest: auth ok");
11580         }
11581         return 1;
11582 @@ -985,23 +948,23 @@
11583         HASH h;
11584         MD5_CTX Md5Ctx;
11585         char hh[32];
11586 -       
11587 +
11588         UNUSED(p);
11589  
11590         /* generate shared-secret */
11591         MD5_Init(&Md5Ctx);
11592         MD5_Update(&Md5Ctx, (unsigned char *)fn->ptr, fn->used - 1);
11593         MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
11594 -       
11595 +
11596         /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
11597         ltostr(hh, srv->cur_ts);
11598         MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
11599         ltostr(hh, rand());
11600         MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
11601 -       
11602 +
11603         MD5_Final(h, &Md5Ctx);
11604 -       
11605 +
11606         CvtHex(h, out);
11607 -       
11608 +
11609         return 0;
11610  }
11611 --- ../lighttpd-1.4.11/src/http_auth.h  2005-08-14 17:12:31.000000000 +0300
11612 +++ lighttpd-1.4.12/src/http_auth.h     2006-07-16 00:26:04.000000000 +0300
11613 @@ -9,22 +9,26 @@
11614  # include <ldap.h>
11615  #endif
11616  
11617 -typedef enum { AUTH_BACKEND_UNSET, AUTH_BACKEND_PLAIN, 
11618 -               AUTH_BACKEND_LDAP, AUTH_BACKEND_HTPASSWD, 
11619 -               AUTH_BACKEND_HTDIGEST, AUTH_BACKEND_PAM } auth_backend_t;
11620 +typedef enum {
11621 +       AUTH_BACKEND_UNSET,
11622 +       AUTH_BACKEND_PLAIN,
11623 +       AUTH_BACKEND_LDAP,
11624 +       AUTH_BACKEND_HTPASSWD,
11625 +       AUTH_BACKEND_HTDIGEST
11626 +} auth_backend_t;
11627  
11628  typedef struct {
11629         /* auth */
11630         array  *auth_require;
11631 -       
11632 +
11633         buffer *auth_plain_groupfile;
11634         buffer *auth_plain_userfile;
11635 -       
11636 +
11637         buffer *auth_htdigest_userfile;
11638         buffer *auth_htpasswd_userfile;
11639 -       
11640 +
11641         buffer *auth_backend_conf;
11642 -       
11643 +
11644         buffer *auth_ldap_hostname;
11645         buffer *auth_ldap_basedn;
11646         buffer *auth_ldap_binddn;
11647 @@ -32,15 +36,15 @@
11648         buffer *auth_ldap_filter;
11649         buffer *auth_ldap_cafile;
11650         unsigned short auth_ldap_starttls;
11651 -       
11652 +
11653         unsigned short auth_debug;
11654 -       
11655 +
11656         /* generated */
11657         auth_backend_t auth_backend;
11658 -       
11659 +
11660  #ifdef USE_LDAP
11661         LDAP *ldap;
11662 -       
11663 +
11664         buffer *ldap_filter_pre;
11665         buffer *ldap_filter_post;
11666  #endif
11667 @@ -49,15 +53,15 @@
11668  typedef struct {
11669         PLUGIN_DATA;
11670         buffer *tmp_buf;
11671 -       
11672 +
11673         buffer *auth_user;
11674  
11675  #ifdef USE_LDAP
11676         buffer *ldap_filter;
11677  #endif
11678 -       
11679 +
11680         mod_auth_plugin_config **config_storage;
11681 -       
11682 +
11683         mod_auth_plugin_config conf; /* this is only used as long as no handler_ctx is setup */
11684  } mod_auth_plugin_data;
11685  
11686 --- ../lighttpd-1.4.11/src/http_auth_digest.h   2006-01-05 00:54:01.000000000 +0200
11687 +++ lighttpd-1.4.12/src/http_auth_digest.h      2006-07-16 00:26:04.000000000 +0300
11688 @@ -12,7 +12,7 @@
11689  #ifdef USE_OPENSSL
11690  #define IN const
11691  #else
11692 -#define IN 
11693 +#define IN
11694  #endif
11695  #define OUT
11696  
11697 --- ../lighttpd-1.4.11/src/http_chunk.c 2005-08-11 01:26:50.000000000 +0300
11698 +++ lighttpd-1.4.12/src/http_chunk.c    2006-07-16 00:26:04.000000000 +0300
11699 @@ -1,7 +1,7 @@
11700  /**
11701   * the HTTP chunk-API
11702 - * 
11703 - * 
11704 + *
11705 + *
11706   */
11707  
11708  #include <sys/types.h>
11709 @@ -9,7 +9,6 @@
11710  
11711  #include <stdlib.h>
11712  #include <fcntl.h>
11713 -#include <unistd.h>
11714  
11715  #include <stdio.h>
11716  #include <errno.h>
11717 @@ -23,19 +22,19 @@
11718  static int http_chunk_append_len(server *srv, connection *con, size_t len) {
11719         size_t i, olen = len, j;
11720         buffer *b;
11721 -       
11722 +
11723         b = srv->tmp_chunk_len;
11724 -       
11725 +
11726         if (len == 0) {
11727                 buffer_copy_string(b, "0");
11728         } else {
11729                 for (i = 0; i < 8 && len; i++) {
11730                         len >>= 4;
11731                 }
11732 -               
11733 +
11734                 /* i is the number of hex digits we have */
11735                 buffer_prepare_copy(b, i + 1);
11736 -               
11737 +
11738                 for (j = i-1, len = olen; j+1 > 0; j--) {
11739                         b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10);
11740                         len >>= 4;
11741 @@ -43,61 +42,61 @@
11742                 b->used = i;
11743                 b->ptr[b->used++] = '\0';
11744         }
11745 -               
11746 +
11747         buffer_append_string(b, "\r\n");
11748         chunkqueue_append_buffer(con->write_queue, b);
11749 -       
11750 +
11751         return 0;
11752  }
11753  
11754  
11755  int http_chunk_append_file(server *srv, connection *con, buffer *fn, off_t offset, off_t len) {
11756         chunkqueue *cq;
11757 -       
11758 +
11759         if (!con) return -1;
11760 -       
11761 +
11762         cq = con->write_queue;
11763 -       
11764 +
11765         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11766                 http_chunk_append_len(srv, con, len);
11767         }
11768 -       
11769 +
11770         chunkqueue_append_file(cq, fn, offset, len);
11771 -       
11772 +
11773         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && len > 0) {
11774                 chunkqueue_append_mem(cq, "\r\n", 2 + 1);
11775         }
11776 -       
11777 +
11778         return 0;
11779  }
11780  
11781  int http_chunk_append_buffer(server *srv, connection *con, buffer *mem) {
11782         chunkqueue *cq;
11783 -       
11784 +
11785         if (!con) return -1;
11786 -       
11787 +
11788         cq = con->write_queue;
11789 -       
11790 +
11791         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11792                 http_chunk_append_len(srv, con, mem->used - 1);
11793         }
11794 -       
11795 +
11796         chunkqueue_append_buffer(cq, mem);
11797 -       
11798 +
11799         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && mem->used > 0) {
11800                 chunkqueue_append_mem(cq, "\r\n", 2 + 1);
11801         }
11802 -       
11803 +
11804         return 0;
11805  }
11806  
11807  int http_chunk_append_mem(server *srv, connection *con, const char * mem, size_t len) {
11808         chunkqueue *cq;
11809 -       
11810 +
11811         if (!con) return -1;
11812 -       
11813 +
11814         cq = con->write_queue;
11815 -       
11816 +
11817         if (len == 0) {
11818                 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11819                         http_chunk_append_len(srv, con, 0);
11820 @@ -107,17 +106,17 @@
11821                 }
11822                 return 0;
11823         }
11824 -       
11825 +
11826         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11827                 http_chunk_append_len(srv, con, len - 1);
11828         }
11829 -       
11830 +
11831         chunkqueue_append_mem(cq, mem, len);
11832 -       
11833 +
11834         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11835                 chunkqueue_append_mem(cq, "\r\n", 2 + 1);
11836         }
11837 -       
11838 +
11839         return 0;
11840  }
11841  
11842 @@ -125,9 +124,9 @@
11843  off_t http_chunkqueue_length(server *srv, connection *con) {
11844         if (!con) {
11845                 log_error_write(srv, __FILE__, __LINE__, "s", "connection is NULL!!");
11846 -               
11847 +
11848                 return 0;
11849         }
11850 -       
11851 +
11852         return chunkqueue_length(con->write_queue);
11853  }
11854 --- ../lighttpd-1.4.11/src/http_resp.c  1970-01-01 03:00:00.000000000 +0300
11855 +++ lighttpd-1.4.12/src/http_resp.c     2006-07-18 13:03:40.000000000 +0300
11856 @@ -0,0 +1,277 @@
11857 +#include <string.h>
11858 +#include <stdlib.h>
11859 +#include <stdio.h>
11860 +#include <assert.h>
11861 +
11862 +#include "log.h"
11863 +#include "http_resp.h"
11864 +#include "http_resp_parser.h"
11865 +
11866 +/* declare prototypes for the parser */
11867 +void *http_resp_parserAlloc(void *(*mallocProc)(size_t));
11868 +void http_resp_parserFree(void *p,  void (*freeProc)(void*));
11869 +void http_resp_parserTrace(FILE *TraceFILE, char *zTracePrompt);
11870 +void http_resp_parser(void *, int, buffer *, http_resp_ctx_t *);
11871 +
11872 +typedef struct {
11873 +       chunkqueue *cq;
11874 +
11875 +       chunk *c; /* current chunk in the chunkqueue */
11876 +       size_t offset; /* current offset in current chunk */
11877 +
11878 +       chunk *lookup_c;
11879 +       size_t lookup_offset;
11880 +
11881 +       int is_key;
11882 +       int is_statusline;
11883 +} http_resp_tokenizer_t;
11884 +
11885 +http_resp *http_response_init(void) {
11886 +       http_resp *resp = calloc(1, sizeof(*resp));
11887 +
11888 +       resp->reason = buffer_init();
11889 +       resp->headers = array_init();
11890 +
11891 +       return resp;
11892 +}
11893 +
11894 +void http_response_reset(http_resp *resp) {
11895 +       if (!resp) return;
11896 +
11897 +       buffer_reset(resp->reason);
11898 +       array_reset(resp->headers);
11899 +
11900 +}
11901 +
11902 +void http_response_free(http_resp *resp) {
11903 +       if (!resp) return;
11904 +
11905 +       buffer_free(resp->reason);
11906 +       array_free(resp->headers);
11907 +
11908 +       free(resp);
11909 +}
11910 +
11911 +static int http_resp_get_next_char(http_resp_tokenizer_t *t, unsigned char *c) {
11912 +       if (t->offset == t->c->mem->used - 1) {
11913 +               /* end of chunk, open next chunk */
11914 +
11915 +               if (!t->c->next) return -1;
11916 +
11917 +               t->c = t->c->next;
11918 +               t->offset = 0;
11919 +       }
11920 +
11921 +       *c = t->c->mem->ptr[t->offset++];
11922 +
11923 +       t->lookup_offset = t->offset;
11924 +       t->lookup_c = t->c;
11925 +
11926 +#if 0
11927 +       fprintf(stderr, "%s.%d: get: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->offset - 1);
11928 +#endif
11929 +
11930 +       return 0;
11931 +}
11932 +
11933 +static int http_resp_lookup_next_char(http_resp_tokenizer_t *t, unsigned char *c) {
11934 +       if (t->lookup_offset == t->lookup_c->mem->used - 1) {
11935 +               /* end of chunk, open next chunk */
11936 +
11937 +               if (!t->lookup_c->next) return -1;
11938 +
11939 +               t->lookup_c = t->lookup_c->next;
11940 +               t->lookup_offset = 0;
11941 +       }
11942 +
11943 +       *c = t->lookup_c->mem->ptr[t->lookup_offset++];
11944 +#if 0
11945 +       fprintf(stderr, "%s.%d: lookup: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->lookup_offset - 1);
11946 +#endif
11947 +
11948 +       return 0;
11949 +}
11950 +
11951 +
11952 +static int http_resp_tokenizer(
11953 +       http_resp_tokenizer_t *t,
11954 +       int *token_id,
11955 +       buffer *token
11956 +) {
11957 +       unsigned char c;
11958 +       int tid = 0;
11959 +
11960 +       /* push the token to the parser */
11961 +
11962 +       while (tid == 0 && 0 == http_resp_get_next_char(t, &c)) {
11963 +               switch (c) {
11964 +               case ':':
11965 +                       tid = TK_COLON;
11966 +
11967 +                       t->is_key = 0;
11968 +
11969 +                       break;
11970 +               case ' ':
11971 +               case '\t':
11972 +                       /* ignore WS */
11973 +
11974 +                       break;
11975 +               case '\r':
11976 +                       if (0 != http_resp_lookup_next_char(t, &c)) return -1;
11977 +
11978 +                       if (c == '\n') {
11979 +                               tid = TK_CRLF;
11980 +
11981 +                               t->c = t->lookup_c;
11982 +                               t->offset = t->lookup_offset;
11983 +
11984 +                               t->is_statusline = 0;
11985 +                               t->is_key = 1;
11986 +                       } else {
11987 +                               fprintf(stderr, "%s.%d: CR with out LF\r\n", __FILE__, __LINE__);
11988 +                               return -1;
11989 +                       }
11990 +                       break;
11991 +               case '\n':
11992 +                       tid = TK_CRLF;
11993 +
11994 +                       t->is_statusline = 0;
11995 +                       t->is_key = 1;
11996 +
11997 +                       break;
11998 +               default:
11999 +                       while (c >= 32 && c != 127 && c != 255) {
12000 +                               if (t->is_statusline) {
12001 +                                       if (c == ':') { t->is_statusline = 0; break; } /* this is not a status line by a real header */
12002 +                                       if (c == 32) break; /* the space is a splitter in the statusline */
12003 +                               } else {
12004 +                                       if (t->is_key) {
12005 +                                               if (c == ':') break; /* the : is the splitter between key and value */
12006 +                                       }
12007 +                               }
12008 +                               if (0 != http_resp_lookup_next_char(t, &c)) return -1;
12009 +                       }
12010 +
12011 +                       if (t->c == t->lookup_c &&
12012 +                               t->offset == t->lookup_offset + 1) {
12013 +
12014 +                               fprintf(stderr, "%s.%d: invalid char in string\n", __FILE__, __LINE__);
12015 +                               return -1;
12016 +                       }
12017 +
12018 +                       tid = TK_STRING;
12019 +
12020 +                       /* the lookup points to the first invalid char */
12021 +                       t->lookup_offset--;
12022 +
12023 +                       /* no overlapping string */
12024 +                       if (t->c == t->lookup_c) {
12025 +                               buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->lookup_offset - t->offset + 1);
12026 +                       } else {
12027 +                               /* first chunk */
12028 +                               buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->c->mem->used - t->offset);
12029 +
12030 +                               /* chunks in the middle */
12031 +                               for (t->c = t->c->next; t->c != t->lookup_c; t->c = t->c->next) {
12032 +                                       buffer_append_string_buffer(token, t->c->mem);
12033 +                                       t->offset = t->c->mem->used - 1;
12034 +                               }
12035 +
12036 +                               /* last chunk */
12037 +                               buffer_append_string_len(token, t->c->mem->ptr, t->lookup_offset);
12038 +                       }
12039 +
12040 +                       t->offset = t->lookup_offset;
12041 +
12042 +                       break;
12043 +               }
12044 +       }
12045 +
12046 +       if (tid) {
12047 +               *token_id = tid;
12048 +
12049 +               return 1;
12050 +       }
12051 +
12052 +       return -1;
12053 +}
12054 +
12055 +parse_status_t http_response_parse_cq(chunkqueue *cq, http_resp *resp) {
12056 +       http_resp_tokenizer_t t;
12057 +       void *pParser = NULL;
12058 +       int token_id = 0;
12059 +       buffer *token = NULL;
12060 +       http_resp_ctx_t context;
12061 +       parse_status_t ret = PARSE_UNSET;
12062 +       int last_token_id = 0;
12063 +
12064 +       t.cq = cq;
12065 +       t.c = cq->first;
12066 +       t.offset = t.c->offset;
12067 +       t.is_key = 0;
12068 +       t.is_statusline = 1;
12069 +
12070 +       context.ok = 1;
12071 +       context.errmsg = buffer_init();
12072 +       context.resp = resp;
12073 +
12074 +       pParser = http_resp_parserAlloc( malloc );
12075 +       token = buffer_init();
12076 +#if 0
12077 +       http_resp_parserTrace(stderr, "http-response: "); 
12078 +#endif
12079 +
12080 +       while((1 == http_resp_tokenizer(&t, &token_id, token)) && context.ok) {
12081 +               http_resp_parser(pParser, token_id, token, &context);
12082 +
12083 +               token = buffer_init();
12084 +
12085 +               /* CRLF CRLF ... the header end sequence */
12086 +               if (last_token_id == TK_CRLF &&
12087 +                   token_id == TK_CRLF) break;
12088 +
12089 +               last_token_id = token_id;
12090 +       }
12091 +
12092 +       /* oops, the parser failed */
12093 +       if (context.ok == 0) {
12094 +               ret = PARSE_ERROR;
12095 +
12096 +               if (!buffer_is_empty(context.errmsg)) {
12097 +                       TRACE("parsing failed: %s", BUF_STR(context.errmsg));
12098 +               } else {
12099 +                       TRACE("%s", "parsing failed ...");
12100 +               }
12101 +       }
12102 +
12103 +       http_resp_parser(pParser, 0, token, &context);
12104 +       http_resp_parserFree(pParser, free);
12105 +
12106 +       if (context.ok == 0) {
12107 +               /* we are missing the some tokens */
12108 +
12109 +               if (!buffer_is_empty(context.errmsg)) {
12110 +                       TRACE("parsing failed: %s", BUF_STR(context.errmsg));
12111 +               }
12112 +
12113 +               if (ret == PARSE_UNSET) {
12114 +                       ret = buffer_is_empty(context.errmsg) ? PARSE_NEED_MORE : PARSE_ERROR;
12115 +               }
12116 +       } else {
12117 +               chunk *c;
12118 +
12119 +               for (c = cq->first; c != t.c; c = c->next) {
12120 +                       c->offset = c->mem->used - 1;
12121 +               }
12122 +
12123 +               c->offset = t.offset;
12124 +
12125 +               ret = PARSE_SUCCESS;
12126 +       }
12127 +
12128 +       buffer_free(token);
12129 +       buffer_free(context.errmsg);
12130 +
12131 +       return ret;
12132 +}
12133 +
12134 --- ../lighttpd-1.4.11/src/http_resp.h  1970-01-01 03:00:00.000000000 +0300
12135 +++ lighttpd-1.4.12/src/http_resp.h     2006-07-16 00:26:04.000000000 +0300
12136 @@ -0,0 +1,34 @@
12137 +#ifndef _HTTP_RESP_H_
12138 +#define _HTTP_RESP_H_
12139 +
12140 +#include "array.h"
12141 +#include "chunk.h"
12142 +
12143 +typedef enum {
12144 +    PARSE_UNSET,
12145 +    PARSE_SUCCESS,
12146 +    PARSE_ERROR,
12147 +    PARSE_NEED_MORE
12148 +} parse_status_t;
12149 +
12150 +typedef struct {
12151 +    int protocol;   /* http/1.0, http/1.1 */
12152 +    int status;     /* e.g. 200 */
12153 +    buffer *reason; /* e.g. Ok */
12154 +    array *headers;
12155 +} http_resp;
12156 +
12157 +typedef struct {
12158 +       int     ok;
12159 +    buffer *errmsg;
12160 +
12161 +    http_resp *resp;
12162 +} http_resp_ctx_t;
12163 +
12164 +http_resp *http_response_init(void);
12165 +void http_response_free(http_resp *resp);
12166 +void http_response_reset(http_resp *resp);
12167 +
12168 +parse_status_t http_response_parse_cq(chunkqueue *cq, http_resp *http_response);
12169 +
12170 +#endif
12171 --- ../lighttpd-1.4.11/src/http_resp_parser.c   1970-01-01 03:00:00.000000000 +0300
12172 +++ lighttpd-1.4.12/src/http_resp_parser.c      2006-07-18 13:03:52.000000000 +0300
12173 @@ -0,0 +1,901 @@
12174 +/* Driver template for the LEMON parser generator.
12175 +** The author disclaims copyright to this source code.
12176 +*/
12177 +/* First off, code is include which follows the "include" declaration
12178 +** in the input file. */
12179 +#include <stdio.h>
12180 +#line 6 "./http_resp_parser.y"
12181 +
12182 +#include <assert.h>
12183 +#include <string.h>
12184 +#include "http_resp.h"
12185 +#include "keyvalue.h"
12186 +#include "array.h"
12187 +#include "log.h"
12188 +
12189 +#line 17 "http_resp_parser.c"
12190 +/* Next is all token values, in a form suitable for use by makeheaders.
12191 +** This section will be null unless lemon is run with the -m switch.
12192 +*/
12193 +/*
12194 +** These constants (all generated automatically by the parser generator)
12195 +** specify the various kinds of tokens (terminals) that the parser
12196 +** understands.
12197 +**
12198 +** Each symbol here is a terminal symbol in the grammar.
12199 +*/
12200 +/* Make sure the INTERFACE macro is defined.
12201 +*/
12202 +#ifndef INTERFACE
12203 +# define INTERFACE 1
12204 +#endif
12205 +/* The next thing included is series of defines which control
12206 +** various aspects of the generated parser.
12207 +**    YYCODETYPE         is the data type used for storing terminal
12208 +**                       and nonterminal numbers.  "unsigned char" is
12209 +**                       used if there are fewer than 250 terminals
12210 +**                       and nonterminals.  "int" is used otherwise.
12211 +**    YYNOCODE           is a number of type YYCODETYPE which corresponds
12212 +**                       to no legal terminal or nonterminal number.  This
12213 +**                       number is used to fill in empty slots of the hash
12214 +**                       table.
12215 +**    YYFALLBACK         If defined, this indicates that one or more tokens
12216 +**                       have fall-back values which should be used if the
12217 +**                       original value of the token will not parse.
12218 +**    YYACTIONTYPE       is the data type used for storing terminal
12219 +**                       and nonterminal numbers.  "unsigned char" is
12220 +**                       used if there are fewer than 250 rules and
12221 +**                       states combined.  "int" is used otherwise.
12222 +**    http_resp_parserTOKENTYPE     is the data type used for minor tokens given
12223 +**                       directly to the parser from the tokenizer.
12224 +**    YYMINORTYPE        is the data type used for all minor tokens.
12225 +**                       This is typically a union of many types, one of
12226 +**                       which is http_resp_parserTOKENTYPE.  The entry in the union
12227 +**                       for base tokens is called "yy0".
12228 +**    YYSTACKDEPTH       is the maximum depth of the parser's stack.
12229 +**    http_resp_parserARG_SDECL     A static variable declaration for the %extra_argument
12230 +**    http_resp_parserARG_PDECL     A parameter declaration for the %extra_argument
12231 +**    http_resp_parserARG_STORE     Code to store %extra_argument into yypParser
12232 +**    http_resp_parserARG_FETCH     Code to extract %extra_argument from yypParser
12233 +**    YYNSTATE           the combined number of states.
12234 +**    YYNRULE            the number of rules in the grammar
12235 +**    YYERRORSYMBOL      is the code number of the error symbol.  If not
12236 +**                       defined, then do no error processing.
12237 +*/
12238 +/* \ 1 */
12239 +#define YYCODETYPE unsigned char
12240 +#define YYNOCODE 12
12241 +#define YYACTIONTYPE unsigned char
12242 +#define http_resp_parserTOKENTYPE buffer *
12243 +typedef union {
12244 +  http_resp_parserTOKENTYPE yy0;
12245 +  http_resp * yy2;
12246 +  data_string * yy9;
12247 +  array * yy12;
12248 +  int yy20;
12249 +  int yy23;
12250 +} YYMINORTYPE;
12251 +#define YYSTACKDEPTH 100
12252 +#define http_resp_parserARG_SDECL http_resp_ctx_t *ctx;
12253 +#define http_resp_parserARG_PDECL ,http_resp_ctx_t *ctx
12254 +#define http_resp_parserARG_FETCH http_resp_ctx_t *ctx = yypParser->ctx
12255 +#define http_resp_parserARG_STORE yypParser->ctx = ctx
12256 +#define YYNSTATE 19
12257 +#define YYNRULE 9
12258 +#define YYERRORSYMBOL 4
12259 +#define YYERRSYMDT yy23
12260 +#define YY_NO_ACTION      (YYNSTATE+YYNRULE+2)
12261 +#define YY_ACCEPT_ACTION  (YYNSTATE+YYNRULE+1)
12262 +#define YY_ERROR_ACTION   (YYNSTATE+YYNRULE)
12263 +
12264 +/* Next are that tables used to determine what action to take based on the
12265 +** current state and lookahead token.  These tables are used to implement
12266 +** functions that take a state number and lookahead value and return an
12267 +** action integer.
12268 +**
12269 +** Suppose the action integer is N.  Then the action is determined as
12270 +** follows
12271 +**
12272 +**   0 <= N < YYNSTATE                  Shift N.  That is, push the lookahead
12273 +**                                      token onto the stack and goto state N.
12274 +**
12275 +**   YYNSTATE <= N < YYNSTATE+YYNRULE   Reduce by rule N-YYNSTATE.
12276 +**
12277 +**   N == YYNSTATE+YYNRULE              A syntax error has occurred.
12278 +**
12279 +**   N == YYNSTATE+YYNRULE+1            The parser accepts its input.
12280 +**
12281 +**   N == YYNSTATE+YYNRULE+2            No such action.  Denotes unused
12282 +**                                      slots in the yy_action[] table.
12283 +**
12284 +** The action table is constructed as a single large table named yy_action[].
12285 +** Given state S and lookahead X, the action is computed as
12286 +**
12287 +**      yy_action[ yy_shift_ofst[S] + X ]
12288 +**
12289 +** If the index value yy_shift_ofst[S]+X is out of range or if the value
12290 +** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
12291 +** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
12292 +** and that yy_default[S] should be used instead.
12293 +**
12294 +** The formula above is for computing the action when the lookahead is
12295 +** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
12296 +** a reduce action) then the yy_reduce_ofst[] array is used in place of
12297 +** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
12298 +** YY_SHIFT_USE_DFLT.
12299 +**
12300 +** The following are the tables generated in this section:
12301 +**
12302 +**  yy_action[]        A single table containing all actions.
12303 +**  yy_lookahead[]     A table containing the lookahead for each entry in
12304 +**                     yy_action.  Used to detect hash collisions.
12305 +**  yy_shift_ofst[]    For each state, the offset into yy_action for
12306 +**                     shifting terminals.
12307 +**  yy_reduce_ofst[]   For each state, the offset into yy_action for
12308 +**                     shifting non-terminals after a reduce.
12309 +**  yy_default[]       Default action for each state.
12310 +*/
12311 +static YYACTIONTYPE yy_action[] = {
12312 + /*     0 */     8,   29,   18,    1,   14,    2,    4,   11,   15,   12,
12313 + /*    10 */    14,   13,    4,   21,    5,   19,    3,    5,    6,    7,
12314 + /*    20 */     9,   17,   16,    4,   20,   22,   22,   10,
12315 +};
12316 +static YYCODETYPE yy_lookahead[] = {
12317 + /*     0 */     5,    6,    2,    8,    9,    1,    2,    1,    2,    8,
12318 + /*    10 */     9,    1,    2,    2,    3,    0,    9,    3,    2,    1,
12319 + /*    20 */     7,    2,    2,    2,    0,    2,   11,   10,
12320 +};
12321 +#define YY_SHIFT_USE_DFLT (-1)
12322 +static signed char yy_shift_ofst[] = {
12323 + /*     0 */     0,    4,   15,   -1,   14,   16,   18,   -1,   19,   20,
12324 + /*    10 */     6,   21,   10,   24,   -1,   -1,   -1,   23,   11,
12325 +};
12326 +#define YY_REDUCE_USE_DFLT (-6)
12327 +static signed char yy_reduce_ofst[] = {
12328 + /*     0 */    -5,    7,   -6,   -6,   -6,   -6,   -6,   -6,   13,   17,
12329 + /*    10 */    -6,    1,    7,   -6,   -6,   -6,   -6,   -6,   -6,
12330 +};
12331 +static YYACTIONTYPE yy_default[] = {
12332 + /*     0 */    28,   28,   28,   25,   28,   28,   28,   27,   28,   28,
12333 + /*    10 */    28,   28,   28,   28,   26,   24,   23,   28,   28,
12334 +};
12335 +#define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
12336 +
12337 +/* The next table maps tokens into fallback tokens.  If a construct
12338 +** like the following:
12339 +**
12340 +**      %fallback ID X Y Z.
12341 +**
12342 +** appears in the grammer, then ID becomes a fallback token for X, Y,
12343 +** and Z.  Whenever one of the tokens X, Y, or Z is input to the parser
12344 +** but it does not parse, the type of the token is changed to ID and
12345 +** the parse is retried before an error is thrown.
12346 +*/
12347 +#ifdef YYFALLBACK
12348 +static const YYCODETYPE yyFallback[] = {
12349 +};
12350 +#endif /* YYFALLBACK */
12351 +
12352 +/* The following structure represents a single element of the
12353 +** parser's stack.  Information stored includes:
12354 +**
12355 +**   +  The state number for the parser at this level of the stack.
12356 +**
12357 +**   +  The value of the token stored at this level of the stack.
12358 +**      (In other words, the "major" token.)
12359 +**
12360 +**   +  The semantic value stored at this level of the stack.  This is
12361 +**      the information used by the action routines in the grammar.
12362 +**      It is sometimes called the "minor" token.
12363 +*/
12364 +struct yyStackEntry {
12365 +  int stateno;       /* The state-number */
12366 +  int major;         /* The major token value.  This is the code
12367 +                     ** number for the token at this stack level */
12368 +  YYMINORTYPE minor; /* The user-supplied minor token value.  This
12369 +                     ** is the value of the token  */
12370 +};
12371 +typedef struct yyStackEntry yyStackEntry;
12372 +
12373 +/* The state of the parser is completely contained in an instance of
12374 +** the following structure */
12375 +struct yyParser {
12376 +  int yyidx;                    /* Index of top element in stack */
12377 +  int yyerrcnt;                 /* Shifts left before out of the error */
12378 +  http_resp_parserARG_SDECL                /* A place to hold %extra_argument */
12379 +  yyStackEntry yystack[YYSTACKDEPTH];  /* The parser's stack */
12380 +};
12381 +typedef struct yyParser yyParser;
12382 +
12383 +#ifndef NDEBUG
12384 +#include <stdio.h>
12385 +static FILE *yyTraceFILE = 0;
12386 +static char *yyTracePrompt = 0;
12387 +#endif /* NDEBUG */
12388 +
12389 +#ifndef NDEBUG
12390 +/*
12391 +** Turn parser tracing on by giving a stream to which to write the trace
12392 +** and a prompt to preface each trace message.  Tracing is turned off
12393 +** by making either argument NULL
12394 +**
12395 +** Inputs:
12396 +** <ul>
12397 +** <li> A FILE* to which trace output should be written.
12398 +**      If NULL, then tracing is turned off.
12399 +** <li> A prefix string written at the beginning of every
12400 +**      line of trace output.  If NULL, then tracing is
12401 +**      turned off.
12402 +** </ul>
12403 +**
12404 +** Outputs:
12405 +** None.
12406 +*/
12407 +void http_resp_parserTrace(FILE *TraceFILE, char *zTracePrompt){
12408 +  yyTraceFILE = TraceFILE;
12409 +  yyTracePrompt = zTracePrompt;
12410 +  if( yyTraceFILE==0 ) yyTracePrompt = 0;
12411 +  else if( yyTracePrompt==0 ) yyTraceFILE = 0;
12412 +}
12413 +#endif /* NDEBUG */
12414 +
12415 +#ifndef NDEBUG
12416 +/* For tracing shifts, the names of all terminals and nonterminals
12417 +** are required.  The following table supplies these names */
12418 +static const char *yyTokenName[] = {
12419 +  "$",             "CRLF",          "STRING",        "COLON",       
12420 +  "error",         "protocol",      "response_hdr",  "number",      
12421 +  "headers",       "header",        "reason",      
12422 +};
12423 +#endif /* NDEBUG */
12424 +
12425 +#ifndef NDEBUG
12426 +/* For tracing reduce actions, the names of all rules are required.
12427 +*/
12428 +static const char *yyRuleName[] = {
12429 + /*   0 */ "response_hdr ::= headers CRLF",
12430 + /*   1 */ "response_hdr ::= protocol number reason CRLF headers CRLF",
12431 + /*   2 */ "protocol ::= STRING",
12432 + /*   3 */ "number ::= STRING",
12433 + /*   4 */ "reason ::= STRING",
12434 + /*   5 */ "reason ::= reason STRING",
12435 + /*   6 */ "headers ::= headers header",
12436 + /*   7 */ "headers ::= header",
12437 + /*   8 */ "header ::= STRING COLON STRING CRLF",
12438 +};
12439 +#endif /* NDEBUG */
12440 +
12441 +/*
12442 +** This function returns the symbolic name associated with a token
12443 +** value.
12444 +*/
12445 +const char *http_resp_parserTokenName(int tokenType){
12446 +#ifndef NDEBUG
12447 +  if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
12448 +    return yyTokenName[tokenType];
12449 +  }else{
12450 +    return "Unknown";
12451 +  }
12452 +#else
12453 +  return "";
12454 +#endif
12455 +}
12456 +
12457 +/*
12458 +** This function allocates a new parser.
12459 +** The only argument is a pointer to a function which works like
12460 +** malloc.
12461 +**
12462 +** Inputs:
12463 +** A pointer to the function used to allocate memory.
12464 +**
12465 +** Outputs:
12466 +** A pointer to a parser.  This pointer is used in subsequent calls
12467 +** to http_resp_parser and http_resp_parserFree.
12468 +*/
12469 +void *http_resp_parserAlloc(void *(*mallocProc)(size_t)){
12470 +  yyParser *pParser;
12471 +  pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
12472 +  if( pParser ){
12473 +    pParser->yyidx = -1;
12474 +  }
12475 +  return pParser;
12476 +}
12477 +
12478 +/* The following function deletes the value associated with a
12479 +** symbol.  The symbol can be either a terminal or nonterminal.
12480 +** "yymajor" is the symbol code, and "yypminor" is a pointer to
12481 +** the value.
12482 +*/
12483 +static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
12484 +  switch( yymajor ){
12485 +    /* Here is inserted the actions which take place when a
12486 +    ** terminal or non-terminal is destroyed.  This can happen
12487 +    ** when the symbol is popped from the stack during a
12488 +    ** reduce or during error processing or when a parser is
12489 +    ** being destroyed before it is finished parsing.
12490 +    **
12491 +    ** Note: during a reduce, the only symbols destroyed are those
12492 +    ** which appear on the RHS of the rule, but which are not used
12493 +    ** inside the C code.
12494 +    */
12495 +    case 1:
12496 +    case 2:
12497 +    case 3:
12498 +#line 25 "./http_resp_parser.y"
12499 +{ buffer_free((yypminor->yy0)); }
12500 +#line 327 "http_resp_parser.c"
12501 +      break;
12502 +    case 10:
12503 +#line 24 "./http_resp_parser.y"
12504 +{ buffer_free((yypminor->yy0)); }
12505 +#line 332 "http_resp_parser.c"
12506 +      break;
12507 +    default:  break;   /* If no destructor action specified: do nothing */
12508 +  }
12509 +}
12510 +
12511 +/*
12512 +** Pop the parser's stack once.
12513 +**
12514 +** If there is a destructor routine associated with the token which
12515 +** is popped from the stack, then call it.
12516 +**
12517 +** Return the major token number for the symbol popped.
12518 +*/
12519 +static int yy_pop_parser_stack(yyParser *pParser){
12520 +  YYCODETYPE yymajor;
12521 +  yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
12522 +
12523 +  if( pParser->yyidx<0 ) return 0;
12524 +#ifndef NDEBUG
12525 +  if( yyTraceFILE && pParser->yyidx>=0 ){
12526 +    fprintf(yyTraceFILE,"%sPopping %s\n",
12527 +      yyTracePrompt,
12528 +      yyTokenName[yytos->major]);
12529 +  }
12530 +#endif
12531 +  yymajor = yytos->major;
12532 +  yy_destructor( yymajor, &yytos->minor);
12533 +  pParser->yyidx--;
12534 +  return yymajor;
12535 +}
12536 +
12537 +/*
12538 +** Deallocate and destroy a parser.  Destructors are all called for
12539 +** all stack elements before shutting the parser down.
12540 +**
12541 +** Inputs:
12542 +** <ul>
12543 +** <li>  A pointer to the parser.  This should be a pointer
12544 +**       obtained from http_resp_parserAlloc.
12545 +** <li>  A pointer to a function used to reclaim memory obtained
12546 +**       from malloc.
12547 +** </ul>
12548 +*/
12549 +void http_resp_parserFree(
12550 +  void *p,                    /* The parser to be deleted */
12551 +  void (*freeProc)(void*)     /* Function used to reclaim memory */
12552 +){
12553 +  yyParser *pParser = (yyParser*)p;
12554 +  if( pParser==0 ) return;
12555 +  while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
12556 +  (*freeProc)((void*)pParser);
12557 +}
12558 +
12559 +/*
12560 +** Find the appropriate action for a parser given the terminal
12561 +** look-ahead token iLookAhead.
12562 +**
12563 +** If the look-ahead token is YYNOCODE, then check to see if the action is
12564 +** independent of the look-ahead.  If it is, return the action, otherwise
12565 +** return YY_NO_ACTION.
12566 +*/
12567 +static int yy_find_shift_action(
12568 +  yyParser *pParser,        /* The parser */
12569 +  int iLookAhead            /* The look-ahead token */
12570 +){
12571 +  int i;
12572 +  int stateno = pParser->yystack[pParser->yyidx].stateno;
12573 +
12574 +  /* if( pParser->yyidx<0 ) return YY_NO_ACTION;  */
12575 +  i = yy_shift_ofst[stateno];
12576 +  if( i==YY_SHIFT_USE_DFLT ){
12577 +    return yy_default[stateno];
12578 +  }
12579 +  if( iLookAhead==YYNOCODE ){
12580 +    return YY_NO_ACTION;
12581 +  }
12582 +  i += iLookAhead;
12583 +  if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
12584 +#ifdef YYFALLBACK
12585 +    int iFallback;            /* Fallback token */
12586 +    if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
12587 +           && (iFallback = yyFallback[iLookAhead])!=0 ){
12588 +#ifndef NDEBUG
12589 +      if( yyTraceFILE ){
12590 +        fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
12591 +           yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
12592 +      }
12593 +#endif
12594 +      return yy_find_shift_action(pParser, iFallback);
12595 +    }
12596 +#endif
12597 +    return yy_default[stateno];
12598 +  }else{
12599 +    return yy_action[i];
12600 +  }
12601 +}
12602 +
12603 +/*
12604 +** Find the appropriate action for a parser given the non-terminal
12605 +** look-ahead token iLookAhead.
12606 +**
12607 +** If the look-ahead token is YYNOCODE, then check to see if the action is
12608 +** independent of the look-ahead.  If it is, return the action, otherwise
12609 +** return YY_NO_ACTION.
12610 +*/
12611 +static int yy_find_reduce_action(
12612 +  yyParser *pParser,        /* The parser */
12613 +  int iLookAhead            /* The look-ahead token */
12614 +){
12615 +  int i;
12616 +  int stateno = pParser->yystack[pParser->yyidx].stateno;
12617 +
12618 +  i = yy_reduce_ofst[stateno];
12619 +  if( i==YY_REDUCE_USE_DFLT ){
12620 +    return yy_default[stateno];
12621 +  }
12622 +  if( iLookAhead==YYNOCODE ){
12623 +    return YY_NO_ACTION;
12624 +  }
12625 +  i += iLookAhead;
12626 +  if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
12627 +    return yy_default[stateno];
12628 +  }else{
12629 +    return yy_action[i];
12630 +  }
12631 +}
12632 +
12633 +/*
12634 +** Perform a shift action.
12635 +*/
12636 +static void yy_shift(
12637 +  yyParser *yypParser,          /* The parser to be shifted */
12638 +  int yyNewState,               /* The new state to shift in */
12639 +  int yyMajor,                  /* The major token to shift in */
12640 +  YYMINORTYPE *yypMinor         /* Pointer ot the minor token to shift in */
12641 +){
12642 +  yyStackEntry *yytos;
12643 +  yypParser->yyidx++;
12644 +  if( yypParser->yyidx>=YYSTACKDEPTH ){
12645 +     http_resp_parserARG_FETCH;
12646 +     yypParser->yyidx--;
12647 +#ifndef NDEBUG
12648 +     if( yyTraceFILE ){
12649 +       fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
12650 +     }
12651 +#endif
12652 +     while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
12653 +     /* Here code is inserted which will execute if the parser
12654 +     ** stack every overflows */
12655 +     http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument var */
12656 +     return;
12657 +  }
12658 +  yytos = &yypParser->yystack[yypParser->yyidx];
12659 +  yytos->stateno = yyNewState;
12660 +  yytos->major = yyMajor;
12661 +  yytos->minor = *yypMinor;
12662 +#ifndef NDEBUG
12663 +  if( yyTraceFILE && yypParser->yyidx>0 ){
12664 +    int i;
12665 +    fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
12666 +    fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
12667 +    for(i=1; i<=yypParser->yyidx; i++)
12668 +      fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
12669 +    fprintf(yyTraceFILE,"\n");
12670 +  }
12671 +#endif
12672 +}
12673 +
12674 +/* The following table contains information about every rule that
12675 +** is used during the reduce.
12676 +*/
12677 +static struct {
12678 +  YYCODETYPE lhs;         /* Symbol on the left-hand side of the rule */
12679 +  unsigned char nrhs;     /* Number of right-hand side symbols in the rule */
12680 +} yyRuleInfo[] = {
12681 +  { 6, 2 },
12682 +  { 6, 6 },
12683 +  { 5, 1 },
12684 +  { 7, 1 },
12685 +  { 10, 1 },
12686 +  { 10, 2 },
12687 +  { 8, 2 },
12688 +  { 8, 1 },
12689 +  { 9, 4 },
12690 +};
12691 +
12692 +static void yy_accept(yyParser*);  /* Forward Declaration */
12693 +
12694 +/*
12695 +** Perform a reduce action and the shift that must immediately
12696 +** follow the reduce.
12697 +*/
12698 +static void yy_reduce(
12699 +  yyParser *yypParser,         /* The parser */
12700 +  int yyruleno                 /* Number of the rule by which to reduce */
12701 +){
12702 +  int yygoto;                     /* The next state */
12703 +  int yyact;                      /* The next action */
12704 +  YYMINORTYPE yygotominor;        /* The LHS of the rule reduced */
12705 +  yyStackEntry *yymsp;            /* The top of the parser's stack */
12706 +  int yysize;                     /* Amount to pop the stack */
12707 +  http_resp_parserARG_FETCH;
12708 +  yymsp = &yypParser->yystack[yypParser->yyidx];
12709 +#ifndef NDEBUG
12710 +  if( yyTraceFILE && yyruleno>=0
12711 +        && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
12712 +    fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
12713 +      yyRuleName[yyruleno]);
12714 +  }
12715 +#endif /* NDEBUG */
12716 +
12717 +  switch( yyruleno ){
12718 +  /* Beginning here are the reduction cases.  A typical example
12719 +  ** follows:
12720 +  **   case 0:
12721 +  **  #line <lineno> <grammarfile>
12722 +  **     { ... }           // User supplied code
12723 +  **  #line <lineno> <thisfile>
12724 +  **     break;
12725 +  */
12726 +      case 0:
12727 +#line 28 "./http_resp_parser.y"
12728 +{
12729 +    http_resp *resp = ctx->resp;
12730 +    data_string *ds;
12731
12732 +    resp->protocol = HTTP_VERSION_UNSET;
12733 +
12734 +    buffer_copy_string(resp->reason, ""); /* no reason */
12735 +    array_free(resp->headers);
12736 +    resp->headers = yymsp[-1].minor.yy12;
12737 +
12738 +    if (NULL == (ds = (data_string *)array_get_element(yymsp[-1].minor.yy12, "Status"))) { 
12739 +        resp->status = 0;
12740 +    } else {
12741 +        char *err;
12742 +        resp->status = strtol(ds->value->ptr, &err, 10);
12743 +   
12744 +        if (*err != '\0' && *err != ' ') {
12745 +            buffer_copy_string(ctx->errmsg, "expected a number: ");
12746 +            buffer_append_string_buffer(ctx->errmsg, ds->value);
12747 +            buffer_append_string(ctx->errmsg, err);
12748 +        
12749 +            ctx->ok = 0;
12750 +        }
12751 +    }
12752 +
12753 +    yymsp[-1].minor.yy12 = NULL;
12754 +}
12755 +#line 582 "http_resp_parser.c"
12756 +  yy_destructor(1,&yymsp[0].minor);
12757 +        break;
12758 +      case 1:
12759 +#line 56 "./http_resp_parser.y"
12760 +{
12761 +    http_resp *resp = ctx->resp;
12762 +    
12763 +    resp->status = yymsp[-4].minor.yy20;
12764 +    resp->protocol = yymsp[-5].minor.yy20;
12765 +    buffer_copy_string_buffer(resp->reason, yymsp[-3].minor.yy0);
12766 +    buffer_free(yymsp[-3].minor.yy0); 
12767 +
12768 +    array_free(resp->headers);
12769 +    
12770 +    resp->headers = yymsp[-1].minor.yy12;
12771 +}
12772 +#line 599 "http_resp_parser.c"
12773 +  yy_destructor(1,&yymsp[-2].minor);
12774 +  yy_destructor(1,&yymsp[0].minor);
12775 +        break;
12776 +      case 2:
12777 +#line 69 "./http_resp_parser.y"
12778 +{
12779 +    if (buffer_is_equal_string(yymsp[0].minor.yy0, CONST_STR_LEN("HTTP/1.0"))) {
12780 +        yygotominor.yy20 = HTTP_VERSION_1_0;
12781 +    } else if (buffer_is_equal_string(yymsp[0].minor.yy0, CONST_STR_LEN("HTTP/1.1"))) {
12782 +        yygotominor.yy20 = HTTP_VERSION_1_1;
12783 +    } else {
12784 +        buffer_copy_string(ctx->errmsg, "unknown protocol: ");
12785 +        buffer_append_string_buffer(ctx->errmsg, yymsp[0].minor.yy0);
12786 +        
12787 +        ctx->ok = 0;
12788 +    }
12789 +    buffer_free(yymsp[0].minor.yy0);
12790 +}
12791 +#line 618 "http_resp_parser.c"
12792 +        break;
12793 +      case 3:
12794 +#line 83 "./http_resp_parser.y"
12795 +{
12796 +    char *err;
12797 +    yygotominor.yy20 = strtol(yymsp[0].minor.yy0->ptr, &err, 10);
12798 +    
12799 +    if (*err != '\0') {
12800 +        buffer_copy_string(ctx->errmsg, "expected a number, got: ");
12801 +        buffer_append_string_buffer(ctx->errmsg, yymsp[0].minor.yy0);
12802 +        
12803 +        ctx->ok = 0;
12804 +    }
12805 +    buffer_free(yymsp[0].minor.yy0);
12806 +}
12807 +#line 634 "http_resp_parser.c"
12808 +        break;
12809 +      case 4:
12810 +#line 96 "./http_resp_parser.y"
12811 +{
12812 +    yygotominor.yy0 = yymsp[0].minor.yy0;
12813 +}
12814 +#line 641 "http_resp_parser.c"
12815 +        break;
12816 +      case 5:
12817 +#line 100 "./http_resp_parser.y"
12818 +{
12819 +    yygotominor.yy0 = yymsp[-1].minor.yy0;
12820 +    
12821 +    buffer_append_string(yygotominor.yy0, " ");
12822 +    buffer_append_string_buffer(yygotominor.yy0, yymsp[0].minor.yy0);
12823 +
12824 +    buffer_free(yymsp[0].minor.yy0); 
12825 +}
12826 +#line 653 "http_resp_parser.c"
12827 +        break;
12828 +      case 6:
12829 +#line 109 "./http_resp_parser.y"
12830 +{
12831 +    yygotominor.yy12 = yymsp[-1].minor.yy12;
12832 +    
12833 +    array_insert_unique(yygotominor.yy12, (data_unset *)yymsp[0].minor.yy9);
12834 +}
12835 +#line 662 "http_resp_parser.c"
12836 +        break;
12837 +      case 7:
12838 +#line 115 "./http_resp_parser.y"
12839 +{
12840 +    yygotominor.yy12 = array_init();
12841 +
12842 +    array_insert_unique(yygotominor.yy12, (data_unset *)yymsp[0].minor.yy9);
12843 +}
12844 +#line 671 "http_resp_parser.c"
12845 +        break;
12846 +      case 8:
12847 +#line 120 "./http_resp_parser.y"
12848 +{
12849 +    yygotominor.yy9 = data_string_init();
12850 +    
12851 +    buffer_copy_string_buffer(yygotominor.yy9->key, yymsp[-3].minor.yy0);
12852 +    buffer_copy_string_buffer(yygotominor.yy9->value, yymsp[-1].minor.yy0);    
12853 +    buffer_free(yymsp[-3].minor.yy0);
12854 +    buffer_free(yymsp[-1].minor.yy0);
12855 +}
12856 +#line 683 "http_resp_parser.c"
12857 +  yy_destructor(3,&yymsp[-2].minor);
12858 +  yy_destructor(1,&yymsp[0].minor);
12859 +        break;
12860 +  };
12861 +  yygoto = yyRuleInfo[yyruleno].lhs;
12862 +  yysize = yyRuleInfo[yyruleno].nrhs;
12863 +  yypParser->yyidx -= yysize;
12864 +  yyact = yy_find_reduce_action(yypParser,yygoto);
12865 +  if( yyact < YYNSTATE ){
12866 +    yy_shift(yypParser,yyact,yygoto,&yygotominor);
12867 +  }else if( yyact == YYNSTATE + YYNRULE + 1 ){
12868 +    yy_accept(yypParser);
12869 +  }
12870 +}
12871 +
12872 +/*
12873 +** The following code executes when the parse fails
12874 +*/
12875 +static void yy_parse_failed(
12876 +  yyParser *yypParser           /* The parser */
12877 +){
12878 +  http_resp_parserARG_FETCH;
12879 +#ifndef NDEBUG
12880 +  if( yyTraceFILE ){
12881 +    fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
12882 +  }
12883 +#endif
12884 +  while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
12885 +  /* Here code is inserted which will be executed whenever the
12886 +  ** parser fails */
12887 +#line 15 "./http_resp_parser.y"
12888 +
12889 +  ctx->ok = 0;
12890 +
12891 +#line 718 "http_resp_parser.c"
12892 +  http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
12893 +}
12894 +
12895 +/*
12896 +** The following code executes when a syntax error first occurs.
12897 +*/
12898 +static void yy_syntax_error(
12899 +  yyParser *yypParser,           /* The parser */
12900 +  int yymajor,                   /* The major type of the error token */
12901 +  YYMINORTYPE yyminor            /* The minor type of the error token */
12902 +){
12903 +  http_resp_parserARG_FETCH;
12904 +#define TOKEN (yyminor.yy0)
12905 +  http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
12906 +}
12907 +
12908 +/*
12909 +** The following is executed when the parser accepts
12910 +*/
12911 +static void yy_accept(
12912 +  yyParser *yypParser           /* The parser */
12913 +){
12914 +  http_resp_parserARG_FETCH;
12915 +#ifndef NDEBUG
12916 +  if( yyTraceFILE ){
12917 +    fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
12918 +  }
12919 +#endif
12920 +  while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
12921 +  /* Here code is inserted which will be executed whenever the
12922 +  ** parser accepts */
12923 +  http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
12924 +}
12925 +
12926 +/* The main parser program.
12927 +** The first argument is a pointer to a structure obtained from
12928 +** "http_resp_parserAlloc" which describes the current state of the parser.
12929 +** The second argument is the major token number.  The third is
12930 +** the minor token.  The fourth optional argument is whatever the
12931 +** user wants (and specified in the grammar) and is available for
12932 +** use by the action routines.
12933 +**
12934 +** Inputs:
12935 +** <ul>
12936 +** <li> A pointer to the parser (an opaque structure.)
12937 +** <li> The major token number.
12938 +** <li> The minor token number.
12939 +** <li> An option argument of a grammar-specified type.
12940 +** </ul>
12941 +**
12942 +** Outputs:
12943 +** None.
12944 +*/
12945 +void http_resp_parser(
12946 +  void *yyp,                   /* The parser */
12947 +  int yymajor,                 /* The major token code number */
12948 +  http_resp_parserTOKENTYPE yyminor       /* The value for the token */
12949 +  http_resp_parserARG_PDECL               /* Optional %extra_argument parameter */
12950 +){
12951 +  YYMINORTYPE yyminorunion;
12952 +  int yyact;            /* The parser action. */
12953 +  int yyendofinput;     /* True if we are at the end of input */
12954 +  int yyerrorhit = 0;   /* True if yymajor has invoked an error */
12955 +  yyParser *yypParser;  /* The parser */
12956 +
12957 +  /* (re)initialize the parser, if necessary */
12958 +  yypParser = (yyParser*)yyp;
12959 +  if( yypParser->yyidx<0 ){
12960 +    if( yymajor==0 ) return;
12961 +    yypParser->yyidx = 0;
12962 +    yypParser->yyerrcnt = -1;
12963 +    yypParser->yystack[0].stateno = 0;
12964 +    yypParser->yystack[0].major = 0;
12965 +  }
12966 +  yyminorunion.yy0 = yyminor;
12967 +  yyendofinput = (yymajor==0);
12968 +  http_resp_parserARG_STORE;
12969 +
12970 +#ifndef NDEBUG
12971 +  if( yyTraceFILE ){
12972 +    fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
12973 +  }
12974 +#endif
12975 +
12976 +  do{
12977 +    yyact = yy_find_shift_action(yypParser,yymajor);
12978 +    if( yyact<YYNSTATE ){
12979 +      yy_shift(yypParser,yyact,yymajor,&yyminorunion);
12980 +      yypParser->yyerrcnt--;
12981 +      if( yyendofinput && yypParser->yyidx>=0 ){
12982 +        yymajor = 0;
12983 +      }else{
12984 +        yymajor = YYNOCODE;
12985 +      }
12986 +    }else if( yyact < YYNSTATE + YYNRULE ){
12987 +      yy_reduce(yypParser,yyact-YYNSTATE);
12988 +    }else if( yyact == YY_ERROR_ACTION ){
12989 +      int yymx;
12990 +#ifndef NDEBUG
12991 +      if( yyTraceFILE ){
12992 +        fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
12993 +      }
12994 +#endif
12995 +#ifdef YYERRORSYMBOL
12996 +      /* A syntax error has occurred.
12997 +      ** The response to an error depends upon whether or not the
12998 +      ** grammar defines an error token "ERROR".
12999 +      **
13000 +      ** This is what we do if the grammar does define ERROR:
13001 +      **
13002 +      **  * Call the %syntax_error function.
13003 +      **
13004 +      **  * Begin popping the stack until we enter a state where
13005 +      **    it is legal to shift the error symbol, then shift
13006 +      **    the error symbol.
13007 +      **
13008 +      **  * Set the error count to three.
13009 +      **
13010 +      **  * Begin accepting and shifting new tokens.  No new error
13011 +      **    processing will occur until three tokens have been
13012 +      **    shifted successfully.
13013 +      **
13014 +      */
13015 +      if( yypParser->yyerrcnt<0 ){
13016 +        yy_syntax_error(yypParser,yymajor,yyminorunion);
13017 +      }
13018 +      yymx = yypParser->yystack[yypParser->yyidx].major;
13019 +      if( yymx==YYERRORSYMBOL || yyerrorhit ){
13020 +#ifndef NDEBUG
13021 +        if( yyTraceFILE ){
13022 +          fprintf(yyTraceFILE,"%sDiscard input token %s\n",
13023 +             yyTracePrompt,yyTokenName[yymajor]);
13024 +        }
13025 +#endif
13026 +        yy_destructor(yymajor,&yyminorunion);
13027 +        yymajor = YYNOCODE;
13028 +      }else{
13029 +         while(
13030 +          yypParser->yyidx >= 0 &&
13031 +          yymx != YYERRORSYMBOL &&
13032 +          (yyact = yy_find_shift_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
13033 +        ){
13034 +          yy_pop_parser_stack(yypParser);
13035 +        }
13036 +        if( yypParser->yyidx < 0 || yymajor==0 ){
13037 +          yy_destructor(yymajor,&yyminorunion);
13038 +          yy_parse_failed(yypParser);
13039 +          yymajor = YYNOCODE;
13040 +        }else if( yymx!=YYERRORSYMBOL ){
13041 +          YYMINORTYPE u2;
13042 +          u2.YYERRSYMDT = 0;
13043 +          yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
13044 +        }
13045 +      }
13046 +      yypParser->yyerrcnt = 3;
13047 +      yyerrorhit = 1;
13048 +#else  /* YYERRORSYMBOL is not defined */
13049 +      /* This is what we do if the grammar does not define ERROR:
13050 +      **
13051 +      **  * Report an error message, and throw away the input token.
13052 +      **
13053 +      **  * If the input token is $, then fail the parse.
13054 +      **
13055 +      ** As before, subsequent error messages are suppressed until
13056 +      ** three input tokens have been successfully shifted.
13057 +      */
13058 +      if( yypParser->yyerrcnt<=0 ){
13059 +        yy_syntax_error(yypParser,yymajor,yyminorunion);
13060 +      }
13061 +      yypParser->yyerrcnt = 3;
13062 +      yy_destructor(yymajor,&yyminorunion);
13063 +      if( yyendofinput ){
13064 +        yy_parse_failed(yypParser);
13065 +      }
13066 +      yymajor = YYNOCODE;
13067 +#endif
13068 +    }else{
13069 +      yy_accept(yypParser);
13070 +      yymajor = YYNOCODE;
13071 +    }
13072 +  }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
13073 +  return;
13074 +}
13075 --- ../lighttpd-1.4.11/src/http_resp_parser.h   1970-01-01 03:00:00.000000000 +0300
13076 +++ lighttpd-1.4.12/src/http_resp_parser.h      2006-07-18 13:03:52.000000000 +0300
13077 @@ -0,0 +1,3 @@
13078 +#define TK_CRLF                            1
13079 +#define TK_STRING                          2
13080 +#define TK_COLON                           3
13081 --- ../lighttpd-1.4.11/src/http_resp_parser.y   1970-01-01 03:00:00.000000000 +0300
13082 +++ lighttpd-1.4.12/src/http_resp_parser.y      2006-07-18 13:03:40.000000000 +0300
13083 @@ -0,0 +1,127 @@
13084 +%token_prefix TK_
13085 +%token_type {buffer *}
13086 +%extra_argument {http_resp_ctx_t *ctx}
13087 +%name http_resp_parser
13088 +
13089 +%include {
13090 +#include <assert.h>
13091 +#include <string.h>
13092 +#include "http_resp.h"
13093 +#include "keyvalue.h"
13094 +#include "array.h"
13095 +#include "log.h"
13096 +}
13097 +
13098 +%parse_failure {
13099 +  ctx->ok = 0;
13100 +}
13101 +
13102 +%type protocol { int }
13103 +%type response_hdr { http_resp * }
13104 +%type number { int }
13105 +%type headers { array * }
13106 +%type header { data_string * }
13107 +%destructor reason { buffer_free($$); }
13108 +%token_destructor { buffer_free($$); }
13109 +
13110 +/* just headers + Status: ... */
13111 +response_hdr ::= headers(HDR) CRLF . {
13112 +    http_resp *resp = ctx->resp;
13113 +    data_string *ds;
13114
13115 +    resp->protocol = HTTP_VERSION_UNSET;
13116 +
13117 +    buffer_copy_string(resp->reason, ""); /* no reason */
13118 +    array_free(resp->headers);
13119 +    resp->headers = HDR;
13120 +
13121 +    if (NULL == (ds = (data_string *)array_get_element(HDR, "Status"))) { 
13122 +        resp->status = 0;
13123 +    } else {
13124 +        char *err;
13125 +        resp->status = strtol(ds->value->ptr, &err, 10);
13126 +   
13127 +        if (*err != '\0' && *err != ' ') {
13128 +            buffer_copy_string(ctx->errmsg, "expected a number: ");
13129 +            buffer_append_string_buffer(ctx->errmsg, ds->value);
13130 +            buffer_append_string(ctx->errmsg, err);
13131 +        
13132 +            ctx->ok = 0;
13133 +        }
13134 +    }
13135 +
13136 +    HDR = NULL;
13137 +}
13138 +/* HTTP/1.0 <status> ... */
13139 +response_hdr ::= protocol(B) number(C) reason(D) CRLF headers(HDR) CRLF . {
13140 +    http_resp *resp = ctx->resp;
13141 +    
13142 +    resp->status = C;
13143 +    resp->protocol = B;
13144 +    buffer_copy_string_buffer(resp->reason, D);
13145 +    buffer_free(D); 
13146 +
13147 +    array_free(resp->headers);
13148 +    
13149 +    resp->headers = HDR;
13150 +}
13151 +
13152 +protocol(A) ::= STRING(B). {
13153 +    if (buffer_is_equal_string(B, CONST_STR_LEN("HTTP/1.0"))) {
13154 +        A = HTTP_VERSION_1_0;
13155 +    } else if (buffer_is_equal_string(B, CONST_STR_LEN("HTTP/1.1"))) {
13156 +        A = HTTP_VERSION_1_1;
13157 +    } else {
13158 +        buffer_copy_string(ctx->errmsg, "unknown protocol: ");
13159 +        buffer_append_string_buffer(ctx->errmsg, B);
13160 +        
13161 +        ctx->ok = 0;
13162 +    }
13163 +    buffer_free(B);
13164 +}
13165 +
13166 +number(A) ::= STRING(B). {
13167 +    char *err;
13168 +    A = strtol(B->ptr, &err, 10);
13169 +    
13170 +    if (*err != '\0') {
13171 +        buffer_copy_string(ctx->errmsg, "expected a number, got: ");
13172 +        buffer_append_string_buffer(ctx->errmsg, B);
13173 +        
13174 +        ctx->ok = 0;
13175 +    }
13176 +    buffer_free(B);
13177 +}
13178 +
13179 +reason(A) ::= STRING(B). {
13180 +    A = B;
13181 +}
13182 +
13183 +reason(A) ::= reason(C) STRING(B). {
13184 +    A = C;
13185 +    
13186 +    buffer_append_string(A, " ");
13187 +    buffer_append_string_buffer(A, B);
13188 +
13189 +    buffer_free(B); 
13190 +}
13191 +
13192 +headers(HDRS) ::= headers(SRC) header(HDR). {
13193 +    HDRS = SRC;
13194 +    
13195 +    array_insert_unique(HDRS, (data_unset *)HDR);
13196 +}
13197 +
13198 +headers(HDRS) ::= header(HDR). {
13199 +    HDRS = array_init();
13200 +
13201 +    array_insert_unique(HDRS, (data_unset *)HDR);
13202 +}
13203 +header(HDR) ::= STRING(A) COLON STRING(B) CRLF. {
13204 +    HDR = data_string_init();
13205 +    
13206 +    buffer_copy_string_buffer(HDR->key, A);
13207 +    buffer_copy_string_buffer(HDR->value, B);    
13208 +    buffer_free(A);
13209 +    buffer_free(B);
13210 +}
13211 --- ../lighttpd-1.4.11/src/inet_ntop_cache.c    2005-08-11 01:26:38.000000000 +0300
13212 +++ lighttpd-1.4.12/src/inet_ntop_cache.c       2006-07-16 00:26:04.000000000 +0300
13213 @@ -8,7 +8,7 @@
13214  #include "sys-socket.h"
13215  
13216  const char * inet_ntop_cache_get_ip(server *srv, sock_addr *addr) {
13217 -#ifdef HAVE_IPV6       
13218 +#ifdef HAVE_IPV6
13219         size_t ndx = 0, i;
13220         for (i = 0; i < INET_NTOP_CACHE_MAX; i++) {
13221                 if (srv->inet_ntop_cache[i].ts != 0) {
13222 @@ -20,31 +20,31 @@
13223                                    srv->inet_ntop_cache[i].addr.ipv4.s_addr == addr->ipv4.sin_addr.s_addr) {
13224                                 /* IPv4 found in cache */
13225                                 break;
13226 -                               
13227 +
13228                         }
13229                 }
13230         }
13231 -       
13232 +
13233         if (i == INET_NTOP_CACHE_MAX) {
13234                 /* not found in cache */
13235 -               
13236 +
13237                 i = ndx;
13238 -               inet_ntop(addr->plain.sa_family, 
13239 -                         addr->plain.sa_family == AF_INET6 ? 
13240 +               inet_ntop(addr->plain.sa_family,
13241 +                         addr->plain.sa_family == AF_INET6 ?
13242                           (const void *) &(addr->ipv6.sin6_addr) :
13243                           (const void *) &(addr->ipv4.sin_addr),
13244                           srv->inet_ntop_cache[i].b2, INET6_ADDRSTRLEN);
13245 -               
13246 +
13247                 srv->inet_ntop_cache[i].ts = srv->cur_ts;
13248                 srv->inet_ntop_cache[i].family = addr->plain.sa_family;
13249 -               
13250 +
13251                 if (srv->inet_ntop_cache[i].family == AF_INET) {
13252                         srv->inet_ntop_cache[i].addr.ipv4.s_addr = addr->ipv4.sin_addr.s_addr;
13253                 } else if (srv->inet_ntop_cache[i].family == AF_INET6) {
13254                         memcpy(srv->inet_ntop_cache[i].addr.ipv6.s6_addr, addr->ipv6.sin6_addr.s6_addr, 16);
13255                 }
13256         }
13257 -       
13258 +
13259         return srv->inet_ntop_cache[i].b2;
13260  #else
13261         UNUSED(srv);
13262 --- ../lighttpd-1.4.11/src/iosocket.c   1970-01-01 03:00:00.000000000 +0300
13263 +++ lighttpd-1.4.12/src/iosocket.c      2006-07-18 13:03:40.000000000 +0300
13264 @@ -0,0 +1,36 @@
13265 +#include <stdlib.h>
13266 +
13267 +#include "iosocket.h"
13268 +#include "sys-socket.h"
13269 +#include "sys-files.h"
13270 +#include "array-static.h"
13271 +
13272 +iosocket *iosocket_init(void) {
13273 +       STRUCT_INIT(iosocket, sock);
13274 +
13275 +       sock->fde_ndx = -1;
13276 +       sock->fd = -1;
13277 +
13278 +       sock->type = IOSOCKET_TYPE_SOCKET;
13279 +
13280 +       return sock;
13281 +}
13282 +
13283 +void iosocket_free(iosocket *sock) {
13284 +       if (!sock) return;
13285 +
13286 +       if (sock->fd != -1) {
13287 +               switch (sock->type) {
13288 +               case IOSOCKET_TYPE_SOCKET:
13289 +                       closesocket(sock->fd);
13290 +                       break;
13291 +               case IOSOCKET_TYPE_PIPE:
13292 +                       close(sock->fd);
13293 +                       break;
13294 +               default:
13295 +                       break;
13296 +               }
13297 +       }
13298 +
13299 +       free(sock);
13300 +}
13301 --- ../lighttpd-1.4.11/src/iosocket.h   1970-01-01 03:00:00.000000000 +0300
13302 +++ lighttpd-1.4.12/src/iosocket.h      2006-07-18 13:03:40.000000000 +0300
13303 @@ -0,0 +1,32 @@
13304 +#ifndef _IOSOCKET_H_
13305 +#define _IOSOCKET_H_
13306 +
13307 +#if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
13308 +# define USE_OPENSSL
13309 +# include <openssl/ssl.h>
13310 +#endif
13311 +
13312 +typedef enum {
13313 +       IOSOCKET_TYPE_UNSET,
13314 +       IOSOCKET_TYPE_SOCKET,
13315 +       IOSOCKET_TYPE_PIPE
13316 +} iosocket_t;
13317 +
13318 +/**
13319 + * a non-blocking fd
13320 + */
13321 +typedef struct {
13322 +       int fd;
13323 +       int fde_ndx;
13324 +
13325 +#ifdef USE_OPENSSL
13326 +       SSL *ssl;
13327 +#endif
13328 +
13329 +       iosocket_t type; /**< sendfile on solaris doesn't work on pipes */
13330 +} iosocket;
13331 +
13332 +iosocket *iosocket_init(void);
13333 +void iosocket_free(iosocket *sock);
13334 +
13335 +#endif
13336 --- ../lighttpd-1.4.11/src/joblist.c    2005-08-11 01:26:41.000000000 +0300
13337 +++ lighttpd-1.4.12/src/joblist.c       2006-07-16 00:26:03.000000000 +0300
13338 @@ -7,7 +7,7 @@
13339  
13340  int joblist_append(server *srv, connection *con) {
13341         if (con->in_joblist) return 0;
13342 -       
13343 +
13344         if (srv->joblist->size == 0) {
13345                 srv->joblist->size  = 16;
13346                 srv->joblist->ptr   = malloc(sizeof(*srv->joblist->ptr) * srv->joblist->size);
13347 @@ -15,15 +15,15 @@
13348                 srv->joblist->size += 16;
13349                 srv->joblist->ptr   = realloc(srv->joblist->ptr, sizeof(*srv->joblist->ptr) * srv->joblist->size);
13350         }
13351 -       
13352 +
13353         srv->joblist->ptr[srv->joblist->used++] = con;
13354 -       
13355 +
13356         return 0;
13357  }
13358  
13359  void joblist_free(server *srv, connections *joblist) {
13360         UNUSED(srv);
13361 -               
13362 +
13363         free(joblist->ptr);
13364         free(joblist);
13365  }
13366 @@ -31,14 +31,14 @@
13367  connection *fdwaitqueue_unshift(server *srv, connections *fdwaitqueue) {
13368         connection *con;
13369         UNUSED(srv);
13370 -               
13371 -       
13372 +
13373 +
13374         if (fdwaitqueue->used == 0) return NULL;
13375 -       
13376 +
13377         con = fdwaitqueue->ptr[0];
13378 -       
13379 +
13380         memmove(fdwaitqueue->ptr, &(fdwaitqueue->ptr[1]), --fdwaitqueue->used * sizeof(*(fdwaitqueue->ptr)));
13381 -       
13382 +
13383         return con;
13384  }
13385  
13386 @@ -50,9 +50,9 @@
13387                 srv->fdwaitqueue->size += 16;
13388                 srv->fdwaitqueue->ptr   = realloc(srv->fdwaitqueue->ptr, sizeof(*(srv->fdwaitqueue->ptr)) * srv->fdwaitqueue->size);
13389         }
13390 -       
13391 +
13392         srv->fdwaitqueue->ptr[srv->fdwaitqueue->used++] = con;
13393 -       
13394 +
13395         return 0;
13396  }
13397  
13398 --- ../lighttpd-1.4.11/src/keyvalue.c   2006-03-02 16:08:06.000000000 +0200
13399 +++ lighttpd-1.4.12/src/keyvalue.c      2006-07-16 00:26:03.000000000 +0300
13400 @@ -87,7 +87,8 @@
13401         { 504, "Gateway Timeout" },
13402         { 505, "HTTP Version Not Supported" },
13403         { 507, "Insufficient Storage" }, /* WebDAV */
13404 -       
13405 +       { 509, "Bandwidth Limit exceeded" },
13406 +
13407         { -1, NULL }
13408  };
13409  
13410 @@ -102,12 +103,12 @@
13411         { 501, "501.html" },
13412         { 503, "503.html" },
13413         { 505, "505.html" },
13414 -       
13415 +
13416         { -1, NULL }
13417  };
13418  
13419  
13420 -const char *keyvalue_get_value(keyvalue *kv, int k) { 
13421 +const char *keyvalue_get_value(keyvalue *kv, int k) {
13422         int i;
13423         for (i = 0; kv[i].value; i++) {
13424                 if (kv[i].key == k) return kv[i].value;
13425 @@ -115,7 +116,7 @@
13426         return NULL;
13427  }
13428  
13429 -int keyvalue_get_key(keyvalue *kv, const char *s) { 
13430 +int keyvalue_get_key(keyvalue *kv, const char *s) {
13431         int i;
13432         for (i = 0; kv[i].value; i++) {
13433                 if (0 == strcmp(kv[i].value, s)) return kv[i].key;
13434 @@ -125,9 +126,9 @@
13435  
13436  keyvalue_buffer *keyvalue_buffer_init(void) {
13437         keyvalue_buffer *kvb;
13438 -       
13439 +
13440         kvb = calloc(1, sizeof(*kvb));
13441 -       
13442 +
13443         return kvb;
13444  }
13445  
13446 @@ -135,49 +136,49 @@
13447         size_t i;
13448         if (kvb->size == 0) {
13449                 kvb->size = 4;
13450 -               
13451 +
13452                 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13453 -               
13454 +
13455                 for(i = 0; i < kvb->size; i++) {
13456                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13457                 }
13458         } else if (kvb->used == kvb->size) {
13459                 kvb->size += 4;
13460 -               
13461 +
13462                 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13463 -               
13464 +
13465                 for(i = kvb->used; i < kvb->size; i++) {
13466                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13467                 }
13468         }
13469 -       
13470 +
13471         kvb->kv[kvb->used]->key = key;
13472         kvb->kv[kvb->used]->value = strdup(value);
13473 -       
13474 +
13475         kvb->used++;
13476 -       
13477 +
13478         return 0;
13479  }
13480  
13481  void keyvalue_buffer_free(keyvalue_buffer *kvb) {
13482         size_t i;
13483 -       
13484 +
13485         for (i = 0; i < kvb->size; i++) {
13486                 if (kvb->kv[i]->value) free(kvb->kv[i]->value);
13487                 free(kvb->kv[i]);
13488         }
13489 -       
13490 +
13491         if (kvb->kv) free(kvb->kv);
13492 -       
13493 +
13494         free(kvb);
13495  }
13496  
13497  
13498  s_keyvalue_buffer *s_keyvalue_buffer_init(void) {
13499         s_keyvalue_buffer *kvb;
13500 -       
13501 +
13502         kvb = calloc(1, sizeof(*kvb));
13503 -       
13504 +
13505         return kvb;
13506  }
13507  
13508 @@ -186,50 +187,50 @@
13509         if (kvb->size == 0) {
13510                 kvb->size = 4;
13511                 kvb->used = 0;
13512 -               
13513 +
13514                 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13515 -               
13516 +
13517                 for(i = 0; i < kvb->size; i++) {
13518                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13519                 }
13520         } else if (kvb->used == kvb->size) {
13521                 kvb->size += 4;
13522 -               
13523 +
13524                 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13525 -               
13526 +
13527                 for(i = kvb->used; i < kvb->size; i++) {
13528                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13529                 }
13530         }
13531 -       
13532 +
13533         kvb->kv[kvb->used]->key = key ? strdup(key) : NULL;
13534         kvb->kv[kvb->used]->value = strdup(value);
13535 -       
13536 +
13537         kvb->used++;
13538 -       
13539 +
13540         return 0;
13541  }
13542  
13543  void s_keyvalue_buffer_free(s_keyvalue_buffer *kvb) {
13544         size_t i;
13545 -       
13546 +
13547         for (i = 0; i < kvb->size; i++) {
13548                 if (kvb->kv[i]->key) free(kvb->kv[i]->key);
13549                 if (kvb->kv[i]->value) free(kvb->kv[i]->value);
13550                 free(kvb->kv[i]);
13551         }
13552 -       
13553 +
13554         if (kvb->kv) free(kvb->kv);
13555 -       
13556 +
13557         free(kvb);
13558  }
13559  
13560  
13561  httpauth_keyvalue_buffer *httpauth_keyvalue_buffer_init(void) {
13562         httpauth_keyvalue_buffer *kvb;
13563 -       
13564 +
13565         kvb = calloc(1, sizeof(*kvb));
13566 -       
13567 +
13568         return kvb;
13569  }
13570  
13571 @@ -237,42 +238,42 @@
13572         size_t i;
13573         if (kvb->size == 0) {
13574                 kvb->size = 4;
13575 -               
13576 +
13577                 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13578 -               
13579 +
13580                 for(i = 0; i < kvb->size; i++) {
13581                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13582                 }
13583         } else if (kvb->used == kvb->size) {
13584                 kvb->size += 4;
13585 -               
13586 +
13587                 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13588 -               
13589 +
13590                 for(i = kvb->used; i < kvb->size; i++) {
13591                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13592                 }
13593         }
13594 -       
13595 +
13596         kvb->kv[kvb->used]->key = strdup(key);
13597         kvb->kv[kvb->used]->realm = strdup(realm);
13598         kvb->kv[kvb->used]->type = type;
13599 -       
13600 +
13601         kvb->used++;
13602 -       
13603 +
13604         return 0;
13605  }
13606  
13607  void httpauth_keyvalue_buffer_free(httpauth_keyvalue_buffer *kvb) {
13608         size_t i;
13609 -       
13610 +
13611         for (i = 0; i < kvb->size; i++) {
13612                 if (kvb->kv[i]->key) free(kvb->kv[i]->key);
13613                 if (kvb->kv[i]->realm) free(kvb->kv[i]->realm);
13614                 free(kvb->kv[i]);
13615         }
13616 -       
13617 +
13618         if (kvb->kv) free(kvb->kv);
13619 -       
13620 +
13621         free(kvb);
13622  }
13623  
13624 @@ -306,9 +307,9 @@
13625  
13626  pcre_keyvalue_buffer *pcre_keyvalue_buffer_init(void) {
13627         pcre_keyvalue_buffer *kvb;
13628 -       
13629 +
13630         kvb = calloc(1, sizeof(*kvb));
13631 -       
13632 +
13633         return kvb;
13634  }
13635  
13636 @@ -319,46 +320,46 @@
13637         int erroff;
13638         pcre_keyvalue *kv;
13639  #endif
13640 -       
13641 +
13642         if (!key) return -1;
13643  
13644  #ifdef HAVE_PCRE_H
13645         if (kvb->size == 0) {
13646                 kvb->size = 4;
13647                 kvb->used = 0;
13648 -               
13649 +
13650                 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13651 -               
13652 +
13653                 for(i = 0; i < kvb->size; i++) {
13654                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13655                 }
13656         } else if (kvb->used == kvb->size) {
13657                 kvb->size += 4;
13658 -               
13659 +
13660                 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13661 -               
13662 +
13663                 for(i = kvb->used; i < kvb->size; i++) {
13664                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13665                 }
13666         }
13667 -       
13668 +
13669         kv = kvb->kv[kvb->used];
13670         if (NULL == (kv->key = pcre_compile(key,
13671                                           0, &errptr, &erroff, NULL))) {
13672 -               
13673 +
13674                 fprintf(stderr, "%s.%d: rexexp compilation error at %s\n", __FILE__, __LINE__, errptr);
13675                 return -1;
13676         }
13677  
13678 -       if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) &&  
13679 +       if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) &&
13680                         errptr != NULL) {
13681                 return -1;
13682         }
13683 -       
13684 +
13685         kv->value = buffer_init_string(value);
13686 -       
13687 +
13688         kvb->used++;
13689 -       
13690 +
13691         return 0;
13692  #else
13693         UNUSED(kvb);
13694 @@ -380,9 +381,9 @@
13695                 if (kv->value) buffer_free(kv->value);
13696                 free(kv);
13697         }
13698 -       
13699 +
13700         if (kvb->kv) free(kvb->kv);
13701  #endif
13702 -       
13703 +
13704         free(kvb);
13705  }
13706 --- ../lighttpd-1.4.11/src/keyvalue.h   2006-03-02 16:08:06.000000000 +0200
13707 +++ lighttpd-1.4.12/src/keyvalue.h      2006-07-16 00:26:04.000000000 +0300
13708 @@ -9,19 +9,19 @@
13709  # include <pcre.h>
13710  #endif
13711  
13712 -typedef enum { 
13713 -       HTTP_METHOD_UNSET = -1, 
13714 -       HTTP_METHOD_GET, 
13715 -       HTTP_METHOD_POST, 
13716 -       HTTP_METHOD_HEAD, 
13717 -       HTTP_METHOD_OPTIONS, 
13718 +typedef enum {
13719 +       HTTP_METHOD_UNSET = -1,
13720 +       HTTP_METHOD_GET,
13721 +       HTTP_METHOD_POST,
13722 +       HTTP_METHOD_HEAD,
13723 +       HTTP_METHOD_OPTIONS,
13724         HTTP_METHOD_PROPFIND,  /* WebDAV */
13725 -       HTTP_METHOD_MKCOL, 
13726 -       HTTP_METHOD_PUT, 
13727 -       HTTP_METHOD_DELETE, 
13728 -       HTTP_METHOD_COPY, 
13729 -       HTTP_METHOD_MOVE, 
13730 -       HTTP_METHOD_PROPPATCH, 
13731 +       HTTP_METHOD_MKCOL,
13732 +       HTTP_METHOD_PUT,
13733 +       HTTP_METHOD_DELETE,
13734 +       HTTP_METHOD_COPY,
13735 +       HTTP_METHOD_MOVE,
13736 +       HTTP_METHOD_PROPPATCH,
13737         HTTP_METHOD_REPORT, /* DeltaV */
13738         HTTP_METHOD_CHECKOUT,
13739         HTTP_METHOD_CHECKIN,
13740 @@ -39,13 +39,13 @@
13741  
13742  typedef struct {
13743         int key;
13744 -       
13745 +
13746         char *value;
13747  } keyvalue;
13748  
13749  typedef struct {
13750         char *key;
13751 -       
13752 +
13753         char *value;
13754  } s_keyvalue;
13755  
13756 @@ -54,7 +54,7 @@
13757         pcre *key;
13758         pcre_extra *key_extra;
13759  #endif
13760 -       
13761 +
13762         buffer *value;
13763  } pcre_keyvalue;
13764  
13765 @@ -62,7 +62,7 @@
13766  
13767  typedef struct {
13768         char *key;
13769 -       
13770 +
13771         char *realm;
13772         httpauth_type type;
13773  } httpauth_keyvalue;
13774 --- ../lighttpd-1.4.11/src/lemon.c      2005-09-01 00:21:34.000000000 +0300
13775 +++ lighttpd-1.4.12/src/lemon.c 2006-07-16 00:26:03.000000000 +0300
13776 @@ -579,7 +579,7 @@
13777  */
13778  
13779  /* Find a precedence symbol of every rule in the grammar.
13780 -** 
13781 +**
13782  ** Those rules which have a precedence symbol coded in the input
13783  ** grammar using the "[symbol]" construct will already have the
13784  ** rp->precsym field filled.  Other rules take as their precedence
13785 @@ -869,7 +869,7 @@
13786        cfp->status = INCOMPLETE;
13787      }
13788    }
13789 -  
13790 +
13791    do{
13792      progress = 0;
13793      for(i=0; i<lemp->nstate; i++){
13794 @@ -900,7 +900,7 @@
13795    struct symbol *sp;
13796    struct rule *rp;
13797  
13798 -  /* Add all of the reduce actions 
13799 +  /* Add all of the reduce actions
13800    ** A reduce action is added for each element of the followset of
13801    ** a configuration which has its dot at the extreme right.
13802    */
13803 @@ -1017,7 +1017,7 @@
13804        apx->type = RD_RESOLVED;
13805      }
13806    }else{
13807 -    assert( 
13808 +    assert(
13809        apx->type==SH_RESOLVED ||
13810        apx->type==RD_RESOLVED ||
13811        apx->type==CONFLICT ||
13812 @@ -1350,7 +1350,7 @@
13813    OptInit(argv,options,stderr);
13814    if( version ){
13815       printf("Lemon version 1.0\n");
13816 -     exit(0); 
13817 +     exit(0);
13818    }
13819    if( OptNArgs() < 1 ){
13820      fprintf(stderr,"Exactly one filename argument is required.\n");
13821 @@ -2031,7 +2031,7 @@
13822      case IN_RHS:
13823        if( x[0]=='.' ){
13824          struct rule *rp;
13825 -        rp = (struct rule *)malloc( sizeof(struct rule) + 
13826 +        rp = (struct rule *)malloc( sizeof(struct rule) +
13827               sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs );
13828          if( rp==0 ){
13829            ErrorMsg(psp->filename,psp->tokenlineno,
13830 @@ -2546,7 +2546,7 @@
13831    return fp;
13832  }
13833  
13834 -/* Duplicate the input file without comments and without actions 
13835 +/* Duplicate the input file without comments and without actions
13836  ** on rules */
13837  void Reprint(lemp)
13838  struct lemon *lemp;
13839 @@ -2822,7 +2822,7 @@
13840  PRIVATE FILE *tplt_open(lemp)
13841  struct lemon *lemp;
13842  {
13843 -  
13844 +
13845    char buf[1000];
13846    FILE *in;
13847    char *tpltname;
13848 @@ -2930,7 +2930,7 @@
13849    return ret;
13850  }
13851  
13852 -/* 
13853 +/*
13854  ** Generate code which executes when the rule "rp" is reduced.  Write
13855  ** the code to "out".  Make sure lineno stays up-to-date.
13856  */
13857 @@ -3384,7 +3384,7 @@
13858  
13859    /* Output the yy_shift_ofst[] table */
13860    fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++;
13861 -  fprintf(out, "static %s yy_shift_ofst[] = {\n", 
13862 +  fprintf(out, "static %s yy_shift_ofst[] = {\n",
13863            minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++;
13864    n = lemp->nstate;
13865    for(i=j=0; i<n; i++){
13866 @@ -3405,7 +3405,7 @@
13867  
13868    /* Output the yy_reduce_ofst[] table */
13869    fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++;
13870 -  fprintf(out, "static %s yy_reduce_ofst[] = {\n", 
13871 +  fprintf(out, "static %s yy_reduce_ofst[] = {\n",
13872            minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++;
13873    n = lemp->nstate;
13874    for(i=j=0; i<n; i++){
13875 @@ -3480,7 +3480,7 @@
13876    tplt_xfer(lemp->name,in,out,&lineno);
13877  
13878    /* Generate code which executes every time a symbol is popped from
13879 -  ** the stack while processing errors or while destroying the parser. 
13880 +  ** the stack while processing errors or while destroying the parser.
13881    ** (In other words, generate the %destructor actions)
13882    */
13883    if( lemp->tokendest ){
13884 @@ -3522,7 +3522,7 @@
13885    tplt_print(out,lemp,lemp->overflow,lemp->overflowln,&lineno);
13886    tplt_xfer(lemp->name,in,out,&lineno);
13887  
13888 -  /* Generate the table of rule information 
13889 +  /* Generate the table of rule information
13890    **
13891    ** Note: This code depends on the fact that rules are number
13892    ** sequentually beginning with 0.
13893 @@ -3589,7 +3589,7 @@
13894      for(i=1; i<lemp->nterminal; i++){
13895        fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
13896      }
13897 -    fclose(out);  
13898 +    fclose(out);
13899    }
13900    return;
13901  }
13902 @@ -3630,7 +3630,7 @@
13903          rbest = rp;
13904        }
13905      }
13906
13907 +
13908      /* Do not make a default if the number of rules to default
13909      ** is not at least 2 */
13910      if( nbest<2 ) continue;
13911 @@ -3781,7 +3781,7 @@
13912    if( x1a ){
13913      x1a->size = 1024;
13914      x1a->count = 0;
13915 -    x1a->tbl = (x1node*)malloc( 
13916 +    x1a->tbl = (x1node*)malloc(
13917        (sizeof(x1node) + sizeof(x1node*))*1024 );
13918      if( x1a->tbl==0 ){
13919        free(x1a);
13920 @@ -3943,7 +3943,7 @@
13921    if( x2a ){
13922      x2a->size = 128;
13923      x2a->count = 0;
13924 -    x2a->tbl = (x2node*)malloc( 
13925 +    x2a->tbl = (x2node*)malloc(
13926        (sizeof(x2node) + sizeof(x2node*))*128 );
13927      if( x2a->tbl==0 ){
13928        free(x2a);
13929 @@ -4149,7 +4149,7 @@
13930    if( x3a ){
13931      x3a->size = 128;
13932      x3a->count = 0;
13933 -    x3a->tbl = (x3node*)malloc( 
13934 +    x3a->tbl = (x3node*)malloc(
13935        (sizeof(x3node) + sizeof(x3node*))*128 );
13936      if( x3a->tbl==0 ){
13937        free(x3a);
13938 @@ -4295,7 +4295,7 @@
13939    if( x4a ){
13940      x4a->size = 64;
13941      x4a->count = 0;
13942 -    x4a->tbl = (x4node*)malloc( 
13943 +    x4a->tbl = (x4node*)malloc(
13944        (sizeof(x4node) + sizeof(x4node*))*64 );
13945      if( x4a->tbl==0 ){
13946        free(x4a);
13947 --- ../lighttpd-1.4.11/src/lempar.c     2005-08-11 01:26:40.000000000 +0300
13948 +++ lighttpd-1.4.12/src/lempar.c        2006-07-16 00:26:03.000000000 +0300
13949 @@ -8,10 +8,10 @@
13950  /* Next is all token values, in a form suitable for use by makeheaders.
13951  ** This section will be null unless lemon is run with the -m switch.
13952  */
13953 -/* 
13954 +/*
13955  ** These constants (all generated automatically by the parser generator)
13956  ** specify the various kinds of tokens (terminals) that the parser
13957 -** understands. 
13958 +** understands.
13959  **
13960  ** Each symbol here is a terminal symbol in the grammar.
13961  */
13962 @@ -29,7 +29,7 @@
13963  **                       and nonterminals.  "int" is used otherwise.
13964  **    YYNOCODE           is a number of type YYCODETYPE which corresponds
13965  **                       to no legal terminal or nonterminal number.  This
13966 -**                       number is used to fill in empty slots of the hash 
13967 +**                       number is used to fill in empty slots of the hash
13968  **                       table.
13969  **    YYFALLBACK         If defined, this indicates that one or more tokens
13970  **                       have fall-back values which should be used if the
13971 @@ -38,7 +38,7 @@
13972  **                       and nonterminal numbers.  "unsigned char" is
13973  **                       used if there are fewer than 250 rules and
13974  **                       states combined.  "int" is used otherwise.
13975 -**    ParseTOKENTYPE     is the data type used for minor tokens given 
13976 +**    ParseTOKENTYPE     is the data type used for minor tokens given
13977  **                       directly to the parser from the tokenizer.
13978  **    YYMINORTYPE        is the data type used for all minor tokens.
13979  **                       This is typically a union of many types, one of
13980 @@ -62,7 +62,7 @@
13981  /* Next are that tables used to determine what action to take based on the
13982  ** current state and lookahead token.  These tables are used to implement
13983  ** functions that take a state number and lookahead value and return an
13984 -** action integer.  
13985 +** action integer.
13986  **
13987  ** Suppose the action integer is N.  Then the action is determined as
13988  ** follows
13989 @@ -87,7 +87,7 @@
13990  ** If the index value yy_shift_ofst[S]+X is out of range or if the value
13991  ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
13992  ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
13993 -** and that yy_default[S] should be used instead.  
13994 +** and that yy_default[S] should be used instead.
13995  **
13996  ** The formula above is for computing the action when the lookahead is
13997  ** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
13998 @@ -111,7 +111,7 @@
13999  
14000  /* The next table maps tokens into fallback tokens.  If a construct
14001  ** like the following:
14002 -** 
14003 +**
14004  **      %fallback ID X Y Z.
14005  **
14006  ** appears in the grammer, then ID becomes a fallback token for X, Y,
14007 @@ -163,10 +163,10 @@
14008  #endif /* NDEBUG */
14009  
14010  #ifndef NDEBUG
14011 -/* 
14012 +/*
14013  ** Turn parser tracing on by giving a stream to which to write the trace
14014  ** and a prompt to preface each trace message.  Tracing is turned off
14015 -** by making either argument NULL 
14016 +** by making either argument NULL
14017  **
14018  ** Inputs:
14019  ** <ul>
14020 @@ -191,7 +191,7 @@
14021  #ifndef NDEBUG
14022  /* For tracing shifts, the names of all terminals and nonterminals
14023  ** are required.  The following table supplies these names */
14024 -static const char *yyTokenName[] = { 
14025 +static const char *yyTokenName[] = {
14026  %%
14027  };
14028  #endif /* NDEBUG */
14029 @@ -220,7 +220,7 @@
14030  #endif
14031  }
14032  
14033 -/* 
14034 +/*
14035  ** This function allocates a new parser.
14036  ** The only argument is a pointer to a function which works like
14037  ** malloc.
14038 @@ -251,7 +251,7 @@
14039      /* Here is inserted the actions which take place when a
14040      ** terminal or non-terminal is destroyed.  This can happen
14041      ** when the symbol is popped from the stack during a
14042 -    ** reduce or during error processing or when a parser is 
14043 +    ** reduce or during error processing or when a parser is
14044      ** being destroyed before it is finished parsing.
14045      **
14046      ** Note: during a reduce, the only symbols destroyed are those
14047 @@ -289,7 +289,7 @@
14048    return yymajor;
14049  }
14050  
14051 -/* 
14052 +/*
14053  ** Deallocate and destroy a parser.  Destructors are all called for
14054  ** all stack elements before shutting the parser down.
14055  **
14056 @@ -325,7 +325,7 @@
14057  ){
14058    int i;
14059    int stateno = pParser->yystack[pParser->yyidx].stateno;
14060
14061 +
14062    /* if( pParser->yyidx<0 ) return YY_NO_ACTION;  */
14063    i = yy_shift_ofst[stateno];
14064    if( i==YY_SHIFT_USE_DFLT ){
14065 @@ -369,7 +369,7 @@
14066  ){
14067    int i;
14068    int stateno = pParser->yystack[pParser->yyidx].stateno;
14069
14070 +
14071    i = yy_reduce_ofst[stateno];
14072    if( i==YY_REDUCE_USE_DFLT ){
14073      return yy_default[stateno];
14074 @@ -455,7 +455,7 @@
14075    ParseARG_FETCH;
14076    yymsp = &yypParser->yystack[yypParser->yyidx];
14077  #ifndef NDEBUG
14078 -  if( yyTraceFILE && yyruleno>=0 
14079 +  if( yyTraceFILE && yyruleno>=0
14080          && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
14081      fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
14082        yyRuleName[yyruleno]);
14083 @@ -608,7 +608,7 @@
14084  #ifdef YYERRORSYMBOL
14085        /* A syntax error has occurred.
14086        ** The response to an error depends upon whether or not the
14087 -      ** grammar defines an error token "ERROR".  
14088 +      ** grammar defines an error token "ERROR".
14089        **
14090        ** This is what we do if the grammar does define ERROR:
14091        **
14092 --- ../lighttpd-1.4.11/src/log.c        2005-11-07 15:01:35.000000000 +0200
14093 +++ lighttpd-1.4.12/src/log.c   2006-07-18 13:03:40.000000000 +0300
14094 @@ -5,7 +5,6 @@
14095  #include <errno.h>
14096  #include <fcntl.h>
14097  #include <time.h>
14098 -#include <unistd.h>
14099  #include <string.h>
14100  #include <stdlib.h>
14101  
14102 @@ -16,6 +15,10 @@
14103  #include "config.h"
14104  #endif
14105  
14106 +#ifdef _WIN32
14107 +#undef HAVE_SYSLOG_H
14108 +#endif
14109 +
14110  #ifdef HAVE_SYSLOG_H
14111  #include <syslog.h>
14112  #endif
14113 @@ -23,6 +26,8 @@
14114  #include "log.h"
14115  #include "array.h"
14116  
14117 +#include "sys-files.h"
14118 +
14119  #ifdef HAVE_VALGRIND_VALGRIND_H
14120  #include <valgrind/valgrind.h>
14121  #endif
14122 @@ -31,55 +36,114 @@
14123  # define O_LARGEFILE 0
14124  #endif
14125  
14126 -/** 
14127 +/**
14128   * open the errorlog
14129 - * 
14130 + *
14131   * we have 3 possibilities:
14132   * - stderr (default)
14133 - * - syslog 
14134 + * - syslog
14135   * - logfile
14136 - * 
14137 + *
14138   * if the open failed, report to the user and die
14139 - * 
14140 + *
14141   */
14142  
14143 -int log_error_open(server *srv) {
14144 +
14145 +typedef struct {
14146 +       buffer *file;
14147 +       unsigned short use_syslog;
14148 +
14149 +       /* the errorlog */
14150         int fd;
14151 -       int close_stderr = 1;
14152 +       enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG } mode;
14153 +       buffer *buf;
14154 +
14155 +       time_t cached_ts;
14156 +       buffer *cached_ts_str;
14157 +} errorlog;
14158 +
14159 +errorlog *myconfig = NULL;
14160 +
14161 +void log_init(void) {
14162 +       /* use syslog */
14163 +       errorlog *err;
14164 +
14165 +       err = calloc(1, sizeof(*err));
14166         
14167 +       err->fd = -1;
14168 +       err->mode = ERRORLOG_STDERR;
14169 +       err->buf = buffer_init();
14170 +       err->cached_ts_str = buffer_init();
14171 +
14172 +       myconfig = err;
14173 +}
14174 +
14175 +void log_free(void) {
14176 +       errorlog *err = myconfig;
14177 +
14178 +       if (!err) return;
14179 +
14180 +       TRACE("%s", "server stopped");
14181 +
14182 +       switch(err->mode) {
14183 +       case ERRORLOG_FILE:
14184 +               close(err->fd);
14185 +               break;
14186 +       case ERRORLOG_SYSLOG:
14187 +#ifdef HAVE_SYSLOG_H
14188 +               closelog();
14189 +#endif
14190 +               break;
14191 +       case ERRORLOG_STDERR:
14192 +               break;
14193 +       }
14194 +
14195 +       buffer_free(err->buf);
14196 +       buffer_free(err->cached_ts_str);
14197 +       if (err->file) buffer_free(err->file);
14198 +
14199 +       free(err);
14200 +
14201 +       myconfig = NULL;
14202 +}
14203 +
14204 +int log_error_open(buffer *file, int use_syslog) {
14205 +       int fd;
14206 +       int close_stderr = 1;
14207 +
14208 +       errorlog *err = myconfig;
14209 +
14210  #ifdef HAVE_SYSLOG_H
14211         /* perhaps someone wants to use syslog() */
14212         openlog("lighttpd", LOG_CONS | LOG_PID, LOG_DAEMON);
14213  #endif
14214 -       srv->errorlog_mode = ERRORLOG_STDERR;
14215 -       
14216 -       if (srv->srvconf.errorlog_use_syslog) {
14217 -               srv->errorlog_mode = ERRORLOG_SYSLOG;
14218 -       } else if (!buffer_is_empty(srv->srvconf.errorlog_file)) {
14219 -               const char *logfile = srv->srvconf.errorlog_file->ptr;
14220 -               
14221 -               if (-1 == (srv->errorlog_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14222 -                       log_error_write(srv, __FILE__, __LINE__, "SSSS", 
14223 -                                       "opening errorlog '", logfile,
14224 +       err->mode = ERRORLOG_STDERR;
14225 +
14226 +       if (use_syslog) {
14227 +               err->mode = ERRORLOG_SYSLOG;
14228 +       } else if (!buffer_is_empty(file)) {
14229 +               if (-1 == (err->fd = open(file->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14230 +                       log_error_write(NULL, __FILE__, __LINE__, "SBSS",
14231 +                                       "opening errorlog '", file,
14232                                         "' failed: ", strerror(errno));
14233 -                       
14234 +
14235                         return -1;
14236                 }
14237  #ifdef FD_CLOEXEC
14238                 /* close fd on exec (cgi) */
14239 -               fcntl(srv->errorlog_fd, F_SETFD, FD_CLOEXEC);
14240 +               fcntl(err->fd, F_SETFD, FD_CLOEXEC);
14241  #endif
14242 -               srv->errorlog_mode = ERRORLOG_FILE;
14243 +               err->mode = ERRORLOG_FILE;
14244         }
14245 -       
14246 -       log_error_write(srv, __FILE__, __LINE__, "s", "server started");
14247 -       
14248 +
14249 +       TRACE("%s", "server started");
14250 +
14251  #ifdef HAVE_VALGRIND_VALGRIND_H
14252         /* don't close stderr for debugging purposes if run in valgrind */
14253         if (RUNNING_ON_VALGRIND) close_stderr = 0;
14254  #endif
14255 -       if (srv->errorlog_mode == ERRORLOG_STDERR) close_stderr = 0;
14256 -       
14257 +       if (err->mode == ERRORLOG_STDERR) close_stderr = 0;
14258 +
14259         /* move stderr to /dev/null */
14260         if (close_stderr &&
14261             -1 != (fd = open("/dev/null", O_WRONLY))) {
14262 @@ -90,167 +154,202 @@
14263         return 0;
14264  }
14265  
14266 -/** 
14267 +/**
14268   * open the errorlog
14269 - * 
14270 + *
14271   * if the open failed, report to the user and die
14272   * if no filename is given, use syslog instead
14273 - * 
14274 + *
14275   */
14276  
14277 -int log_error_cycle(server *srv) {
14278 +int log_error_cycle(void) {
14279         /* only cycle if we are not in syslog-mode */
14280 -       
14281 -       if (srv->errorlog_mode == ERRORLOG_FILE) {
14282 -               const char *logfile = srv->srvconf.errorlog_file->ptr;
14283 +
14284 +       errorlog *err = myconfig;
14285 +
14286 +       if (err->mode == ERRORLOG_FILE) {
14287 +               buffer *file = err->file;
14288                 /* already check of opening time */
14289 -               
14290 +
14291                 int new_fd;
14292 -               
14293 -               if (-1 == (new_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14294 +
14295 +               if (-1 == (new_fd = open(file->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14296                         /* write to old log */
14297 -                       log_error_write(srv, __FILE__, __LINE__, "SSSSS", 
14298 -                                       "cycling errorlog '", logfile,
14299 +                       log_error_write(NULL, __FILE__, __LINE__, "SBSSS",
14300 +                                       "cycling errorlog '", file,
14301                                         "' failed: ", strerror(errno),
14302                                         ", falling back to syslog()");
14303 -                       
14304 -                       close(srv->errorlog_fd);
14305 -                       srv->errorlog_fd = -1;
14306 -#ifdef HAVE_SYSLOG_H   
14307 -                       srv->errorlog_mode = ERRORLOG_SYSLOG;
14308 +
14309 +                       close(err->fd);
14310 +                       err->fd = -1;
14311 +#ifdef HAVE_SYSLOG_H
14312 +                       err->mode = ERRORLOG_SYSLOG;
14313  #endif
14314                 } else {
14315                         /* ok, new log is open, close the old one */
14316 -                       close(srv->errorlog_fd);
14317 -                       srv->errorlog_fd = new_fd;
14318 +                       close(err->fd);
14319 +                       err->fd = new_fd;
14320                 }
14321         }
14322 -       
14323 -       log_error_write(srv, __FILE__, __LINE__, "s", "logfiles cycled");
14324 -       
14325 -       return 0;
14326 -}
14327  
14328 -int log_error_close(server *srv) {
14329 -       log_error_write(srv, __FILE__, __LINE__, "s", "server stopped");
14330 -       
14331 -       switch(srv->errorlog_mode) {
14332 -       case ERRORLOG_FILE:
14333 -               close(srv->errorlog_fd);
14334 -               break;
14335 -       case ERRORLOG_SYSLOG:
14336 -#ifdef HAVE_SYSLOG_H
14337 -               closelog();
14338 -#endif
14339 -               break;
14340 -       case ERRORLOG_STDERR:
14341 -               break;
14342 -       }
14343 -       
14344 +       TRACE("%s", "logfiles cycled");
14345 +
14346         return 0;
14347  }
14348  
14349 -int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...) {
14350 +int log_error_write(void *srv, const char *filename, unsigned int line, const char *fmt, ...) {
14351         va_list ap;
14352 -       
14353 -       switch(srv->errorlog_mode) {
14354 +       time_t t;
14355 +
14356 +       errorlog *err = myconfig;
14357 +
14358 +       switch(err->mode) {
14359         case ERRORLOG_FILE:
14360         case ERRORLOG_STDERR:
14361                 /* cache the generated timestamp */
14362 -               if (srv->cur_ts != srv->last_generated_debug_ts) {
14363 -                       buffer_prepare_copy(srv->ts_debug_str, 255);
14364 -                       strftime(srv->ts_debug_str->ptr, srv->ts_debug_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts)));
14365 -                       srv->ts_debug_str->used = strlen(srv->ts_debug_str->ptr) + 1;
14366 -                       
14367 -                       srv->last_generated_debug_ts = srv->cur_ts;
14368 +               t = time(NULL);
14369 +               
14370 +               if (t != err->cached_ts) {
14371 +                       buffer_prepare_copy(err->cached_ts_str, 255);
14372 +                       strftime(err->cached_ts_str->ptr, err->cached_ts_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(t)));
14373 +                       err->cached_ts_str->used = strlen(err->cached_ts_str->ptr) + 1;
14374 +                       err->cached_ts = t;
14375                 }
14376  
14377 -               buffer_copy_string_buffer(srv->errorlog_buf, srv->ts_debug_str);
14378 -               BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ": (");
14379 +               buffer_copy_string_buffer(err->buf, err->cached_ts_str);
14380 +               BUFFER_APPEND_STRING_CONST(err->buf, ": (");
14381                 break;
14382         case ERRORLOG_SYSLOG:
14383                 /* syslog is generating its own timestamps */
14384 -               BUFFER_COPY_STRING_CONST(srv->errorlog_buf, "(");
14385 +               BUFFER_COPY_STRING_CONST(err->buf, "(");
14386                 break;
14387         }
14388 -       
14389 -       buffer_append_string(srv->errorlog_buf, filename);
14390 -       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ".");
14391 -       buffer_append_long(srv->errorlog_buf, line);
14392 -       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ") ");
14393 -       
14394 -       
14395 +
14396 +       buffer_append_string(err->buf, filename);
14397 +       BUFFER_APPEND_STRING_CONST(err->buf, ".");
14398 +       buffer_append_long(err->buf, line);
14399 +       BUFFER_APPEND_STRING_CONST(err->buf, ") ");
14400 +
14401         for(va_start(ap, fmt); *fmt; fmt++) {
14402                 int d;
14403                 char *s;
14404                 buffer *b;
14405                 off_t o;
14406 -               
14407 +
14408                 switch(*fmt) {
14409                 case 's':           /* string */
14410                         s = va_arg(ap, char *);
14411 -                       buffer_append_string(srv->errorlog_buf, s);
14412 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14413 +                       buffer_append_string(err->buf, s);
14414 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
14415                         break;
14416                 case 'b':           /* buffer */
14417                         b = va_arg(ap, buffer *);
14418 -                       buffer_append_string_buffer(srv->errorlog_buf, b);
14419 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14420 +                       buffer_append_string_buffer(err->buf, b);
14421 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
14422                         break;
14423                 case 'd':           /* int */
14424                         d = va_arg(ap, int);
14425 -                       buffer_append_long(srv->errorlog_buf, d);
14426 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14427 +                       buffer_append_long(err->buf, d);
14428 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
14429                         break;
14430                 case 'o':           /* off_t */
14431                         o = va_arg(ap, off_t);
14432 -                       buffer_append_off_t(srv->errorlog_buf, o);
14433 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14434 +                       buffer_append_off_t(err->buf, o);
14435 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
14436                         break;
14437                 case 'x':           /* int (hex) */
14438                         d = va_arg(ap, int);
14439 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "0x");
14440 -                       buffer_append_long_hex(srv->errorlog_buf, d);
14441 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14442 +                       BUFFER_APPEND_STRING_CONST(err->buf, "0x");
14443 +                       buffer_append_long_hex(err->buf, d);
14444 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
14445                         break;
14446                 case 'S':           /* string */
14447                         s = va_arg(ap, char *);
14448 -                       buffer_append_string(srv->errorlog_buf, s);
14449 +                       buffer_append_string(err->buf, s);
14450                         break;
14451                 case 'B':           /* buffer */
14452                         b = va_arg(ap, buffer *);
14453 -                       buffer_append_string_buffer(srv->errorlog_buf, b);
14454 +                       buffer_append_string_buffer(err->buf, b);
14455                         break;
14456                 case 'D':           /* int */
14457                         d = va_arg(ap, int);
14458 -                       buffer_append_long(srv->errorlog_buf, d);
14459 +                       buffer_append_long(err->buf, d);
14460                         break;
14461                 case '(':
14462                 case ')':
14463 -               case '<':       
14464 +               case '<':
14465                 case '>':
14466                 case ',':
14467                 case ' ':
14468 -                       buffer_append_string_len(srv->errorlog_buf, fmt, 1);
14469 +                       buffer_append_string_len(err->buf, fmt, 1);
14470                         break;
14471                 }
14472         }
14473         va_end(ap);
14474 -       
14475 -       switch(srv->errorlog_mode) {
14476 +
14477 +       switch(err->mode) {
14478         case ERRORLOG_FILE:
14479 -               BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "\n");
14480 -               write(srv->errorlog_fd, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1);
14481 +               BUFFER_APPEND_STRING_CONST(err->buf, "\n");
14482 +               write(err->fd, err->buf->ptr, err->buf->used - 1);
14483                 break;
14484         case ERRORLOG_STDERR:
14485 -               BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "\n");
14486 -               write(STDERR_FILENO, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1);
14487 +               BUFFER_APPEND_STRING_CONST(err->buf, "\n");
14488 +               write(STDERR_FILENO, err->buf->ptr, err->buf->used - 1);
14489                 break;
14490 +#ifdef HAVE_SYSLOG_H
14491 +       case ERRORLOG_SYSLOG:
14492 +               syslog(LOG_ERR, "%s", err->buf->ptr);
14493 +               break;
14494 +#endif
14495 +       }
14496 +
14497 +       return 0;
14498 +}
14499 +
14500 +static int log_trace_write(const char *fmt, va_list ap) {
14501 +       buffer *b;
14502 +       int l;
14503 +       errorlog *err = myconfig;
14504 +       
14505 +       b = buffer_init();
14506 +       buffer_prepare_copy(b, 1024);
14507 +       l = vsnprintf(b->ptr, b->size - 1, fmt, ap);
14508 +       if (l > 0) {
14509 +               b->used = (l > b->size - 1) ? b->size : l + 1;
14510 +       }
14511 +
14512 +       /* write b */
14513 +       switch(err->mode) {
14514 +       case ERRORLOG_FILE:
14515 +               buffer_append_string(b, "\r\n");
14516 +               write(err->fd, b->ptr, b->used - 1);
14517 +               break;
14518 +       case ERRORLOG_STDERR:
14519 +               buffer_append_string(b, "\r\n");
14520 +               write(STDERR_FILENO, b->ptr, b->used - 1);
14521 +               break;
14522 +#ifdef HAVE_SYSLOG_H
14523         case ERRORLOG_SYSLOG:
14524 -               syslog(LOG_ERR, "%s", srv->errorlog_buf->ptr);
14525 +               syslog(LOG_ERR, "%s", b->ptr);
14526                 break;
14527 +#endif
14528         }
14529         
14530 +       buffer_free(b);
14531 +
14532 +       return 0;
14533 +}
14534 +
14535 +int log_trace(const char *fmt, ...) {
14536 +       va_list ap;
14537 +
14538 +       va_start(ap, fmt);
14539 +
14540 +       log_trace_write(fmt, ap);
14541 +
14542 +       va_end(ap);
14543 +
14544         return 0;
14545  }
14546  
14547 +
14548 --- ../lighttpd-1.4.11/src/log.h        2005-08-11 01:26:36.000000000 +0300
14549 +++ lighttpd-1.4.12/src/log.h   2006-07-18 13:03:40.000000000 +0300
14550 @@ -1,13 +1,22 @@
14551  #ifndef _LOG_H_
14552  #define _LOG_H_
14553  
14554 -#include "server.h"
14555 +#include "buffer.h"
14556  
14557 -#define WP() log_error_write(srv, __FILE__, __LINE__, "");
14558 +void log_init(void); 
14559 +void log_free(void); 
14560  
14561 -int log_error_open(server *srv);
14562 -int log_error_close(server *srv);
14563 -int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...);
14564 -int log_error_cycle(server *srv);
14565 -       
14566 +int log_error_open(buffer *file, int use_syslog);
14567 +int log_error_close();
14568 +int log_error_write(void *srv, const char *filename, unsigned int line, const char *fmt, ...);
14569 +int log_error_cycle();
14570 +
14571 +#define ERROR(fmt, ...) \
14572 +       log_trace("%s.%d: (error) "fmt, __FILE__, __LINE__, __VA_ARGS__)
14573 +
14574 +#define TRACE(fmt, ...) \
14575 +       log_trace("%s.%d: (trace) "fmt, __FILE__, __LINE__, __VA_ARGS__)
14576 +
14577 +#define SEGFAULT() do { ERROR("%s", "Ooh, Ooh, Ooh. Something is not good ... going down"); abort(); } while(0)
14578 +int log_trace(const char *fmt, ...);
14579  #endif
14580 --- ../lighttpd-1.4.11/src/md5.h        2005-11-17 16:20:40.000000000 +0200
14581 +++ lighttpd-1.4.12/src/md5.h   2006-07-16 00:26:04.000000000 +0300
14582 @@ -30,9 +30,15 @@
14583  # include <inttypes.h>
14584  #endif
14585  
14586 +#ifdef _WIN32
14587 +#define UINT4 unsigned __int32
14588 +#define UINT2 unsigned __int16
14589 +#define POINTER unsigned char *
14590 +#else
14591  #define UINT4 uint32_t
14592  #define UINT2 uint16_t
14593  #define POINTER unsigned char *
14594 +#endif
14595  
14596  /* MD5 context. */
14597  typedef struct {
14598 --- ../lighttpd-1.4.11/src/mod_access.c 2006-01-14 19:44:54.000000000 +0200
14599 +++ lighttpd-1.4.12/src/mod_access.c    2006-07-16 00:26:04.000000000 +0300
14600 @@ -8,126 +8,125 @@
14601  
14602  #include "plugin.h"
14603  
14604 +#include "sys-strings.h"
14605 +
14606  typedef struct {
14607         array *access_deny;
14608  } plugin_config;
14609  
14610  typedef struct {
14611         PLUGIN_DATA;
14612 -       
14613 +
14614         plugin_config **config_storage;
14615 -       
14616 -       plugin_config conf; 
14617 +
14618 +       plugin_config conf;
14619  } plugin_data;
14620  
14621  INIT_FUNC(mod_access_init) {
14622         plugin_data *p;
14623 -       
14624 +
14625         p = calloc(1, sizeof(*p));
14626 -       
14627 +
14628         return p;
14629  }
14630  
14631  FREE_FUNC(mod_access_free) {
14632         plugin_data *p = p_d;
14633 -       
14634 +
14635         UNUSED(srv);
14636  
14637         if (!p) return HANDLER_GO_ON;
14638 -       
14639 +
14640         if (p->config_storage) {
14641                 size_t i;
14642                 for (i = 0; i < srv->config_context->used; i++) {
14643                         plugin_config *s = p->config_storage[i];
14644 -                       
14645 +
14646                         array_free(s->access_deny);
14647 -                       
14648 +
14649                         free(s);
14650                 }
14651                 free(p->config_storage);
14652         }
14653 -       
14654 +
14655         free(p);
14656 -       
14657 +
14658         return HANDLER_GO_ON;
14659  }
14660  
14661  SETDEFAULTS_FUNC(mod_access_set_defaults) {
14662         plugin_data *p = p_d;
14663         size_t i = 0;
14664 -       
14665 -       config_values_t cv[] = { 
14666 +
14667 +       config_values_t cv[] = {
14668                 { "url.access-deny",             NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
14669                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
14670         };
14671 -       
14672 +
14673         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
14674 -       
14675 +
14676         for (i = 0; i < srv->config_context->used; i++) {
14677                 plugin_config *s;
14678 -               
14679 +
14680                 s = calloc(1, sizeof(plugin_config));
14681                 s->access_deny    = array_init();
14682 -               
14683 +
14684                 cv[0].destination = s->access_deny;
14685 -               
14686 +
14687                 p->config_storage[i] = s;
14688 -       
14689 +
14690                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
14691                         return HANDLER_ERROR;
14692                 }
14693         }
14694 -       
14695 +
14696         return HANDLER_GO_ON;
14697  }
14698  
14699 -#define PATCH(x) \
14700 -       p->conf.x = s->x;
14701  static int mod_access_patch_connection(server *srv, connection *con, plugin_data *p) {
14702         size_t i, j;
14703         plugin_config *s = p->config_storage[0];
14704  
14705 -       PATCH(access_deny);
14706 -       
14707 +       PATCH_OPTION(access_deny);
14708 +
14709         /* skip the first, the global context */
14710         for (i = 1; i < srv->config_context->used; i++) {
14711                 data_config *dc = (data_config *)srv->config_context->data[i];
14712                 s = p->config_storage[i];
14713 -               
14714 +
14715                 /* condition didn't match */
14716                 if (!config_check_cond(srv, con, dc)) continue;
14717 -               
14718 +
14719                 /* merge config */
14720                 for (j = 0; j < dc->value->used; j++) {
14721                         data_unset *du = dc->value->data[j];
14722 -                       
14723 +
14724                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.access-deny"))) {
14725 -                               PATCH(access_deny);
14726 +                               PATCH_OPTION(access_deny);
14727                         }
14728                 }
14729         }
14730 -       
14731 +
14732         return 0;
14733  }
14734 -#undef PATCH
14735  
14736  URIHANDLER_FUNC(mod_access_uri_handler) {
14737         plugin_data *p = p_d;
14738         int s_len;
14739         size_t k;
14740 -       
14741 +
14742         if (con->uri.path->used == 0) return HANDLER_GO_ON;
14743 -       
14744 +
14745         mod_access_patch_connection(srv, con, p);
14746 -       
14747 +
14748         s_len = con->uri.path->used - 1;
14749 -       
14750 +
14751         for (k = 0; k < p->conf.access_deny->used; k++) {
14752                 data_string *ds = (data_string *)p->conf.access_deny->data[k];
14753                 int ct_len = ds->value->used - 1;
14754 -               
14755 +
14756                 if (ct_len > s_len) continue;
14757 -               
14758 +
14759                 if (ds->value->used == 0) continue;
14760  
14761                 /* if we have a case-insensitive FS we have to lower-case the URI here too */
14762 @@ -135,18 +134,18 @@
14763                 if (con->conf.force_lowercase_filenames) {
14764                         if (0 == strncasecmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
14765                                 con->http_status = 403;
14766 -                       
14767 +
14768                                 return HANDLER_FINISHED;
14769                         }
14770                 } else {
14771                         if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
14772                                 con->http_status = 403;
14773 -                       
14774 +
14775                                 return HANDLER_FINISHED;
14776                         }
14777                 }
14778         }
14779 -       
14780 +
14781         /* not found */
14782         return HANDLER_GO_ON;
14783  }
14784 @@ -155,13 +154,13 @@
14785  int mod_access_plugin_init(plugin *p) {
14786         p->version     = LIGHTTPD_VERSION_ID;
14787         p->name        = buffer_init_string("access");
14788 -       
14789 +
14790         p->init        = mod_access_init;
14791         p->set_defaults = mod_access_set_defaults;
14792         p->handle_uri_clean  = mod_access_uri_handler;
14793         p->cleanup     = mod_access_free;
14794 -       
14795 +
14796         p->data        = NULL;
14797 -       
14798 +
14799         return 0;
14800  }
14801 --- ../lighttpd-1.4.11/src/mod_accesslog.c      2006-01-31 14:01:43.000000000 +0200
14802 +++ lighttpd-1.4.12/src/mod_accesslog.c 2006-07-16 00:26:04.000000000 +0300
14803 @@ -6,8 +6,7 @@
14804  #include <ctype.h>
14805  #include <stdlib.h>
14806  #include <string.h>
14807 -#include <fcntl.h>
14808 -#include <unistd.h>
14809 +#include <fcntl.h> /* only the defines on windows */
14810  #include <errno.h>
14811  #include <time.h>
14812  
14813 @@ -22,6 +21,7 @@
14814  #include "inet_ntop_cache.h"
14815  
14816  #include "sys-socket.h"
14817 +#include "sys-files.h"
14818  
14819  #ifdef HAVE_SYSLOG_H
14820  # include <syslog.h>
14821 @@ -29,7 +29,7 @@
14822  
14823  typedef struct {
14824         char key;
14825 -       enum { 
14826 +       enum {
14827                 FORMAT_UNSET,
14828                         FORMAT_UNSUPPORTED,
14829                         FORMAT_PERCENT,
14830 @@ -41,7 +41,7 @@
14831                         FORMAT_STATUS,
14832                         FORMAT_BYTES_OUT_NO_HEADER,
14833                         FORMAT_HEADER,
14834 -                       
14835 +
14836                         FORMAT_REMOTE_ADDR,
14837                         FORMAT_LOCAL_ADDR,
14838                         FORMAT_COOKIE,
14839 @@ -59,20 +59,20 @@
14840                         FORMAT_CONNECTION_STATUS,
14841                         FORMAT_BYTES_IN,
14842                         FORMAT_BYTES_OUT,
14843 -                       
14844 +
14845                         FORMAT_RESPONSE_HEADER
14846         } type;
14847  } format_mapping;
14848  
14849  /**
14850 - * 
14851 - * 
14852 + *
14853 + *
14854   * "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
14855 - * 
14856 + *
14857   */
14858  
14859 -const format_mapping fmap[] = 
14860 -{ 
14861 +const format_mapping fmap[] =
14862 +{
14863         { '%', FORMAT_PERCENT },
14864         { 'h', FORMAT_REMOTE_HOST },
14865         { 'l', FORMAT_REMOTE_IDENT },
14866 @@ -82,7 +82,7 @@
14867         { 's', FORMAT_STATUS },
14868         { 'b', FORMAT_BYTES_OUT_NO_HEADER },
14869         { 'i', FORMAT_HEADER },
14870 -       
14871 +
14872         { 'a', FORMAT_REMOTE_ADDR },
14873         { 'A', FORMAT_LOCAL_ADDR },
14874         { 'B', FORMAT_BYTES_OUT_NO_HEADER },
14875 @@ -103,23 +103,23 @@
14876         { 'X', FORMAT_CONNECTION_STATUS },
14877         { 'I', FORMAT_BYTES_IN },
14878         { 'O', FORMAT_BYTES_OUT },
14879 -       
14880 +
14881         { 'o', FORMAT_RESPONSE_HEADER },
14882 -       
14883 +
14884         { '\0', FORMAT_UNSET }
14885  };
14886  
14887  
14888  typedef struct {
14889         enum { FIELD_UNSET, FIELD_STRING, FIELD_FORMAT } type;
14890 -       
14891 +
14892         buffer *string;
14893         int field;
14894  } format_field;
14895  
14896  typedef struct {
14897         format_field **ptr;
14898 -       
14899 +
14900         size_t used;
14901         size_t size;
14902  } format_fields;
14903 @@ -128,39 +128,39 @@
14904         buffer *access_logfile;
14905         buffer *format;
14906         unsigned short use_syslog;
14907 -       
14908 -       
14909 +
14910 +
14911         int    log_access_fd;
14912         time_t last_generated_accesslog_ts;
14913         time_t *last_generated_accesslog_ts_ptr;
14914 -       
14915 -       
14916 +
14917 +
14918         buffer *access_logbuffer;
14919         buffer *ts_accesslog_str;
14920 -       
14921 +
14922         format_fields *parsed_format;
14923  } plugin_config;
14924  
14925  typedef struct {
14926         PLUGIN_DATA;
14927 -       
14928 +
14929         plugin_config **config_storage;
14930 -       plugin_config conf; 
14931 +       plugin_config conf;
14932  } plugin_data;
14933  
14934  INIT_FUNC(mod_accesslog_init) {
14935         plugin_data *p;
14936 -       
14937 +
14938         p = calloc(1, sizeof(*p));
14939 -       
14940 +
14941         return p;
14942  }
14943  
14944  int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) {
14945         size_t i, j, k = 0, start = 0;
14946 -       
14947 +
14948         for (i = 0; i < format->used - 1; i++) {
14949 -               
14950 +
14951                 switch(format->ptr[i]) {
14952                 case '%':
14953                         if (start != i) {
14954 @@ -173,19 +173,19 @@
14955                                         fields->size += 16;
14956                                         fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
14957                                 }
14958 -                               
14959 +
14960                                 fields->ptr[fields->used] = malloc(sizeof(format_fields));
14961                                 fields->ptr[fields->used]->type = FIELD_STRING;
14962                                 fields->ptr[fields->used]->string = buffer_init();
14963 -                               
14964 +
14965                                 buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
14966 -                               
14967 +
14968                                 fields->used++;
14969                         }
14970 -                       
14971 -                       
14972 +
14973 +
14974                         /* we need a new field */
14975 -                       
14976 +
14977                         if (fields->size == 0) {
14978                                 fields->size = 16;
14979                                 fields->used = 0;
14980 @@ -194,43 +194,43 @@
14981                                 fields->size += 16;
14982                                 fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
14983                         }
14984 -                       
14985 +
14986                         /* search for the terminating command */
14987                         switch (format->ptr[i+1]) {
14988                         case '>':
14989                         case '<':
14990                                 /* only for s */
14991 -                               
14992 +
14993                                 for (j = 0; fmap[j].key != '\0'; j++) {
14994                                         if (fmap[j].key != format->ptr[i+2]) continue;
14995 -                                       
14996 +
14997                                         /* found key */
14998 -                                               
14999 +
15000                                         fields->ptr[fields->used] = malloc(sizeof(format_fields));
15001                                         fields->ptr[fields->used]->type = FIELD_FORMAT;
15002                                         fields->ptr[fields->used]->field = fmap[j].type;
15003                                         fields->ptr[fields->used]->string = NULL;
15004 -                                       
15005 +
15006                                         fields->used++;
15007 -                                       
15008 +
15009                                         break;
15010                                 }
15011 -                               
15012 +
15013                                 if (fmap[j].key == '\0') {
15014                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15015                                         return -1;
15016                                 }
15017 -                               
15018 +
15019                                 start = i + 3;
15020 -                               
15021 +
15022                                 break;
15023                         case '{':
15024                                 /* go forward to } */
15025 -                               
15026 +
15027                                 for (k = i+2; k < format->used - 1; k++) {
15028                                         if (format->ptr[k] == '}') break;
15029                                 }
15030 -                               
15031 +
15032                                 if (k == format->used - 1) {
15033                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15034                                         return -1;
15035 @@ -239,62 +239,62 @@
15036                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15037                                         return -1;
15038                                 }
15039 -                               
15040 +
15041                                 for (j = 0; fmap[j].key != '\0'; j++) {
15042                                         if (fmap[j].key != format->ptr[k+1]) continue;
15043 -                                       
15044 +
15045                                         /* found key */
15046 -                                               
15047 +
15048                                         fields->ptr[fields->used] = malloc(sizeof(format_fields));
15049                                         fields->ptr[fields->used]->type = FIELD_FORMAT;
15050                                         fields->ptr[fields->used]->field = fmap[j].type;
15051                                         fields->ptr[fields->used]->string = buffer_init();
15052 -                                       
15053 +
15054                                         buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + i + 2, k - (i + 2));
15055 -                                       
15056 +
15057                                         fields->used++;
15058 -                                       
15059 +
15060                                         break;
15061                                 }
15062 -                               
15063 +
15064                                 if (fmap[j].key == '\0') {
15065                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15066                                         return -1;
15067                                 }
15068 -                               
15069 +
15070                                 start = k + 2;
15071 -                               
15072 +
15073                                 break;
15074                         default:
15075                                 for (j = 0; fmap[j].key != '\0'; j++) {
15076                                         if (fmap[j].key != format->ptr[i+1]) continue;
15077 -                                       
15078 +
15079                                         /* found key */
15080 -                                               
15081 +
15082                                         fields->ptr[fields->used] = malloc(sizeof(format_fields));
15083                                         fields->ptr[fields->used]->type = FIELD_FORMAT;
15084                                         fields->ptr[fields->used]->field = fmap[j].type;
15085                                         fields->ptr[fields->used]->string = NULL;
15086 -                                       
15087 +
15088                                         fields->used++;
15089 -                                       
15090 +
15091                                         break;
15092                                 }
15093 -                               
15094 +
15095                                 if (fmap[j].key == '\0') {
15096                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15097                                         return -1;
15098                                 }
15099 -                               
15100 +
15101                                 start = i + 2;
15102 -                               
15103 +
15104                                 break;
15105                         }
15106 -                       
15107 +
15108                         break;
15109                 }
15110         }
15111 -       
15112 +
15113         if (start < i) {
15114                 /* copy the string */
15115                 if (fields->size == 0) {
15116 @@ -305,32 +305,32 @@
15117                         fields->size += 16;
15118                         fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
15119                 }
15120 -               
15121 +
15122                 fields->ptr[fields->used] = malloc(sizeof(format_fields));
15123                 fields->ptr[fields->used]->type = FIELD_STRING;
15124                 fields->ptr[fields->used]->string = buffer_init();
15125 -               
15126 +
15127                 buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
15128 -               
15129 +
15130                 fields->used++;
15131         }
15132 -       
15133 +
15134         return 0;
15135  }
15136  
15137  FREE_FUNC(mod_accesslog_free) {
15138         plugin_data *p = p_d;
15139         size_t i;
15140 -       
15141 +
15142         if (!p) return HANDLER_GO_ON;
15143 -       
15144 +
15145         if (p->config_storage) {
15146 -               
15147 +
15148                 for (i = 0; i < srv->config_context->used; i++) {
15149                         plugin_config *s = p->config_storage[i];
15150  
15151                         if (!s) continue;
15152 -                       
15153 +
15154                         if (s->access_logbuffer->used) {
15155                                 if (s->use_syslog) {
15156  # ifdef HAVE_SYSLOG_H
15157 @@ -342,14 +342,14 @@
15158                                         write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
15159                                 }
15160                         }
15161 -                       
15162 +
15163                         if (s->log_access_fd != -1) close(s->log_access_fd);
15164 -                       
15165 +
15166                         buffer_free(s->ts_accesslog_str);
15167                         buffer_free(s->access_logbuffer);
15168                         buffer_free(s->format);
15169                         buffer_free(s->access_logfile);
15170 -                       
15171 +
15172                         if (s->parsed_format) {
15173                                 size_t j;
15174                                 for (j = 0; j < s->parsed_format->used; j++) {
15175 @@ -359,36 +359,36 @@
15176                                 free(s->parsed_format->ptr);
15177                                 free(s->parsed_format);
15178                         }
15179 -                       
15180 +
15181                         free(s);
15182                 }
15183 -       
15184 +
15185                 free(p->config_storage);
15186         }
15187 -       
15188 +
15189         free(p);
15190 -       
15191 +
15192         return HANDLER_GO_ON;
15193  }
15194  
15195  SETDEFAULTS_FUNC(log_access_open) {
15196         plugin_data *p = p_d;
15197         size_t i = 0;
15198 -       
15199 -       config_values_t cv[] = { 
15200 +
15201 +       config_values_t cv[] = {
15202                 { "accesslog.filename",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
15203                 { "accesslog.use-syslog",           NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
15204                 { "accesslog.format",               NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
15205                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
15206         };
15207 -       
15208 +
15209         if (!p) return HANDLER_ERROR;
15210 -       
15211 +
15212         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
15213 -       
15214 +
15215         for (i = 0; i < srv->config_context->used; i++) {
15216                 plugin_config *s;
15217 -               
15218 +
15219                 s = calloc(1, sizeof(plugin_config));
15220                 s->access_logfile = buffer_init();
15221                 s->format = buffer_init();
15222 @@ -397,44 +397,44 @@
15223                 s->log_access_fd = -1;
15224                 s->last_generated_accesslog_ts = 0;
15225                 s->last_generated_accesslog_ts_ptr = &(s->last_generated_accesslog_ts);
15226 -               
15227 -       
15228 +
15229 +
15230                 cv[0].destination = s->access_logfile;
15231                 cv[1].destination = &(s->use_syslog);
15232                 cv[2].destination = s->format;
15233 -       
15234 +
15235                 p->config_storage[i] = s;
15236 -               
15237 +
15238                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
15239                         return HANDLER_ERROR;
15240                 }
15241 -               
15242 +
15243                 if (i == 0 && buffer_is_empty(s->format)) {
15244                         /* set a default logfile string */
15245 -                       
15246 +
15247                         buffer_copy_string(s->format, "%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"");
15248                 }
15249 -               
15250 +
15251                 /* parse */
15252 -               
15253 +
15254                 if (s->format->used) {
15255                         s->parsed_format = calloc(1, sizeof(*(s->parsed_format)));
15256 -                       
15257 +
15258                         if (-1 == accesslog_parse_format(srv, s->parsed_format, s->format)) {
15259  
15260 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
15261 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
15262                                                 "parsing accesslog-definition failed:", s->format);
15263  
15264                                 return HANDLER_ERROR;
15265                         }
15266  #if 0
15267 -                       /* debugging */                 
15268 +                       /* debugging */
15269                         for (j = 0; j < s->parsed_format->used; j++) {
15270                                 switch (s->parsed_format->ptr[j]->type) {
15271                                 case FIELD_FORMAT:
15272 -                                       log_error_write(srv, __FILE__, __LINE__, "ssds", 
15273 +                                       log_error_write(srv, __FILE__, __LINE__, "ssds",
15274                                                         "config:", "format", s->parsed_format->ptr[j]->field,
15275 -                                                       s->parsed_format->ptr[j]->string ? 
15276 +                                                       s->parsed_format->ptr[j]->string ?
15277                                                         s->parsed_format->ptr[j]->string->ptr : "" );
15278                                         break;
15279                                 case FIELD_STRING:
15280 @@ -446,52 +446,52 @@
15281                         }
15282  #endif
15283                 }
15284 -               
15285 +
15286                 if (s->use_syslog) {
15287                         /* ignore the next checks */
15288                         continue;
15289                 }
15290 -               
15291 +
15292                 if (buffer_is_empty(s->access_logfile)) continue;
15293 -               
15294 +
15295                 if (s->access_logfile->ptr[0] == '|') {
15296  #ifdef HAVE_FORK
15297                         /* create write pipe and spawn process */
15298 -                       
15299 +
15300                         int to_log_fds[2];
15301                         pid_t pid;
15302 -                       
15303 +
15304                         if (pipe(to_log_fds)) {
15305                                 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed: ", strerror(errno));
15306                                 return HANDLER_ERROR;
15307                         }
15308 -                       
15309 +
15310                         /* fork, execve */
15311                         switch (pid = fork()) {
15312 -                       case 0: 
15313 +                       case 0:
15314                                 /* child */
15315 -                               
15316 +
15317                                 close(STDIN_FILENO);
15318                                 dup2(to_log_fds[0], STDIN_FILENO);
15319                                 close(to_log_fds[0]);
15320                                 /* not needed */
15321                                 close(to_log_fds[1]);
15322 -                               
15323 +
15324                                 /* we don't need the client socket */
15325                                 for (i = 3; i < 256; i++) {
15326                                         close(i);
15327                                 }
15328 -                               
15329 -                               /* exec the log-process (skip the | ) 
15330 -                                * 
15331 +
15332 +                               /* exec the log-process (skip the | )
15333 +                                *
15334                                  */
15335 -                               
15336 +
15337                                 execl("/bin/sh", "sh", "-c", s->access_logfile->ptr + 1, NULL);
15338  
15339 -                               log_error_write(srv, __FILE__, __LINE__, "sss", 
15340 -                                               "spawning log-process failed: ", strerror(errno), 
15341 +                               log_error_write(srv, __FILE__, __LINE__, "sss",
15342 +                                               "spawning log-process failed: ", strerror(errno),
15343                                                 s->access_logfile->ptr + 1);
15344 -                               
15345 +
15346                                 exit(-1);
15347                                 break;
15348                         case -1:
15349 @@ -500,27 +500,28 @@
15350                                 break;
15351                         default:
15352                                 close(to_log_fds[0]);
15353 -                               
15354 +
15355                                 s->log_access_fd = to_log_fds[1];
15356 -                               
15357 +
15358                                 break;
15359                         }
15360  #else
15361                         return -1;
15362  #endif
15363 -               } else if (-1 == (s->log_access_fd = 
15364 +               } else if (-1 == (s->log_access_fd =
15365                                   open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
15366 -                       
15367 -                       log_error_write(srv, __FILE__, __LINE__, "ssb", 
15368 -                                       "opening access-log failed:", 
15369 +
15370 +                       log_error_write(srv, __FILE__, __LINE__, "ssb",
15371 +                                       "opening access-log failed:",
15372                                         strerror(errno), s->access_logfile);
15373 -                       
15374 +
15375                         return HANDLER_ERROR;
15376                 }
15377 +#ifndef _WIN32
15378                 fcntl(s->log_access_fd, F_SETFD, FD_CLOEXEC);
15379 -       
15380 +#endif
15381         }
15382 -       
15383 +
15384         return HANDLER_GO_ON;
15385  }
15386  
15387 @@ -529,7 +530,7 @@
15388         size_t i;
15389  
15390         if (!p->config_storage) return HANDLER_GO_ON;
15391 -               
15392 +
15393         for (i = 0; i < srv->config_context->used; i++) {
15394                 plugin_config *s = p->config_storage[i];
15395  
15396 @@ -544,90 +545,87 @@
15397                         } else if (s->log_access_fd != -1) {
15398                                 write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
15399                         }
15400 -                       
15401 +
15402                         buffer_reset(s->access_logbuffer);
15403                 }
15404 -               
15405 +
15406                 if (s->use_syslog == 0 &&
15407                     !buffer_is_empty(s->access_logfile) &&
15408                     s->access_logfile->ptr[0] != '|') {
15409 -                       
15410 +
15411                         close(s->log_access_fd);
15412 -                       
15413 -                       if (-1 == (s->log_access_fd = 
15414 +
15415 +                       if (-1 == (s->log_access_fd =
15416                                    open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
15417 -                               
15418 +
15419                                 log_error_write(srv, __FILE__, __LINE__, "ss", "cycling access-log failed:", strerror(errno));
15420 -                               
15421 +
15422                                 return HANDLER_ERROR;
15423                         }
15424                 }
15425         }
15426 -       
15427 +
15428         return HANDLER_GO_ON;
15429  }
15430  
15431 -#define PATCH(x) \
15432 -       p->conf.x = s->x;
15433  static int mod_accesslog_patch_connection(server *srv, connection *con, plugin_data *p) {
15434         size_t i, j;
15435         plugin_config *s = p->config_storage[0];
15436 -       
15437 -       PATCH(access_logfile);
15438 -       PATCH(format);
15439 -       PATCH(log_access_fd);
15440 -       PATCH(last_generated_accesslog_ts_ptr);
15441 -       PATCH(access_logbuffer);
15442 -       PATCH(ts_accesslog_str);
15443 -       PATCH(parsed_format);
15444 -       PATCH(use_syslog);
15445 -       
15446 +
15447 +       PATCH_OPTION(access_logfile);
15448 +       PATCH_OPTION(format);
15449 +       PATCH_OPTION(log_access_fd);
15450 +       PATCH_OPTION(last_generated_accesslog_ts_ptr);
15451 +       PATCH_OPTION(access_logbuffer);
15452 +       PATCH_OPTION(ts_accesslog_str);
15453 +       PATCH_OPTION(parsed_format);
15454 +       PATCH_OPTION(use_syslog);
15455 +
15456         /* skip the first, the global context */
15457         for (i = 1; i < srv->config_context->used; i++) {
15458                 data_config *dc = (data_config *)srv->config_context->data[i];
15459                 s = p->config_storage[i];
15460 -               
15461 +
15462                 /* condition didn't match */
15463                 if (!config_check_cond(srv, con, dc)) continue;
15464 -               
15465 +
15466                 /* merge config */
15467                 for (j = 0; j < dc->value->used; j++) {
15468                         data_unset *du = dc->value->data[j];
15469 -                       
15470 +
15471                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.filename"))) {
15472 -                               PATCH(access_logfile);
15473 -                               PATCH(log_access_fd);
15474 -                               PATCH(last_generated_accesslog_ts_ptr);
15475 -                               PATCH(access_logbuffer);
15476 -                               PATCH(ts_accesslog_str);
15477 +                               PATCH_OPTION(access_logfile);
15478 +                               PATCH_OPTION(log_access_fd);
15479 +                               PATCH_OPTION(last_generated_accesslog_ts_ptr);
15480 +                               PATCH_OPTION(access_logbuffer);
15481 +                               PATCH_OPTION(ts_accesslog_str);
15482                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.format"))) {
15483 -                               PATCH(format);
15484 -                               PATCH(parsed_format);
15485 +                               PATCH_OPTION(format);
15486 +                               PATCH_OPTION(parsed_format);
15487                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.use-syslog"))) {
15488 -                               PATCH(use_syslog);
15489 +                               PATCH_OPTION(use_syslog);
15490                         }
15491                 }
15492         }
15493 -       
15494 +
15495         return 0;
15496  }
15497 -#undef PATCH
15498  
15499  REQUESTDONE_FUNC(log_access_write) {
15500         plugin_data *p = p_d;
15501         buffer *b;
15502         size_t j;
15503 -       
15504 +
15505         int newts = 0;
15506         data_string *ds;
15507 -       
15508 +
15509         mod_accesslog_patch_connection(srv, con, p);
15510 -       
15511 +
15512         b = p->conf.access_logbuffer;
15513         if (b->used == 0) {
15514                 buffer_copy_string(b, "");
15515         }
15516 -       
15517 +
15518         for (j = 0; j < p->conf.parsed_format->used; j++) {
15519                 switch(p->conf.parsed_format->ptr[j]->type) {
15520                 case FIELD_STRING:
15521 @@ -636,14 +634,14 @@
15522                 case FIELD_FORMAT:
15523                         switch(p->conf.parsed_format->ptr[j]->field) {
15524                         case FORMAT_TIMESTAMP:
15525 -                               
15526 +
15527                                 /* cache the generated timestamp */
15528                                 if (srv->cur_ts != *(p->conf.last_generated_accesslog_ts_ptr)) {
15529                                         struct tm tm;
15530  #if defined(HAVE_STRUCT_TM_GMTOFF)
15531                                         long scd, hrs, min;
15532  #endif
15533 -               
15534 +
15535                                         buffer_prepare_copy(p->conf.ts_accesslog_str, 255);
15536  #if defined(HAVE_STRUCT_TM_GMTOFF)
15537  # ifdef HAVE_LOCALTIME_R
15538 @@ -653,17 +651,17 @@
15539                                         strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, "[%d/%b/%Y:%H:%M:%S ", localtime_r(&(srv->cur_ts)));
15540  # endif
15541                                         p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
15542 -                                       
15543 +
15544                                         buffer_append_string(p->conf.ts_accesslog_str, tm.tm_gmtoff >= 0 ? "+" : "-");
15545 -                                       
15546 +
15547                                         scd = abs(tm.tm_gmtoff);
15548                                         hrs = scd / 3600;
15549                                         min = (scd % 3600) / 60;
15550 -                                       
15551 +
15552                                         /* hours */
15553                                         if (hrs < 10) buffer_append_string(p->conf.ts_accesslog_str, "0");
15554                                         buffer_append_long(p->conf.ts_accesslog_str, hrs);
15555 -                                       
15556 +
15557                                         if (min < 10) buffer_append_string(p->conf.ts_accesslog_str, "0");
15558                                         buffer_append_long(p->conf.ts_accesslog_str, min);
15559                                         BUFFER_APPEND_STRING_CONST(p->conf.ts_accesslog_str, "]");
15560 @@ -676,20 +674,20 @@
15561  #endif
15562                                         p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
15563  #endif
15564 -                                       
15565 +
15566                                         *(p->conf.last_generated_accesslog_ts_ptr) = srv->cur_ts;
15567                                         newts = 1;
15568                                 }
15569 -                               
15570 +
15571                                 buffer_append_string_buffer(b, p->conf.ts_accesslog_str);
15572 -                               
15573 +
15574                                 break;
15575                         case FORMAT_REMOTE_HOST:
15576 -       
15577 +
15578                                 /* handle inet_ntop cache */
15579 -       
15580 +
15581                                 buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
15582 -                               
15583 +
15584                                 break;
15585                         case FORMAT_REMOTE_IDENT:
15586                                 /* ident */
15587 @@ -710,10 +708,10 @@
15588                         case FORMAT_STATUS:
15589                                 buffer_append_long(b, con->http_status);
15590                                 break;
15591 -       
15592 +
15593                         case FORMAT_BYTES_OUT_NO_HEADER:
15594                                 if (con->bytes_written > 0) {
15595 -                                       buffer_append_off_t(b, 
15596 +                                       buffer_append_off_t(b,
15597                                                             con->bytes_written - con->bytes_header <= 0 ? 0 : con->bytes_written - con->bytes_header);
15598                                 } else {
15599                                         BUFFER_APPEND_STRING_CONST(b, "-");
15600 @@ -772,7 +770,7 @@
15601                                 }
15602                                 break;
15603                         case FORMAT_REQUEST_PROTOCOL:
15604 -                               buffer_append_string(b, 
15605 +                               buffer_append_string(b,
15606                                                      con->request.http_version == HTTP_VERSION_1_1 ? "HTTP/1.1" : "HTTP/1.0");
15607                                 break;
15608                         case FORMAT_REQUEST_METHOD:
15609 @@ -801,7 +799,7 @@
15610                                  { 'D', FORMAT_TIME_USED_MS },
15611                                  { 'e', FORMAT_ENV },
15612                                  */
15613 -                               
15614 +
15615                                 break;
15616                         }
15617                         break;
15618 @@ -809,7 +807,7 @@
15619                         break;
15620                 }
15621         }
15622 -       
15623 +
15624         BUFFER_APPEND_STRING_CONST(b, "\n");
15625  
15626         if (p->conf.use_syslog ||  /* syslog doesn't cache */
15627 @@ -828,7 +826,7 @@
15628                 }
15629                 buffer_reset(b);
15630         }
15631 -       
15632 +
15633         return HANDLER_GO_ON;
15634  }
15635  
15636 @@ -836,15 +834,15 @@
15637  int mod_accesslog_plugin_init(plugin *p) {
15638         p->version     = LIGHTTPD_VERSION_ID;
15639         p->name        = buffer_init_string("accesslog");
15640 -       
15641 +
15642         p->init        = mod_accesslog_init;
15643         p->set_defaults= log_access_open;
15644         p->cleanup     = mod_accesslog_free;
15645 -       
15646 +
15647         p->handle_request_done  = log_access_write;
15648         p->handle_sighup        = log_access_cycle;
15649 -       
15650 +
15651         p->data        = NULL;
15652 -       
15653 +
15654         return 0;
15655  }
15656 --- ../lighttpd-1.4.11/src/mod_alias.c  2006-03-01 23:18:51.000000000 +0200
15657 +++ lighttpd-1.4.12/src/mod_alias.c     2006-07-16 00:26:03.000000000 +0300
15658 @@ -8,6 +8,7 @@
15659  #include "buffer.h"
15660  
15661  #include "plugin.h"
15662 +#include "sys-strings.h"
15663  
15664  /* plugin config for all request/connections */
15665  typedef struct {
15666 @@ -16,44 +17,44 @@
15667  
15668  typedef struct {
15669         PLUGIN_DATA;
15670 -       
15671 +
15672         plugin_config **config_storage;
15673 -       
15674 -       plugin_config conf; 
15675 +
15676 +       plugin_config conf;
15677  } plugin_data;
15678  
15679  /* init the plugin data */
15680  INIT_FUNC(mod_alias_init) {
15681         plugin_data *p;
15682 -       
15683 +
15684         p = calloc(1, sizeof(*p));
15685 -       
15686 -       
15687 -       
15688 +
15689 +
15690 +
15691         return p;
15692  }
15693  
15694  /* detroy the plugin data */
15695  FREE_FUNC(mod_alias_free) {
15696         plugin_data *p = p_d;
15697 -       
15698 +
15699         if (!p) return HANDLER_GO_ON;
15700 -       
15701 +
15702         if (p->config_storage) {
15703                 size_t i;
15704 -               
15705 +
15706                 for (i = 0; i < srv->config_context->used; i++) {
15707                         plugin_config *s = p->config_storage[i];
15708 -                       
15709 +
15710                         array_free(s->alias);
15711 -                       
15712 +
15713                         free(s);
15714                 }
15715                 free(p->config_storage);
15716         }
15717 -       
15718 +
15719         free(p);
15720 -       
15721 +
15722         return HANDLER_GO_ON;
15723  }
15724  
15725 @@ -62,25 +63,25 @@
15726  SETDEFAULTS_FUNC(mod_alias_set_defaults) {
15727         plugin_data *p = p_d;
15728         size_t i = 0;
15729 -       
15730 -       config_values_t cv[] = { 
15731 +
15732 +       config_values_t cv[] = {
15733                 { "alias.url",                  NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
15734                 { NULL,                         NULL, T_CONFIG_UNSET,  T_CONFIG_SCOPE_UNSET }
15735         };
15736 -       
15737 +
15738         if (!p) return HANDLER_ERROR;
15739 -       
15740 +
15741         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
15742 -       
15743 +
15744         for (i = 0; i < srv->config_context->used; i++) {
15745                 plugin_config *s;
15746 -               
15747 +
15748                 s = calloc(1, sizeof(plugin_config));
15749 -               s->alias = array_init();        
15750 +               s->alias = array_init();
15751                 cv[0].destination = s->alias;
15752 -               
15753 +
15754                 p->config_storage[i] = s;
15755 -               
15756 +
15757                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
15758                         return HANDLER_ERROR;
15759                 }
15760 @@ -110,76 +111,73 @@
15761                         }
15762                 }
15763         }
15764 -       
15765 +
15766         return HANDLER_GO_ON;
15767  }
15768  
15769 -#define PATCH(x) \
15770 -       p->conf.x = s->x;
15771  static int mod_alias_patch_connection(server *srv, connection *con, plugin_data *p) {
15772         size_t i, j;
15773         plugin_config *s = p->config_storage[0];
15774 -       
15775 -       PATCH(alias);
15776 -       
15777 +
15778 +       PATCH_OPTION(alias);
15779 +
15780         /* skip the first, the global context */
15781         for (i = 1; i < srv->config_context->used; i++) {
15782                 data_config *dc = (data_config *)srv->config_context->data[i];
15783                 s = p->config_storage[i];
15784 -               
15785 +
15786                 /* condition didn't match */
15787                 if (!config_check_cond(srv, con, dc)) continue;
15788 -               
15789 +
15790                 /* merge config */
15791                 for (j = 0; j < dc->value->used; j++) {
15792                         data_unset *du = dc->value->data[j];
15793 -                       
15794 +
15795                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("alias.url"))) {
15796 -                               PATCH(alias);
15797 +                               PATCH_OPTION(alias);
15798                         }
15799                 }
15800         }
15801 -       
15802 +
15803         return 0;
15804  }
15805 -#undef PATCH
15806  
15807  PHYSICALPATH_FUNC(mod_alias_physical_handler) {
15808         plugin_data *p = p_d;
15809         int uri_len, basedir_len;
15810         char *uri_ptr;
15811         size_t k;
15812 -       
15813 +
15814         if (con->physical.path->used == 0) return HANDLER_GO_ON;
15815 -       
15816 +
15817         mod_alias_patch_connection(srv, con, p);
15818 -       
15819 +
15820         /* not to include the tailing slash */
15821         basedir_len = (con->physical.basedir->used - 1) - 1;
15822         uri_len = con->physical.path->used - 1 - basedir_len;
15823         uri_ptr = con->physical.path->ptr + basedir_len;
15824 -       
15825 +
15826         for (k = 0; k < p->conf.alias->used; k++) {
15827                 data_string *ds = (data_string *)p->conf.alias->data[k];
15828                 int alias_len = ds->key->used - 1;
15829 -               
15830 +
15831                 if (alias_len > uri_len) continue;
15832                 if (ds->key->used == 0) continue;
15833 -               
15834 +
15835                 if (0 == (con->conf.force_lowercase_filenames ?
15836                                         strncasecmp(uri_ptr, ds->key->ptr, alias_len) :
15837                                         strncmp(uri_ptr, ds->key->ptr, alias_len))) {
15838                         /* matched */
15839 -                       
15840 +
15841                         buffer_copy_string_buffer(con->physical.basedir, ds->value);
15842                         buffer_copy_string_buffer(srv->tmp_buf, ds->value);
15843                         buffer_append_string(srv->tmp_buf, uri_ptr + alias_len);
15844                         buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
15845 -                       
15846 +
15847                         return HANDLER_GO_ON;
15848                 }
15849         }
15850 -       
15851 +
15852         /* not found */
15853         return HANDLER_GO_ON;
15854  }
15855 @@ -189,13 +187,13 @@
15856  int mod_alias_plugin_init(plugin *p) {
15857         p->version     = LIGHTTPD_VERSION_ID;
15858         p->name        = buffer_init_string("alias");
15859 -       
15860 +
15861         p->init           = mod_alias_init;
15862         p->handle_physical= mod_alias_physical_handler;
15863         p->set_defaults   = mod_alias_set_defaults;
15864         p->cleanup        = mod_alias_free;
15865 -       
15866 +
15867         p->data        = NULL;
15868 -       
15869 +
15870         return 0;
15871  }
15872 --- ../lighttpd-1.4.11/src/mod_auth.c   2006-02-15 20:01:31.000000000 +0200
15873 +++ lighttpd-1.4.12/src/mod_auth.c      2006-07-18 13:03:40.000000000 +0300
15874 @@ -5,168 +5,167 @@
15875  #include <string.h>
15876  #include <errno.h>
15877  #include <fcntl.h>
15878 -#include <unistd.h>
15879  
15880  #include "plugin.h"
15881  #include "http_auth.h"
15882  #include "log.h"
15883  #include "response.h"
15884  
15885 +#include "sys-strings.h"
15886 +#include "sys-files.h"
15887 +
15888  handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s);
15889  
15890  
15891  /**
15892   * the basic and digest auth framework
15893 - * 
15894 + *
15895   * - config handling
15896   * - protocol handling
15897 - * 
15898 - * http_auth.c 
15899 - * http_auth_digest.c 
15900 - * 
15901 + *
15902 + * http_auth.c
15903 + * http_auth_digest.c
15904 + *
15905   * do the real work
15906   */
15907  
15908  INIT_FUNC(mod_auth_init) {
15909         mod_auth_plugin_data *p;
15910 -       
15911 +
15912         p = calloc(1, sizeof(*p));
15913 -       
15914 +
15915         p->tmp_buf = buffer_init();
15916 -       
15917 +
15918         p->auth_user = buffer_init();
15919  #ifdef USE_LDAP
15920         p->ldap_filter = buffer_init();
15921  #endif
15922 -       
15923 +
15924         return p;
15925  }
15926  
15927  FREE_FUNC(mod_auth_free) {
15928         mod_auth_plugin_data *p = p_d;
15929 -       
15930 +
15931         UNUSED(srv);
15932  
15933         if (!p) return HANDLER_GO_ON;
15934 -       
15935 +
15936         buffer_free(p->tmp_buf);
15937         buffer_free(p->auth_user);
15938  #ifdef USE_LDAP
15939         buffer_free(p->ldap_filter);
15940  #endif
15941 -       
15942 +
15943         if (p->config_storage) {
15944                 size_t i;
15945                 for (i = 0; i < srv->config_context->used; i++) {
15946                         mod_auth_plugin_config *s = p->config_storage[i];
15947 -                       
15948 +
15949                         if (!s) continue;
15950 -                       
15951 +
15952                         array_free(s->auth_require);
15953                         buffer_free(s->auth_plain_groupfile);
15954                         buffer_free(s->auth_plain_userfile);
15955                         buffer_free(s->auth_htdigest_userfile);
15956                         buffer_free(s->auth_htpasswd_userfile);
15957                         buffer_free(s->auth_backend_conf);
15958 -                       
15959 +
15960                         buffer_free(s->auth_ldap_hostname);
15961                         buffer_free(s->auth_ldap_basedn);
15962                         buffer_free(s->auth_ldap_binddn);
15963                         buffer_free(s->auth_ldap_bindpw);
15964                         buffer_free(s->auth_ldap_filter);
15965                         buffer_free(s->auth_ldap_cafile);
15966 -                       
15967 +
15968  #ifdef USE_LDAP
15969                         buffer_free(s->ldap_filter_pre);
15970                         buffer_free(s->ldap_filter_post);
15971 -                       
15972 +
15973                         if (s->ldap) ldap_unbind_s(s->ldap);
15974  #endif
15975 -                       
15976 +
15977                         free(s);
15978                 }
15979                 free(p->config_storage);
15980         }
15981 -       
15982 +
15983         free(p);
15984 -       
15985 +
15986         return HANDLER_GO_ON;
15987  }
15988  
15989 -#define PATCH(x) \
15990 -       p->conf.x = s->x;
15991  static int mod_auth_patch_connection(server *srv, connection *con, mod_auth_plugin_data *p) {
15992         size_t i, j;
15993         mod_auth_plugin_config *s = p->config_storage[0];
15994  
15995 -       PATCH(auth_backend);
15996 -       PATCH(auth_plain_groupfile);
15997 -       PATCH(auth_plain_userfile);
15998 -       PATCH(auth_htdigest_userfile);
15999 -       PATCH(auth_htpasswd_userfile);
16000 -       PATCH(auth_require);
16001 -       PATCH(auth_debug);
16002 -       PATCH(auth_ldap_hostname);
16003 -       PATCH(auth_ldap_basedn);
16004 -       PATCH(auth_ldap_binddn);
16005 -       PATCH(auth_ldap_bindpw);
16006 -       PATCH(auth_ldap_filter);
16007 -       PATCH(auth_ldap_cafile);
16008 -       PATCH(auth_ldap_starttls);
16009 +       PATCH_OPTION(auth_backend);
16010 +       PATCH_OPTION(auth_plain_groupfile);
16011 +       PATCH_OPTION(auth_plain_userfile);
16012 +       PATCH_OPTION(auth_htdigest_userfile);
16013 +       PATCH_OPTION(auth_htpasswd_userfile);
16014 +       PATCH_OPTION(auth_require);
16015 +       PATCH_OPTION(auth_debug);
16016 +       PATCH_OPTION(auth_ldap_hostname);
16017 +       PATCH_OPTION(auth_ldap_basedn);
16018 +       PATCH_OPTION(auth_ldap_binddn);
16019 +       PATCH_OPTION(auth_ldap_bindpw);
16020 +       PATCH_OPTION(auth_ldap_filter);
16021 +       PATCH_OPTION(auth_ldap_cafile);
16022 +       PATCH_OPTION(auth_ldap_starttls);
16023  #ifdef USE_LDAP
16024 -       PATCH(ldap);
16025 -       PATCH(ldap_filter_pre);
16026 -       PATCH(ldap_filter_post);
16027 +       PATCH_OPTION(ldap);
16028 +       PATCH_OPTION(ldap_filter_pre);
16029 +       PATCH_OPTION(ldap_filter_post);
16030  #endif
16031 -       
16032 +
16033         /* skip the first, the global context */
16034         for (i = 1; i < srv->config_context->used; i++) {
16035                 data_config *dc = (data_config *)srv->config_context->data[i];
16036                 s = p->config_storage[i];
16037 -               
16038 +
16039                 /* condition didn't match */
16040                 if (!config_check_cond(srv, con, dc)) continue;
16041 -               
16042 +
16043                 /* merge config */
16044                 for (j = 0; j < dc->value->used; j++) {
16045                         data_unset *du = dc->value->data[j];
16046 -                       
16047 +
16048                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend"))) {
16049 -                               PATCH(auth_backend);
16050 +                               PATCH_OPTION(auth_backend);
16051                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.groupfile"))) {
16052 -                               PATCH(auth_plain_groupfile);
16053 +                               PATCH_OPTION(auth_plain_groupfile);
16054                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.userfile"))) {
16055 -                               PATCH(auth_plain_userfile);
16056 +                               PATCH_OPTION(auth_plain_userfile);
16057                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htdigest.userfile"))) {
16058 -                               PATCH(auth_htdigest_userfile);
16059 +                               PATCH_OPTION(auth_htdigest_userfile);
16060                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htpasswd.userfile"))) {
16061 -                               PATCH(auth_htpasswd_userfile);
16062 +                               PATCH_OPTION(auth_htpasswd_userfile);
16063                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.require"))) {
16064 -                               PATCH(auth_require);
16065 +                               PATCH_OPTION(auth_require);
16066                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.debug"))) {
16067 -                               PATCH(auth_debug);
16068 +                               PATCH_OPTION(auth_debug);
16069                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.hostname"))) {
16070 -                               PATCH(auth_ldap_hostname);
16071 +                               PATCH_OPTION(auth_ldap_hostname);
16072  #ifdef USE_LDAP
16073 -                               PATCH(ldap);
16074 -                               PATCH(ldap_filter_pre);
16075 -                               PATCH(ldap_filter_post);
16076 +                               PATCH_OPTION(ldap);
16077 +                               PATCH_OPTION(ldap_filter_pre);
16078 +                               PATCH_OPTION(ldap_filter_post);
16079  #endif
16080                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.base-dn"))) {
16081 -                               PATCH(auth_ldap_basedn);
16082 +                               PATCH_OPTION(auth_ldap_basedn);
16083                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.filter"))) {
16084 -                               PATCH(auth_ldap_filter);
16085 +                               PATCH_OPTION(auth_ldap_filter);
16086                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.ca-file"))) {
16087 -                               PATCH(auth_ldap_cafile);
16088 +                               PATCH_OPTION(auth_ldap_cafile);
16089                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.starttls"))) {
16090 -                               PATCH(auth_ldap_starttls);
16091 +                               PATCH_OPTION(auth_ldap_starttls);
16092                         }
16093                 }
16094         }
16095 -       
16096 +
16097         return 0;
16098  }
16099 -#undef PATCH
16100  
16101  static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
16102         size_t k;
16103 @@ -175,22 +174,22 @@
16104         data_string *ds;
16105         mod_auth_plugin_data *p = p_d;
16106         array *req;
16107 -       
16108 +
16109         /* select the right config */
16110         mod_auth_patch_connection(srv, con, p);
16111 -       
16112 +
16113         if (p->conf.auth_require == NULL) return HANDLER_GO_ON;
16114 -       
16115 +
16116         /*
16117          * AUTH
16118 -        *  
16119 +        *
16120          */
16121 -       
16122 +
16123         /* do we have to ask for auth ? */
16124 -       
16125 +
16126         auth_required = 0;
16127         auth_satisfied = 0;
16128 -       
16129 +
16130         /* search auth-directives for path */
16131         for (k = 0; k < p->conf.auth_require->used; k++) {
16132                 buffer *req = p->conf.auth_require->data[k]->key;
16133 @@ -212,76 +211,76 @@
16134                         }
16135                 }
16136         }
16137 -       
16138 +
16139         /* nothing to do for us */
16140         if (auth_required == 0) return HANDLER_GO_ON;
16141 -       
16142 +
16143         req = ((data_array *)(p->conf.auth_require->data[k]))->value;
16144 -       
16145 +
16146         /* try to get Authorization-header */
16147 -               
16148 +
16149         if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Authorization"))) {
16150                 http_authorization = ds->value->ptr;
16151         }
16152 -       
16153 +
16154         if (ds && ds->value && ds->value->used) {
16155                 char *auth_realm;
16156                 data_string *method;
16157 -               
16158 +
16159                 method = (data_string *)array_get_element(req, "method");
16160 -               
16161 +
16162                 /* parse auth-header */
16163                 if (NULL != (auth_realm = strchr(http_authorization, ' '))) {
16164                         int auth_type_len = auth_realm - http_authorization;
16165 -                       
16166 +
16167                         if ((auth_type_len == 5) &&
16168                             (0 == strncmp(http_authorization, "Basic", auth_type_len))) {
16169 -                               
16170 -                               if (0 == strcmp(method->value->ptr, "basic")) {
16171 +
16172 +                               if (buffer_is_equal_string(method->value, CONST_STR_LEN("basic"))) {
16173                                         auth_satisfied = http_auth_basic_check(srv, con, p, req, con->uri.path, auth_realm+1);
16174                                 }
16175                         } else if ((auth_type_len == 6) &&
16176                                    (0 == strncmp(http_authorization, "Digest", auth_type_len))) {
16177 -                               if (0 == strcmp(method->value->ptr, "digest")) {
16178 +                               if (buffer_is_equal_string(method->value, CONST_STR_LEN("digest"))) {
16179                                         if (-1 == (auth_satisfied = http_auth_digest_check(srv, con, p, req, con->uri.path, auth_realm+1))) {
16180                                                 con->http_status = 400;
16181 -                                               
16182 +
16183                                                 /* a field was missing */
16184 -                                               
16185 +
16186                                                 return HANDLER_FINISHED;
16187                                         }
16188                                 }
16189                         } else {
16190 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
16191 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
16192                                                 "unknown authentification type:",
16193                                                 http_authorization);
16194                         }
16195                 }
16196         }
16197 -       
16198 +
16199         if (!auth_satisfied) {
16200                 data_string *method, *realm;
16201                 method = (data_string *)array_get_element(req, "method");
16202                 realm = (data_string *)array_get_element(req, "realm");
16203 -               
16204 +
16205                 con->http_status = 401;
16206 -                       
16207 -               if (0 == strcmp(method->value->ptr, "basic")) {
16208 +
16209 +               if (buffer_is_equal_string(method->value, CONST_STR_LEN("basic"))) {
16210                         buffer_copy_string(p->tmp_buf, "Basic realm=\"");
16211                         buffer_append_string_buffer(p->tmp_buf, realm->value);
16212                         buffer_append_string(p->tmp_buf, "\"");
16213 -                       
16214 +
16215                         response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
16216 -               } else if (0 == strcmp(method->value->ptr, "digest")) {
16217 +               } else if (buffer_is_equal_string(method->value, CONST_STR_LEN("digest"))) {
16218                         char hh[33];
16219                         http_auth_digest_generate_nonce(srv, p, srv->tmp_buf, hh);
16220 -                       
16221 +
16222                         buffer_copy_string(p->tmp_buf, "Digest realm=\"");
16223                         buffer_append_string_buffer(p->tmp_buf, realm->value);
16224                         buffer_append_string(p->tmp_buf, "\", nonce=\"");
16225                         buffer_append_string(p->tmp_buf, hh);
16226                         buffer_append_string(p->tmp_buf, "\", qop=\"auth\"");
16227 -                       
16228 +
16229                         response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
16230                 } else {
16231                         /* evil */
16232 @@ -289,18 +288,18 @@
16233                 return HANDLER_FINISHED;
16234         } else {
16235                 /* the REMOTE_USER header */
16236 -               
16237 +
16238                 buffer_copy_string_buffer(con->authed_user, p->auth_user);
16239         }
16240 -       
16241 +
16242         return HANDLER_GO_ON;
16243  }
16244  
16245  SETDEFAULTS_FUNC(mod_auth_set_defaults) {
16246         mod_auth_plugin_data *p = p_d;
16247         size_t i;
16248 -       
16249 -       config_values_t cv[] = { 
16250 +
16251 +       config_values_t cv[] = {
16252                 { "auth.backend",                   NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
16253                 { "auth.backend.plain.groupfile",   NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
16254                 { "auth.backend.plain.userfile",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
16255 @@ -317,7 +316,7 @@
16256                 { "auth.debug",                     NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },  /* 13 */
16257                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
16258         };
16259 -       
16260 +
16261         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
16262  
16263         for (i = 0; i < srv->config_context->used; i++) {
16264 @@ -325,14 +324,14 @@
16265                 size_t n;
16266                 data_array *da;
16267                 array *ca;
16268 -               
16269 +
16270                 s = calloc(1, sizeof(mod_auth_plugin_config));
16271                 s->auth_plain_groupfile = buffer_init();
16272                 s->auth_plain_userfile = buffer_init();
16273                 s->auth_htdigest_userfile = buffer_init();
16274                 s->auth_htpasswd_userfile = buffer_init();
16275                 s->auth_backend_conf = buffer_init();
16276 -               
16277 +
16278                 s->auth_ldap_hostname = buffer_init();
16279                 s->auth_ldap_basedn = buffer_init();
16280                 s->auth_ldap_binddn = buffer_init();
16281 @@ -341,15 +340,15 @@
16282                 s->auth_ldap_cafile = buffer_init();
16283                 s->auth_ldap_starttls = 0;
16284                 s->auth_debug = 0;
16285 -               
16286 +
16287                 s->auth_require = array_init();
16288 -               
16289 +
16290  #ifdef USE_LDAP
16291                 s->ldap_filter_pre = buffer_init();
16292                 s->ldap_filter_post = buffer_init();
16293                 s->ldap = NULL;
16294  #endif
16295 -       
16296 +
16297                 cv[0].destination = s->auth_backend_conf;
16298                 cv[1].destination = s->auth_plain_groupfile;
16299                 cv[2].destination = s->auth_plain_userfile;
16300 @@ -364,146 +363,148 @@
16301                 cv[11].destination = s->auth_htdigest_userfile;
16302                 cv[12].destination = s->auth_htpasswd_userfile;
16303                 cv[13].destination = &(s->auth_debug);
16304 -               
16305 +
16306                 p->config_storage[i] = s;
16307                 ca = ((data_config *)srv->config_context->data[i])->value;
16308 -               
16309 +
16310                 if (0 != config_insert_values_global(srv, ca, cv)) {
16311                         return HANDLER_ERROR;
16312                 }
16313 -               
16314 -               if (s->auth_backend_conf->used) {
16315 -                       if (0 == strcmp(s->auth_backend_conf->ptr, "htpasswd")) {
16316 +
16317 +               if (!buffer_is_empty(s->auth_backend_conf)) {
16318 +                       if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("htpasswd"))) {
16319                                 s->auth_backend = AUTH_BACKEND_HTPASSWD;
16320 -                       } else if (0 == strcmp(s->auth_backend_conf->ptr, "htdigest")) {
16321 +                       } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("htdigest"))) {
16322                                 s->auth_backend = AUTH_BACKEND_HTDIGEST;
16323 -                       } else if (0 == strcmp(s->auth_backend_conf->ptr, "plain")) {
16324 +                       } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("plain"))) {
16325                                 s->auth_backend = AUTH_BACKEND_PLAIN;
16326 -                       } else if (0 == strcmp(s->auth_backend_conf->ptr, "ldap")) {
16327 +                       } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("ldap"))) {
16328                                 s->auth_backend = AUTH_BACKEND_LDAP;
16329                         } else {
16330                                 log_error_write(srv, __FILE__, __LINE__, "sb", "auth.backend not supported:", s->auth_backend_conf);
16331 -                               
16332 +
16333                                 return HANDLER_ERROR;
16334                         }
16335                 }
16336  
16337                 /* no auth.require for this section */
16338                 if (NULL == (da = (data_array *)array_get_element(ca, "auth.require"))) continue;
16339 -               
16340 +
16341                 if (da->type != TYPE_ARRAY) continue;
16342 -               
16343 +
16344                 for (n = 0; n < da->value->used; n++) {
16345                         size_t m;
16346                         data_array *da_file = (data_array *)da->value->data[n];
16347 -                       const char *method, *realm, *require;
16348 -                       
16349 +                       buffer *method, *realm, *require;
16350 +
16351                         if (da->value->data[n]->type != TYPE_ARRAY) {
16352 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
16353 -                                               "auth.require should contain an array as in:", 
16354 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
16355 +                                               "auth.require should contain an array as in:",
16356                                                 "auth.require = ( \"...\" => ( ..., ...) )");
16357  
16358                                 return HANDLER_ERROR;
16359                         }
16360 -                                       
16361 +
16362                         method = realm = require = NULL;
16363 -                                       
16364 +
16365                         for (m = 0; m < da_file->value->used; m++) {
16366 -                               if (da_file->value->data[m]->type == TYPE_STRING) {
16367 -                                       if (0 == strcmp(da_file->value->data[m]->key->ptr, "method")) {
16368 -                                               method = ((data_string *)(da_file->value->data[m]))->value->ptr;
16369 -                                       } else if (0 == strcmp(da_file->value->data[m]->key->ptr, "realm")) {
16370 -                                               realm = ((data_string *)(da_file->value->data[m]))->value->ptr;
16371 -                                       } else if (0 == strcmp(da_file->value->data[m]->key->ptr, "require")) {
16372 -                                               require = ((data_string *)(da_file->value->data[m]))->value->ptr;
16373 -                                       } else {
16374 -                                               log_error_write(srv, __FILE__, __LINE__, "ssbs", 
16375 -                                                       "the field is unknown in:", 
16376 +                               data_string *ds_auth_req = (data_string *)da_file->value->data[m];
16377 +
16378 +                               if (ds_auth_req->type != TYPE_STRING) {
16379 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbs",
16380 +                                               "a string was expected for:",
16381 +                                               "auth.require = ( \"...\" => ( ..., -> \"",
16382 +                                               ds_auth_req->key,
16383 +                                               "\" <- => \"...\" ) )");
16384 +
16385 +                                       return HANDLER_ERROR;
16386 +                               }
16387 +
16388 +                               if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("method"))) {
16389 +                                       method = ds_auth_req->value;
16390 +                               } else if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("realm"))) {
16391 +                                       realm = ds_auth_req->value;
16392 +                               } else if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("require"))) {
16393 +                                       require = ds_auth_req->value;
16394 +                               } else {
16395 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbs",
16396 +                                                       "the field is unknown in:",
16397                                                         "auth.require = ( \"...\" => ( ..., -> \"",
16398                                                         da_file->value->data[m]->key,
16399                                                         "\" <- => \"...\" ) )");
16400  
16401 -                                               return HANDLER_ERROR;
16402 -                                       }
16403 -                               } else {
16404 -                                       log_error_write(srv, __FILE__, __LINE__, "ssbs", 
16405 -                                               "a string was expected for:", 
16406 -                                               "auth.require = ( \"...\" => ( ..., -> \"",
16407 -                                               da_file->value->data[m]->key,
16408 -                                               "\" <- => \"...\" ) )");
16409 -                                       
16410                                         return HANDLER_ERROR;
16411 +
16412                                 }
16413                         }
16414 -                                       
16415 +
16416                         if (method == NULL) {
16417 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
16418 -                                               "the require field is missing in:", 
16419 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
16420 +                                               "the require field is missing in:",
16421                                                 "auth.require = ( \"...\" => ( ..., \"method\" => \"...\" ) )");
16422                                 return HANDLER_ERROR;
16423 -                       } else {
16424 -                               if (0 != strcmp(method, "basic") &&
16425 -                                   0 != strcmp(method, "digest")) {
16426 -                                       log_error_write(srv, __FILE__, __LINE__, "ss",
16427 -                                                       "method has to be either \"basic\" or \"digest\" in",
16428 -                                                       "auth.require = ( \"...\" => ( ..., \"method\" => \"...\") )");
16429 -                                       return HANDLER_ERROR;
16430 -                               }
16431 +                       } 
16432 +                       if (!buffer_is_equal_string(method, CONST_STR_LEN("basic")) &&
16433 +                           !buffer_is_equal_string(method, CONST_STR_LEN("digest"))) {
16434 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
16435 +                                               "method has to be either \"basic\" or \"digest\" in",
16436 +                                               "auth.require = ( \"...\" => ( ..., \"method\" => \"...\") )");
16437 +                               return HANDLER_ERROR;
16438                         }
16439 -                       
16440 +
16441                         if (realm == NULL) {
16442 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
16443 -                                               "the require field is missing in:", 
16444 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
16445 +                                               "the require field is missing in:",
16446                                                 "auth.require = ( \"...\" => ( ..., \"realm\" => \"...\" ) )");
16447                                 return HANDLER_ERROR;
16448                         }
16449 -                       
16450 +
16451                         if (require == NULL) {
16452 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
16453 -                                               "the require field is missing in:", 
16454 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
16455 +                                               "the require field is missing in:",
16456                                                 "auth.require = ( \"...\" => ( ..., \"require\" => \"...\" ) )");
16457                                 return HANDLER_ERROR;
16458                         }
16459 -                       
16460 +
16461                         if (method && realm && require) {
16462                                 data_string *ds;
16463                                 data_array *a;
16464 -                               
16465 +
16466                                 a = data_array_init();
16467                                 buffer_copy_string_buffer(a->key, da_file->key);
16468 -                               
16469 +
16470                                 ds = data_string_init();
16471 -                               
16472 +
16473                                 buffer_copy_string(ds->key, "method");
16474 -                               buffer_copy_string(ds->value, method);
16475 -                               
16476 +                               buffer_copy_string_buffer(ds->value, method);
16477 +
16478                                 array_insert_unique(a->value, (data_unset *)ds);
16479 -                               
16480 +
16481                                 ds = data_string_init();
16482 -                               
16483 +
16484                                 buffer_copy_string(ds->key, "realm");
16485 -                               buffer_copy_string(ds->value, realm);
16486 -                               
16487 +                               buffer_copy_string_buffer(ds->value, realm);
16488 +
16489                                 array_insert_unique(a->value, (data_unset *)ds);
16490 -                               
16491 +
16492                                 ds = data_string_init();
16493 -                               
16494 +
16495                                 buffer_copy_string(ds->key, "require");
16496 -                               buffer_copy_string(ds->value, require);
16497 -                               
16498 +                               buffer_copy_string_buffer(ds->value, require);
16499 +
16500                                 array_insert_unique(a->value, (data_unset *)ds);
16501 -                               
16502 +
16503                                 array_insert_unique(s->auth_require, (data_unset *)a);
16504                         }
16505                 }
16506 -       
16507 +
16508                 switch(s->auth_backend) {
16509                 case AUTH_BACKEND_PLAIN:
16510                         if (s->auth_plain_userfile->used) {
16511                                 int fd;
16512                                 /* try to read */
16513                                 if (-1 == (fd = open(s->auth_plain_userfile->ptr, O_RDONLY))) {
16514 -                                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
16515 +                                       log_error_write(srv, __FILE__, __LINE__, "sbss",
16516                                                         "opening auth.backend.plain.userfile:", s->auth_plain_userfile,
16517                                                         "failed:", strerror(errno));
16518                                         return HANDLER_ERROR;
16519 @@ -516,7 +517,7 @@
16520                                 int fd;
16521                                 /* try to read */
16522                                 if (-1 == (fd = open(s->auth_htpasswd_userfile->ptr, O_RDONLY))) {
16523 -                                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
16524 +                                       log_error_write(srv, __FILE__, __LINE__, "sbss",
16525                                                         "opening auth.backend.htpasswd.userfile:", s->auth_htpasswd_userfile,
16526                                                         "failed:", strerror(errno));
16527                                         return HANDLER_ERROR;
16528 @@ -529,7 +530,7 @@
16529                                 int fd;
16530                                 /* try to read */
16531                                 if (-1 == (fd = open(s->auth_htdigest_userfile->ptr, O_RDONLY))) {
16532 -                                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
16533 +                                       log_error_write(srv, __FILE__, __LINE__, "sbss",
16534                                                         "opening auth.backend.htdigest.userfile:", s->auth_htdigest_userfile,
16535                                                         "failed:", strerror(errno));
16536                                         return HANDLER_ERROR;
16537 @@ -554,75 +555,75 @@
16538  handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s) {
16539  #ifdef USE_LDAP
16540                         int ret;
16541 -#if 0                  
16542 +#if 0
16543                         if (s->auth_ldap_basedn->used == 0) {
16544                                 log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.base-dn has to be set");
16545 -                               
16546 +
16547                                 return HANDLER_ERROR;
16548                         }
16549  #endif
16550 -                       
16551 +
16552                         if (s->auth_ldap_filter->used) {
16553                                 char *dollar;
16554 -                               
16555 +
16556                                 /* parse filter */
16557 -                       
16558 +
16559                                 if (NULL == (dollar = strchr(s->auth_ldap_filter->ptr, '$'))) {
16560                                         log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.filter is missing a replace-operator '$'");
16561 -                                       
16562 +
16563                                         return HANDLER_ERROR;
16564                                 }
16565 -                               
16566 +
16567                                 buffer_copy_string_len(s->ldap_filter_pre, s->auth_ldap_filter->ptr, dollar - s->auth_ldap_filter->ptr);
16568                                 buffer_copy_string(s->ldap_filter_post, dollar+1);
16569                         }
16570 -                       
16571 +
16572                         if (s->auth_ldap_hostname->used) {
16573                                 if (NULL == (s->ldap = ldap_init(s->auth_ldap_hostname->ptr, LDAP_PORT))) {
16574                                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno));
16575 -                                       
16576 +
16577                                         return HANDLER_ERROR;
16578                                 }
16579 -                               
16580 +
16581                                 ret = LDAP_VERSION3;
16582                                 if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(s->ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) {
16583                                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
16584 -                               
16585 +
16586                                         return HANDLER_ERROR;
16587                                 }
16588  
16589                                 if (s->auth_ldap_starttls) {
16590 -                                       /* if no CA file is given, it is ok, as we will use encryption 
16591 +                                       /* if no CA file is given, it is ok, as we will use encryption
16592                                          * if the server requires a CAfile it will tell us */
16593                                         if (!buffer_is_empty(s->auth_ldap_cafile)) {
16594 -                                               if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, 
16595 +                                               if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
16596                                                                                 s->auth_ldap_cafile->ptr))) {
16597 -                                                       log_error_write(srv, __FILE__, __LINE__, "ss", 
16598 +                                                       log_error_write(srv, __FILE__, __LINE__, "ss",
16599                                                                         "Loading CA certificate failed:", ldap_err2string(ret));
16600 -                                               
16601 +
16602                                                         return HANDLER_ERROR;
16603                                                 }
16604                                         }
16605 -       
16606 +
16607                                         if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(s->ldap, NULL,  NULL))) {
16608                                                 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
16609 -                                               
16610 +
16611                                                 return HANDLER_ERROR;
16612                                         }
16613                                 }
16614 -                               
16615 -                               
16616 +
16617 +
16618                                 /* 1. */
16619                                 if (s->auth_ldap_binddn->used) {
16620                                         if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, s->auth_ldap_binddn->ptr, s->auth_ldap_bindpw->ptr))) {
16621                                                 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
16622 -                                               
16623 +
16624                                                 return HANDLER_ERROR;
16625                                         }
16626                                 } else {
16627                                         if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, NULL, NULL))) {
16628                                                 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
16629 -                                               
16630 +
16631                                                 return HANDLER_ERROR;
16632                                         }
16633                                 }
16634 @@ -641,8 +642,8 @@
16635         p->set_defaults = mod_auth_set_defaults;
16636         p->handle_uri_clean = mod_auth_uri_handler;
16637         p->cleanup     = mod_auth_free;
16638 -       
16639 +
16640         p->data        = NULL;
16641 -       
16642 +
16643         return 0;
16644  }
16645 --- ../lighttpd-1.4.11/src/mod_cgi.c    2006-02-22 15:15:10.000000000 +0200
16646 +++ lighttpd-1.4.12/src/mod_cgi.c       2006-07-18 17:34:32.000000000 +0300
16647 @@ -1,21 +1,8 @@
16648  #include <sys/types.h>
16649 -#ifdef __WIN32
16650 -#include <winsock2.h>
16651 -#else
16652 -#include <sys/socket.h>
16653 -#include <sys/wait.h>
16654 -#include <sys/mman.h>
16655 -
16656 -#include <netinet/in.h>
16657 -
16658 -#include <arpa/inet.h>
16659 -#endif
16660  
16661 -#include <unistd.h>
16662  #include <errno.h>
16663  #include <stdlib.h>
16664  #include <string.h>
16665 -#include <fdevent.h>
16666  #include <signal.h>
16667  #include <ctype.h>
16668  #include <assert.h>
16669 @@ -29,8 +16,16 @@
16670  #include "connections.h"
16671  #include "joblist.h"
16672  #include "http_chunk.h"
16673 +#include "fdevent.h"
16674  
16675  #include "plugin.h"
16676 +#include "http_resp.h"
16677 +
16678 +#include "sys-files.h"
16679 +#include "sys-mmap.h"
16680 +#include "sys-socket.h"
16681 +#include "sys-strings.h"
16682 +#include "sys-process.h"
16683  
16684  #ifdef HAVE_SYS_FILIO_H
16685  # include <sys/filio.h>
16686 @@ -40,11 +35,12 @@
16687  
16688  typedef struct {
16689         char **ptr;
16690 -       
16691 +
16692         size_t size;
16693         size_t used;
16694  } char_array;
16695  
16696 +#define pid_t int
16697  typedef struct {
16698         pid_t *ptr;
16699         size_t used;
16700 @@ -58,57 +54,68 @@
16701  typedef struct {
16702         PLUGIN_DATA;
16703         buffer_pid_t cgi_pid;
16704 -       
16705 +
16706         buffer *tmp_buf;
16707 -       buffer *parse_response;
16708 -       
16709 +
16710 +       http_resp *resp;
16711 +
16712         plugin_config **config_storage;
16713 -       
16714 -       plugin_config conf; 
16715 +
16716 +       plugin_config conf;
16717  } plugin_data;
16718  
16719 +typedef enum {
16720 +       CGI_STATE_UNSET,
16721 +       CGI_STATE_CONNECTING,
16722 +       CGI_STATE_READ_RESPONSE_HEADER,
16723 +       CGI_STATE_READ_RESPONSE_CONTENT
16724 +} cgi_state_t;
16725 +
16726  typedef struct {
16727         pid_t pid;
16728 -       int fd;
16729 -       int fde_ndx; /* index into the fd-event buffer */
16730 -       
16731 -       connection *remote_conn;  /* dumb pointer */
16732 -       plugin_data *plugin_data; /* dumb pointer */
16733 -       
16734 -       buffer *response;
16735 -       buffer *response_header;
16736 -} handler_ctx;
16737  
16738 -static handler_ctx * cgi_handler_ctx_init() {
16739 -       handler_ctx *hctx = calloc(1, sizeof(*hctx));
16740 +       iosocket *sock;
16741  
16742 -       assert(hctx);
16743 -       
16744 -       hctx->response = buffer_init();
16745 -       hctx->response_header = buffer_init();
16746 -       
16747 -       return hctx;
16748 -}
16749 +       chunkqueue *rb;
16750 +       chunkqueue *wb;
16751  
16752 -static void cgi_handler_ctx_free(handler_ctx *hctx) {
16753 -       buffer_free(hctx->response);
16754 -       buffer_free(hctx->response_header);
16755 -       
16756 -       free(hctx);
16757 +       cgi_state_t state;
16758 +
16759 +       connection *remote_con;  /* dumb pointer */
16760 +} cgi_session;
16761 +
16762 +static cgi_session * cgi_session_init() {
16763 +       cgi_session *sess = calloc(1, sizeof(*sess));
16764 +       assert(sess);
16765 +
16766 +       sess->sock = iosocket_init();
16767 +       sess->wb = chunkqueue_init();
16768 +       sess->rb = chunkqueue_init();
16769 +
16770 +       return sess;
16771  }
16772  
16773 -enum {FDEVENT_HANDLED_UNSET, FDEVENT_HANDLED_FINISHED, FDEVENT_HANDLED_NOT_FINISHED, FDEVENT_HANDLED_ERROR};
16774 +static void cgi_session_free(cgi_session *sess) {
16775 +       if (!sess) return;
16776 +
16777 +       iosocket_free(sess->sock);
16778 +
16779 +       chunkqueue_free(sess->wb);
16780 +       chunkqueue_free(sess->rb);
16781 +
16782 +       free(sess);
16783 +}
16784  
16785  INIT_FUNC(mod_cgi_init) {
16786         plugin_data *p;
16787 -       
16788 +
16789         p = calloc(1, sizeof(*p));
16790  
16791         assert(p);
16792 -       
16793 +
16794         p->tmp_buf = buffer_init();
16795 -       p->parse_response = buffer_init();
16796 -       
16797 +       p->resp = http_response_init();
16798 +
16799         return p;
16800  }
16801  
16802 @@ -116,62 +123,62 @@
16803  FREE_FUNC(mod_cgi_free) {
16804         plugin_data *p = p_d;
16805         buffer_pid_t *r = &(p->cgi_pid);
16806 -       
16807 +
16808         UNUSED(srv);
16809 -       
16810 +
16811         if (p->config_storage) {
16812                 size_t i;
16813                 for (i = 0; i < srv->config_context->used; i++) {
16814                         plugin_config *s = p->config_storage[i];
16815 -                       
16816 +
16817                         array_free(s->cgi);
16818 -                       
16819 +
16820                         free(s);
16821                 }
16822                 free(p->config_storage);
16823         }
16824 -       
16825 +
16826  
16827         if (r->ptr) free(r->ptr);
16828 -       
16829 +
16830         buffer_free(p->tmp_buf);
16831 -       buffer_free(p->parse_response);
16832 -       
16833 +       http_response_free(p->resp);
16834 +
16835         free(p);
16836 -       
16837 +
16838         return HANDLER_GO_ON;
16839  }
16840  
16841  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
16842         plugin_data *p = p_d;
16843         size_t i = 0;
16844 -       
16845 -       config_values_t cv[] = { 
16846 +
16847 +       config_values_t cv[] = {
16848                 { "cgi.assign",                  NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
16849                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET}
16850         };
16851  
16852         if (!p) return HANDLER_ERROR;
16853 -       
16854 +
16855         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
16856 -       
16857 +
16858         for (i = 0; i < srv->config_context->used; i++) {
16859                 plugin_config *s;
16860 -               
16861 +
16862                 s = calloc(1, sizeof(plugin_config));
16863                 assert(s);
16864 -               
16865 +
16866                 s->cgi    = array_init();
16867 -               
16868 +
16869                 cv[0].destination = s->cgi;
16870 -               
16871 +
16872                 p->config_storage[i] = s;
16873 -       
16874 +
16875                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
16876                         return HANDLER_ERROR;
16877                 }
16878         }
16879 -       
16880 +
16881         return HANDLER_GO_ON;
16882  }
16883  
16884 @@ -180,13 +187,13 @@
16885         int m = -1;
16886         size_t i;
16887         buffer_pid_t *r = &(p->cgi_pid);
16888 -       
16889 +
16890         UNUSED(srv);
16891  
16892         for (i = 0; i < r->used; i++) {
16893                 if (r->ptr[i] > m) m = r->ptr[i];
16894         }
16895 -       
16896 +
16897         if (r->size == 0) {
16898                 r->size = 16;
16899                 r->ptr = malloc(sizeof(*r->ptr) * r->size);
16900 @@ -194,321 +201,179 @@
16901                 r->size += 16;
16902                 r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
16903         }
16904 -       
16905 +
16906         r->ptr[r->used++] = pid;
16907 -       
16908 +
16909         return m;
16910  }
16911  
16912  static int cgi_pid_del(server *srv, plugin_data *p, pid_t pid) {
16913         size_t i;
16914         buffer_pid_t *r = &(p->cgi_pid);
16915 -       
16916 +
16917         UNUSED(srv);
16918  
16919         for (i = 0; i < r->used; i++) {
16920                 if (r->ptr[i] == pid) break;
16921         }
16922 -       
16923 +
16924         if (i != r->used) {
16925                 /* found */
16926 -               
16927 +
16928                 if (i != r->used - 1) {
16929                         r->ptr[i] = r->ptr[r->used - 1];
16930                 }
16931                 r->used--;
16932         }
16933 -       
16934 +
16935         return 0;
16936  }
16937  
16938 -static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in, int eol) {
16939 -       char *ns;
16940 -       const char *s;
16941 -       int line = 0;
16942 -       
16943 -       UNUSED(srv);
16944 -       
16945 -       buffer_copy_string_buffer(p->parse_response, in);
16946 -       
16947 -       for (s = p->parse_response->ptr; 
16948 -            NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n'))); 
16949 -            s = ns + (eol == EOL_RN ? 2 : 1), line++) {
16950 -               const char *key, *value;
16951 -               int key_len;
16952 -               data_string *ds;
16953 -               
16954 -               ns[0] = '\0';
16955 -               
16956 -               if (line == 0 && 
16957 -                   0 == strncmp(s, "HTTP/1.", 7)) {
16958 -                       /* non-parsed header ... we parse them anyway */
16959 -                       
16960 -                       if ((s[7] == '1' ||
16961 -                            s[7] == '0') &&
16962 -                           s[8] == ' ') {
16963 -                               int status;
16964 -                               /* after the space should be a status code for us */
16965 -                               
16966 -                               status = strtol(s+9, NULL, 10);
16967 -                               
16968 -                               if (con->http_status >= 100 &&
16969 -                                   con->http_status < 1000) {
16970 -                                       /* we expected 3 digits and didn't got them */
16971 -                                       con->parsed_response |= HTTP_STATUS;
16972 -                                       con->http_status = status;
16973 -                               }
16974 -                       }
16975 -               } else {
16976 -               
16977 -                       key = s;
16978 -                       if (NULL == (value = strchr(s, ':'))) {
16979 -                               /* we expect: "<key>: <value>\r\n" */
16980 -                               continue;
16981 -                       }
16982 -                       
16983 -                       key_len = value - key;
16984 -                       value += 1;
16985 -                       
16986 -                       /* skip LWS */
16987 -                       while (*value == ' ' || *value == '\t') value++;
16988 -                       
16989 -                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
16990 -                               ds = data_response_init();
16991 -                       }
16992 -                       buffer_copy_string_len(ds->key, key, key_len);
16993 -                       buffer_copy_string(ds->value, value);
16994 -                       
16995 -                       array_insert_unique(con->response.headers, (data_unset *)ds);
16996 -                       
16997 -                       switch(key_len) {
16998 -                       case 4:
16999 -                               if (0 == strncasecmp(key, "Date", key_len)) {
17000 -                                       con->parsed_response |= HTTP_DATE;
17001 -                               }
17002 -                               break;
17003 -                       case 6:
17004 -                               if (0 == strncasecmp(key, "Status", key_len)) {
17005 -                                       con->http_status = strtol(value, NULL, 10);
17006 -                                       con->parsed_response |= HTTP_STATUS;
17007 -                               }
17008 -                               break;
17009 -                       case 8:
17010 -                               if (0 == strncasecmp(key, "Location", key_len)) {
17011 -                                       con->parsed_response |= HTTP_LOCATION;
17012 -                               }
17013 -                               break;
17014 -                       case 10:
17015 -                               if (0 == strncasecmp(key, "Connection", key_len)) {
17016 -                                       con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
17017 -                                       con->parsed_response |= HTTP_CONNECTION;
17018 -                               }
17019 -                               break;
17020 -                       case 14:
17021 -                               if (0 == strncasecmp(key, "Content-Length", key_len)) {
17022 -                                       con->response.content_length = strtol(value, NULL, 10);
17023 -                                       con->parsed_response |= HTTP_CONTENT_LENGTH;
17024 -                               }
17025 -                               break;
17026 -                       default:
17027 -                               break;
17028 -                       }
17029 -               }
17030 -       }
17031 -       
17032 -       /* CGI/1.1 rev 03 - 7.2.1.2 */
17033 -       if ((con->parsed_response & HTTP_LOCATION) &&
17034 -           !(con->parsed_response & HTTP_STATUS)) {
17035 -               con->http_status = 302;
17036 +static int cgi_demux_response(server *srv, connection *con, plugin_data *p) {
17037 +       cgi_session *sess = con->plugin_ctx[p->id];
17038 +       chunk *c = NULL;
17039 +
17040 +       switch(srv->network_backend_read(srv, con, sess->sock, sess->rb)) {
17041 +       case NETWORK_STATUS_SUCCESS:
17042 +               /* we got content */
17043 +               break;
17044 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
17045 +               return 0;
17046 +       case NETWORK_STATUS_CONNECTION_CLOSE:
17047 +               /* this is a bit too early */
17048 +               ERROR("%s", "cgi-connection got closed before we read the response-header (CGI died ?)");
17049 +               return -1;
17050 +       default:
17051 +               /* oops */
17052 +               ERROR("%s", "oops, read-pipe-read failed and I don't know why");
17053 +               return -1;
17054         }
17055 -       
17056 -       return 0;
17057 -}
17058  
17059 +       /* looks like we got some content
17060 +       *
17061 +       * split off the header from the incoming stream
17062 +       */
17063  
17064 -static int cgi_demux_response(server *srv, handler_ctx *hctx) {
17065 -       plugin_data *p    = hctx->plugin_data;
17066 -       connection  *con  = hctx->remote_conn;
17067 -       
17068 -       while(1) {
17069 -               int n;
17070 -               
17071 -               buffer_prepare_copy(hctx->response, 1024);
17072 -               if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {
17073 -                       if (errno == EAGAIN || errno == EINTR) {
17074 -                               /* would block, wait for signal */
17075 -                               return FDEVENT_HANDLED_NOT_FINISHED;
17076 -                       }
17077 -                       /* error */
17078 -                       log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd);
17079 -                       return FDEVENT_HANDLED_ERROR;
17080 -               }
17081 -               
17082 -               if (n == 0) {
17083 -                       /* read finished */
17084 -                       
17085 -                       con->file_finished = 1;
17086 -                       
17087 -                       /* send final chunk */
17088 -                       http_chunk_append_mem(srv, con, NULL, 0);
17089 -                       joblist_append(srv, con);
17090 -                       
17091 -                       return FDEVENT_HANDLED_FINISHED;
17092 -               }
17093 -               
17094 -               hctx->response->ptr[n] = '\0';
17095 -               hctx->response->used = n+1;
17096 -               
17097 -               /* split header from body */
17098 -               
17099 -               if (con->file_started == 0) {
17100 -                       char *c;
17101 -                       int in_header = 0;
17102 -                       int header_end = 0;
17103 -                       int cp, eol = EOL_UNSET;
17104 -                       size_t used = 0;
17105 -                       
17106 -                       buffer_append_string_buffer(hctx->response_header, hctx->response);
17107 -                       
17108 -                       /* nph (non-parsed headers) */
17109 -                       if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;
17110 -                       
17111 -                       /* search for the \r\n\r\n or \n\n in the string */
17112 -                       for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) {
17113 -                               if (*c == ':') in_header = 1;
17114 -                               else if (*c == '\n') {
17115 -                                       if (in_header == 0) {
17116 -                                               /* got a response without a response header */
17117 -                                               
17118 -                                               c = NULL;
17119 -                                               header_end = 1;
17120 -                                               break;
17121 -                                       }
17122 -                                       
17123 -                                       if (eol == EOL_UNSET) eol = EOL_N;
17124 -                                       
17125 -                                       if (*(c+1) == '\n') {
17126 -                                               header_end = 1;
17127 -                                               break;
17128 -                                       }
17129 -                                       
17130 -                               } else if (used > 1 && *c == '\r' && *(c+1) == '\n') {
17131 -                                       if (in_header == 0) {
17132 -                                               /* got a response without a response header */
17133 -                                               
17134 -                                               c = NULL;
17135 -                                               header_end = 1;
17136 -                                               break;
17137 -                                       }
17138 -                                       
17139 -                                       if (eol == EOL_UNSET) eol = EOL_RN;
17140 -                                       
17141 -                                       if (used > 3 &&
17142 -                                           *(c+2) == '\r' && 
17143 -                                           *(c+3) == '\n') {
17144 -                                               header_end = 1;
17145 -                                               break;
17146 -                                       }
17147 -                                       
17148 -                                       /* skip the \n */
17149 -                                       c++;
17150 -                                       cp++;
17151 -                                       used--;
17152 +       if (con->file_started == 0) {
17153 +               size_t i;
17154 +               int have_content_length = 0;
17155 +
17156 +               http_response_reset(p->resp);
17157 +
17158 +               /* the response header is not fully received yet,
17159 +               *
17160 +               * extract the http-response header from the rb-cq
17161 +               */
17162 +               switch (http_response_parse_cq(sess->rb, p->resp)) {
17163 +               case PARSE_ERROR:
17164 +                       /* parsing failed */
17165 +
17166 +                       TRACE("%s", "response parser failed");
17167 +
17168 +                       con->http_status = 502; /* Bad Gateway */
17169 +                       return -1;
17170 +               case PARSE_NEED_MORE:
17171 +                       return 0;
17172 +               case PARSE_SUCCESS:
17173 +                       con->http_status = p->resp->status;
17174 +
17175 +                       chunkqueue_remove_finished_chunks(sess->rb);
17176 +
17177 +                       /* copy the http-headers */
17178 +                       for (i = 0; i < p->resp->headers->used; i++) {
17179 +                               const char *ign[] = { "Status", "Connection", NULL };
17180 +                               size_t j;
17181 +                               data_string *ds;
17182 +
17183 +                               data_string *header = (data_string *)p->resp->headers->data[i];
17184 +
17185 +                               /* some headers are ignored by default */
17186 +                               for (j = 0; ign[j]; j++) {
17187 +                                       if (0 == strcasecmp(ign[j], header->key->ptr)) break;
17188                                 }
17189 -                       }
17190 -                       
17191 -                       if (header_end) {
17192 -                               if (c == NULL) {
17193 -                                       /* no header, but a body */
17194 -                                       
17195 -                                       if (con->request.http_version == HTTP_VERSION_1_1) {
17196 -                                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
17197 -                                       }
17198 -                                       
17199 -                                       http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
17200 -                                       joblist_append(srv, con);
17201 -                               } else {
17202 -                                       size_t hlen = c - hctx->response_header->ptr + (eol == EOL_RN ? 4 : 2);
17203 -                                       size_t blen = hctx->response_header->used - hlen - 1;
17204 -                               
17205 -                                       /* a small hack: terminate after at the second \r */
17206 -                                       hctx->response_header->used = hlen + 1 - (eol == EOL_RN ? 2 : 1);
17207 -                                       hctx->response_header->ptr[hlen - (eol == EOL_RN ? 2 : 1)] = '\0';
17208 -                               
17209 -                                       /* parse the response header */
17210 -                                       cgi_response_parse(srv, con, p, hctx->response_header, eol);
17211 -                                       
17212 -                                       /* enable chunked-transfer-encoding */
17213 -                                       if (con->request.http_version == HTTP_VERSION_1_1 &&
17214 -                                           !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
17215 -                                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
17216 -                                       }
17217 -                                       
17218 -                                       if ((hctx->response->used != hlen) && blen > 0) {
17219 -                                               http_chunk_append_mem(srv, con, c + (eol == EOL_RN ? 4: 2), blen + 1);
17220 -                                               joblist_append(srv, con);
17221 -                                       }
17222 +                               if (ign[j]) continue;
17223 +
17224 +                               if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
17225 +                                       /* CGI/1.1 rev 03 - 7.2.1.2 */
17226 +                                       if (con->http_status == 0) con->http_status = 302;
17227 +                               } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
17228 +                                       have_content_length = 1;
17229                                 }
17230                                 
17231 -                               con->file_started = 1;
17232 +                               if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
17233 +                                       ds = data_response_init();
17234 +                               }
17235 +                               buffer_copy_string_buffer(ds->key, header->key);
17236 +                               buffer_copy_string_buffer(ds->value, header->value);
17237 +
17238 +                               array_insert_unique(con->response.headers, (data_unset *)ds);
17239                         }
17240 -               } else {
17241 -                       http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
17242 -                       joblist_append(srv, con);
17243 +
17244 +                       con->file_started = 1;
17245 +                       sess->state = CGI_STATE_READ_RESPONSE_CONTENT;
17246 +
17247 +                       if (con->request.http_version == HTTP_VERSION_1_1 &&
17248 +                           !have_content_length) {
17249 +                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
17250 +                       }
17251 +
17252 +                       break;
17253                 }
17254 -               
17255 -#if 0          
17256 -               log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr);
17257 -#endif
17258         }
17259 -       
17260 -       return FDEVENT_HANDLED_NOT_FINISHED;
17261 +
17262 +       /* FIXME: pass the response-header to the other plugins to
17263 +       * setup the filter-queue
17264 +       *
17265 +       * - use next-queue instead of con->write_queue
17266 +       */
17267 +
17268 +       /* copy the content to the next cq */
17269 +       for (c = sess->rb->first; c; c = c->next) {
17270 +               http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
17271 +
17272 +               c->offset = c->mem->used - 1;
17273 +       }
17274 +
17275 +       chunkqueue_remove_finished_chunks(sess->rb);
17276 +       joblist_append(srv, con);
17277 +
17278 +       return 0;
17279  }
17280  
17281 -static handler_t cgi_connection_close(server *srv, handler_ctx *hctx) {
17282 +static handler_t cgi_connection_close(server *srv, connection *con, plugin_data *p) {
17283 +       cgi_session *sess = con->plugin_ctx[p->id];
17284         int status;
17285         pid_t pid;
17286 -       plugin_data *p;
17287 -       connection  *con;
17288 -       
17289 -       if (NULL == hctx) return HANDLER_GO_ON;
17290 -       
17291 -       p    = hctx->plugin_data;
17292 -       con  = hctx->remote_conn;
17293 -       
17294 +
17295 +       if (NULL == sess) return HANDLER_GO_ON;
17296         if (con->mode != p->id) return HANDLER_GO_ON;
17297  
17298 -#ifndef __WIN32
17299 -       
17300 +#ifndef _WIN32
17301 +
17302         /* the connection to the browser went away, but we still have a connection
17303 -        * to the CGI script 
17304 +        * to the CGI script
17305          *
17306          * close cgi-connection
17307          */
17308 -       
17309 -       if (hctx->fd != -1) {
17310 +
17311 +       if (sess->sock->fd != -1) {
17312                 /* close connection to the cgi-script */
17313 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
17314 -               fdevent_unregister(srv->ev, hctx->fd);
17315 -               
17316 -               if (close(hctx->fd)) {
17317 -                       log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
17318 -               }
17319 -               
17320 -               hctx->fd = -1;
17321 -               hctx->fde_ndx = -1;
17322 +               fdevent_event_del(srv->ev, sess->sock);
17323 +               fdevent_unregister(srv->ev, sess->sock);
17324         }
17325 -       
17326 -       pid = hctx->pid;
17327 -       
17328 +
17329 +       pid = sess->pid;
17330 +
17331         con->plugin_ctx[p->id] = NULL;
17332 -       
17333 +
17334         /* is this a good idea ? */
17335 -       cgi_handler_ctx_free(hctx);
17336 -       
17337 +       cgi_session_free(sess);
17338 +       sess = NULL;
17339 +
17340         /* if waitpid hasn't been called by response.c yet, do it here */
17341         if (pid) {
17342                 /* check if the CGI-script is already gone */
17343 +#ifndef _WIN32
17344                 switch(waitpid(pid, &status, WNOHANG)) {
17345                 case 0:
17346                         /* not finished yet */
17347 @@ -519,35 +384,35 @@
17348                 case -1:
17349                         /* */
17350                         if (errno == EINTR) break;
17351 -                       
17352 -                       /* 
17353 -                        * errno == ECHILD happens if _subrequest catches the process-status before 
17354 +
17355 +                       /*
17356 +                        * errno == ECHILD happens if _subrequest catches the process-status before
17357                          * we have read the response of the cgi process
17358 -                        * 
17359 +                        *
17360                          * -> catch status
17361                          * -> WAIT_FOR_EVENT
17362                          * -> read response
17363                          * -> we get here with waitpid == ECHILD
17364 -                        * 
17365 +                        *
17366                          */
17367                         if (errno == ECHILD) return HANDLER_GO_ON;
17368 -                       
17369 +
17370                         log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
17371                         return HANDLER_ERROR;
17372                 default:
17373                         /* Send an error if we haven't sent any data yet */
17374                         if (0 == con->file_started) {
17375                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
17376 -                               con->http_status = 500;
17377 +                               if (con->http_status == 0) con->http_status = 500;
17378                                 con->mode = DIRECT;
17379                         }
17380 -                               
17381 +
17382                         if (WIFEXITED(status)) {
17383  #if 0
17384                                 log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) cgi exited fine, pid:", pid);
17385  #endif
17386                                 pid = 0;
17387 -                               
17388 +
17389                                 return HANDLER_GO_ON;
17390                         } else {
17391                                 log_error_write(srv, __FILE__, __LINE__, "sd", "cgi died, pid:", pid);
17392 @@ -555,122 +420,126 @@
17393                                 return HANDLER_GO_ON;
17394                         }
17395                 }
17396 -               
17397 -       
17398 +
17399 +
17400                 kill(pid, SIGTERM);
17401 -               
17402 +#endif
17403                 /* cgi-script is still alive, queue the PID for removal */
17404                 cgi_pid_add(srv, p, pid);
17405         }
17406 -#endif 
17407 +#endif
17408         return HANDLER_GO_ON;
17409  }
17410  
17411  static handler_t cgi_connection_close_callback(server *srv, connection *con, void *p_d) {
17412         plugin_data *p = p_d;
17413 -       
17414 -       return cgi_connection_close(srv, con->plugin_ctx[p->id]);
17415 +
17416 +       return cgi_connection_close(srv, con, p);
17417  }
17418  
17419  
17420  static handler_t cgi_handle_fdevent(void *s, void *ctx, int revents) {
17421         server      *srv  = (server *)s;
17422 -       handler_ctx *hctx = ctx;
17423 -       connection  *con  = hctx->remote_conn;
17424 -       
17425 -       joblist_append(srv, con);
17426 -       
17427 -       if (hctx->fd == -1) {
17428 -               log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "invalid cgi-fd");
17429 -               
17430 -               return HANDLER_ERROR;
17431 -       }
17432 -       
17433 +       cgi_session *sess = ctx;
17434 +       connection  *con  = sess->remote_con;
17435 +       chunk *c;
17436 +
17437         if (revents & FDEVENT_IN) {
17438 -               switch (cgi_demux_response(srv, hctx)) {
17439 -               case FDEVENT_HANDLED_NOT_FINISHED:
17440 +               switch (sess->state) {
17441 +               case CGI_STATE_READ_RESPONSE_HEADER:
17442 +                       /* parse the header and set file-started, the demuxer will care about it */
17443 +                       joblist_append(srv, con);
17444 +
17445                         break;
17446 -               case FDEVENT_HANDLED_FINISHED:
17447 -                       /* we are done */
17448 -                       
17449 +               case CGI_STATE_READ_RESPONSE_CONTENT:
17450 +                       /* just forward the content to the out-going queue */
17451 +
17452 +                       chunkqueue_remove_finished_chunks(sess->rb);
17453 +
17454 +                       switch (srv->network_backend_read(srv, sess->remote_con, sess->sock, sess->rb)) {
17455 +                       case NETWORK_STATUS_CONNECTION_CLOSE:
17456 +                               fdevent_event_del(srv->ev, sess->sock);
17457 +
17458 +                               /* the connection is gone
17459 +                                * make the connect */
17460 +                               sess->remote_con->file_finished = 1;
17461  #if 0
17462 -                       log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "finished");
17463 +                               fdevent_event_del(srv->ev, sess->sock);
17464  #endif
17465 -                       cgi_connection_close(srv, hctx);
17466 -                       
17467 -                       /* if we get a IN|HUP and have read everything don't exec the close twice */ 
17468 -                       return HANDLER_FINISHED;
17469 -               case FDEVENT_HANDLED_ERROR:
17470 -                       connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
17471 -                       con->http_status = 500;
17472 -                       con->mode = DIRECT;
17473 -                       
17474 -                       log_error_write(srv, __FILE__, __LINE__, "s", "demuxer failed: ");
17475 +                       case NETWORK_STATUS_SUCCESS:
17476 +                               /* read even more, do we have all the content */
17477 +
17478 +                               /* how much do we want to read ? */
17479 +                               
17480 +                               /* call stream-decoder (HTTP-chunked, FastCGI, ... ) */
17481 +
17482 +                               chunkqueue_remove_finished_chunks(sess->rb);
17483 +
17484 +                               /* copy the content to the next cq */
17485 +                               for (c = sess->rb->first; c; c = c->next) {
17486 +                                       if (c->mem->used == 0) continue;
17487 +
17488 +                                       http_chunk_append_mem(srv, sess->remote_con, c->mem->ptr + c->offset, c->mem->used - c->offset);
17489 +       
17490 +                                       c->offset = c->mem->used - 1;
17491 +
17492 +                               }
17493 +                               chunkqueue_remove_finished_chunks(sess->rb);
17494 +
17495 +                               if (sess->remote_con->file_finished) {
17496 +                                       /* send final HTTP-Chunk packet */
17497 +                                       http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
17498 +                               }
17499 +                               
17500 +                               break;
17501 +                       default:
17502 +                               ERROR("%s", "oops, we failed to read");
17503 +                               break;
17504 +                       }
17505 +
17506 +                       joblist_append(srv, sess->remote_con);
17507 +                       break;
17508 +               default:
17509 +                       TRACE("unexpected state for a FDEVENT_IN: %d", sess->state);
17510                         break;
17511                 }
17512         }
17513 -       
17514 +
17515         if (revents & FDEVENT_OUT) {
17516                 /* nothing to do */
17517         }
17518 -       
17519 +
17520         /* perhaps this issue is already handled */
17521         if (revents & FDEVENT_HUP) {
17522 -               /* check if we still have a unfinished header package which is a body in reality */
17523 -               if (con->file_started == 0 &&
17524 -                   hctx->response_header->used) {
17525 -                       con->file_started = 1;
17526 -                       http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
17527 -                       joblist_append(srv, con);
17528 -               }
17529 -               
17530 -               if (con->file_finished == 0) {
17531 -                       http_chunk_append_mem(srv, con, NULL, 0);
17532 -                       joblist_append(srv, con);
17533 -               }
17534 -               
17535                 con->file_finished = 1;
17536 -               
17537 -               if (chunkqueue_is_empty(con->write_queue)) {
17538 -                       /* there is nothing left to write */
17539 -                       connection_set_state(srv, con, CON_STATE_RESPONSE_END);
17540 -               } else {
17541 -                       /* used the write-handler to finish the request on demand */
17542 -                       
17543 -               }
17544 -               
17545 -# if 0
17546 -               log_error_write(srv, __FILE__, __LINE__, "sddd", "got HUP from cgi", con->fd, hctx->fd, revents);
17547 -# endif
17548 -               
17549 -               /* rtsigs didn't liked the close */
17550 -               cgi_connection_close(srv, hctx);
17551 +
17552 +               fdevent_event_del(srv->ev, sess->sock);
17553 +
17554 +               /* someone has to close this socket now :) */
17555 +               http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
17556 +               joblist_append(srv, sess->remote_con);
17557         } else if (revents & FDEVENT_ERR) {
17558                 con->file_finished = 1;
17559 -               
17560 +
17561                 /* kill all connections to the cgi process */
17562 -               cgi_connection_close(srv, hctx);
17563 -#if 1
17564 -               log_error_write(srv, __FILE__, __LINE__, "s", "cgi-FDEVENT_ERR");
17565 -#endif                 
17566 -               return HANDLER_ERROR;
17567 +               fdevent_event_del(srv->ev, sess->sock);
17568         }
17569 -       
17570 +
17571         return HANDLER_FINISHED;
17572  }
17573  
17574  
17575  static int cgi_env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
17576         char *dst;
17577 -       
17578 +
17579         if (!key || !val) return -1;
17580 -       
17581 +
17582         dst = malloc(key_len + val_len + 3);
17583         memcpy(dst, key, key_len);
17584         dst[key_len] = '=';
17585         /* add the \0 from the value */
17586         memcpy(dst + key_len + 1, val, val_len + 1);
17587 -       
17588 +
17589         if (env->size == 0) {
17590                 env->size = 16;
17591                 env->ptr = malloc(env->size * sizeof(*env->ptr));
17592 @@ -678,45 +547,45 @@
17593                 env->size += 16;
17594                 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
17595         }
17596 -       
17597 +
17598         env->ptr[env->used++] = dst;
17599 -       
17600 +
17601         return 0;
17602  }
17603  
17604  static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *cgi_handler) {
17605         pid_t pid;
17606 -       
17607 +
17608  #ifdef HAVE_IPV6
17609         char b2[INET6_ADDRSTRLEN + 1];
17610  #endif
17611 -       
17612 +
17613         int to_cgi_fds[2];
17614         int from_cgi_fds[2];
17615         struct stat st;
17616 -       
17617 -#ifndef __WIN32        
17618 -       
17619 +
17620 +#ifndef _WIN32
17621 +
17622         if (cgi_handler->used > 1) {
17623                 /* stat the exec file */
17624                 if (-1 == (stat(cgi_handler->ptr, &st))) {
17625 -                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
17626 +                       log_error_write(srv, __FILE__, __LINE__, "sbss",
17627                                         "stat for cgi-handler", cgi_handler,
17628                                         "failed:", strerror(errno));
17629                         return -1;
17630                 }
17631         }
17632 -       
17633 +
17634         if (pipe(to_cgi_fds)) {
17635                 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
17636                 return -1;
17637         }
17638 -       
17639 +
17640         if (pipe(from_cgi_fds)) {
17641                 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
17642                 return -1;
17643         }
17644 -       
17645 +
17646         /* fork, execve */
17647         switch (pid = fork()) {
17648         case 0: {
17649 @@ -730,44 +599,40 @@
17650                 char *c;
17651                 const char *s;
17652                 server_socket *srv_sock = con->srv_socket;
17653 -               
17654 +
17655                 /* move stdout to from_cgi_fd[1] */
17656                 close(STDOUT_FILENO);
17657                 dup2(from_cgi_fds[1], STDOUT_FILENO);
17658                 close(from_cgi_fds[1]);
17659                 /* not needed */
17660                 close(from_cgi_fds[0]);
17661 -               
17662 +
17663                 /* move the stdin to to_cgi_fd[0] */
17664                 close(STDIN_FILENO);
17665                 dup2(to_cgi_fds[0], STDIN_FILENO);
17666                 close(to_cgi_fds[0]);
17667                 /* not needed */
17668                 close(to_cgi_fds[1]);
17669 -               
17670 -               /* HACK: 
17671 -                * this is not nice, but it works
17672 -                *
17673 -                * we feed the stderr of the CGI to our errorlog, if possible
17674 +
17675 +               /**
17676 +                * FIXME: add a event-handler for STDERR_FILENO and let it LOG()
17677                  */
17678 -               if (srv->errorlog_mode == ERRORLOG_FILE) {
17679 -                       close(STDERR_FILENO);
17680 -                       dup2(srv->errorlog_fd, STDERR_FILENO);
17681 -               }
17682 -               
17683 +
17684 +               close(STDERR_FILENO);
17685 +
17686                 /* create environment */
17687                 env.ptr = NULL;
17688                 env.size = 0;
17689                 env.used = 0;
17690 -               
17691 +
17692                 cgi_env_add(&env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
17693  
17694                 if (!buffer_is_empty(con->server_name)) {
17695                         cgi_env_add(&env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
17696                 } else {
17697  #ifdef HAVE_IPV6
17698 -                       s = inet_ntop(srv_sock->addr.plain.sa_family, 
17699 -                                     srv_sock->addr.plain.sa_family == AF_INET6 ? 
17700 +                       s = inet_ntop(srv_sock->addr.plain.sa_family,
17701 +                                     srv_sock->addr.plain.sa_family == AF_INET6 ?
17702                                       (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
17703                                       (const void *) &(srv_sock->addr.ipv4.sin_addr),
17704                                       b2, sizeof(b2)-1);
17705 @@ -779,10 +644,10 @@
17706                 cgi_env_add(&env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
17707  
17708                 s = get_http_version_name(con->request.http_version);
17709 -               
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 +655,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 +676,18 @@
17734                 cgi_env_add(&env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200"));
17735                 if (!buffer_is_empty(con->uri.query)) {
17736                         cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
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 +696,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 +704,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 +731,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 +761,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 +810,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 +820,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 +837,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 +861,16 @@
17930                                                 if (-1 == c->file.fd &&  /* open the file if not already open */
17931                                                     -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
17932                                                         log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
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 +880,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 +888,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 +901,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 +924,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 +               assert(sess->sock);
18007 +
18008 +               sess->sock->fd = from_cgi_fds[0];
18009 +               sess->sock->type = IOSOCKET_TYPE_PIPE;
18010 +
18011 +               if (-1 == fdevent_fcntl_set(srv->ev, sess->sock)) {
18012                         log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
18013 -                       
18014 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
18015 -                       fdevent_unregister(srv->ev, hctx->fd);
18016 -                       
18017 -                       log_error_write(srv, __FILE__, __LINE__, "sd", "cgi close:", hctx->fd);
18018 -                       
18019 -                       close(hctx->fd);
18020 -                       
18021 -                       cgi_handler_ctx_free(hctx);
18022 -                       
18023 -                       con->plugin_ctx[p->id] = NULL;
18024 -                       
18025 +
18026 +                       cgi_session_free(sess);
18027 +
18028                         return -1;
18029                 }
18030 -               
18031 +
18032 +               con->plugin_ctx[p->id] = sess;
18033 +
18034 +               fdevent_register(srv->ev, sess->sock, cgi_handle_fdevent, sess);
18035 +               fdevent_event_add(srv->ev, sess->sock, FDEVENT_IN);
18036 +
18037 +               sess->state = CGI_STATE_READ_RESPONSE_HEADER;
18038 +
18039                 break;
18040         }
18041         }
18042 -       
18043 +
18044         return 0;
18045  #else
18046         return -1;
18047  #endif
18048  }
18049  
18050 -#define PATCH(x) \
18051 -       p->conf.x = s->x;
18052  static int mod_cgi_patch_connection(server *srv, connection *con, plugin_data *p) {
18053         size_t i, j;
18054         plugin_config *s = p->config_storage[0];
18055 -       
18056 -       PATCH(cgi);
18057 -       
18058 +
18059 +       PATCH_OPTION(cgi);
18060 +
18061         /* skip the first, the global context */
18062         for (i = 1; i < srv->config_context->used; i++) {
18063                 data_config *dc = (data_config *)srv->config_context->data[i];
18064                 s = p->config_storage[i];
18065 -               
18066 +
18067                 /* condition didn't match */
18068                 if (!config_check_cond(srv, con, dc)) continue;
18069 -               
18070 +
18071                 /* merge config */
18072                 for (j = 0; j < dc->value->used; j++) {
18073                         data_unset *du = dc->value->data[j];
18074 -                       
18075 +
18076                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.assign"))) {
18077 -                               PATCH(cgi);
18078 +                               PATCH_OPTION(cgi);
18079                         }
18080                 }
18081         }
18082 -       
18083 +
18084         return 0;
18085  }
18086 -#undef PATCH
18087  
18088  URIHANDLER_FUNC(cgi_is_handled) {
18089         size_t k, s_len;
18090         plugin_data *p = p_d;
18091         buffer *fn = con->physical.path;
18092 -       
18093 +
18094         if (fn->used == 0) return HANDLER_GO_ON;
18095 -       
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 +1020,7 @@
18121                         break;
18122                 }
18123         }
18124 -       
18125 +
18126         return HANDLER_GO_ON;
18127  }
18128  
18129 @@ -1168,11 +1028,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 +1042,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 +1053,105 @@
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 +               sess = NULL;
18260 +
18261                 con->plugin_ctx[p->id] = NULL;
18262 -               
18263 +
18264                 return HANDLER_FINISHED;
18265         default:
18266 -               /* cgi process exited cleanly 
18267 -                * 
18268 -                * check if we already got the response 
18269 -                */
18270 -               
18271 -               if (!con->file_started) return HANDLER_WAIT_FOR_EVENT;
18272 -               
18273 +               con->file_finished = 1;
18274 +
18275                 if (WIFEXITED(status)) {
18276                         /* nothing */
18277                 } else {
18278                         log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?");
18279 -                       
18280 +
18281                         con->mode = DIRECT;
18282                         con->http_status = 500;
18283 -                       
18284 +
18285                 }
18286 -               
18287 -               hctx->pid = 0;
18288 -               
18289 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
18290 -               fdevent_unregister(srv->ev, hctx->fd);
18291 -               
18292 -               if (close(hctx->fd)) {
18293 -                       log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
18294 -               }
18295 -               
18296 -               cgi_handler_ctx_free(hctx);
18297 -               
18298 +
18299 +               sess->pid = 0;
18300 +
18301 +               fdevent_event_del(srv->ev, sess->sock);
18302 +               fdevent_unregister(srv->ev, sess->sock);
18303 +
18304 +               cgi_session_free(sess);
18305 +               sess = NULL;
18306 +
18307                 con->plugin_ctx[p->id] = NULL;
18308                 return HANDLER_FINISHED;
18309         }
18310 @@ -1306,8 +1175,8 @@
18311         p->init           = mod_cgi_init;
18312         p->cleanup        = mod_cgi_free;
18313         p->set_defaults   = mod_fastcgi_set_defaults;
18314 -       
18315 +
18316         p->data        = NULL;
18317 -       
18318 +
18319         return 0;
18320  }
18321 --- ../lighttpd-1.4.11/src/mod_cml.c    2006-01-30 13:51:48.000000000 +0200
18322 +++ lighttpd-1.4.12/src/mod_cml.c       2006-07-16 00:26:03.000000000 +0300
18323 @@ -4,7 +4,6 @@
18324  #include <stdlib.h>
18325  #include <string.h>
18326  #include <errno.h>
18327 -#include <unistd.h>
18328  #include <stdio.h>
18329  
18330  #include "buffer.h"
18331 @@ -20,50 +19,50 @@
18332  /* init the plugin data */
18333  INIT_FUNC(mod_cml_init) {
18334         plugin_data *p;
18335 -       
18336 +
18337         p = calloc(1, sizeof(*p));
18338 -       
18339 +
18340         p->basedir         = buffer_init();
18341         p->baseurl         = buffer_init();
18342         p->trigger_handler = buffer_init();
18343 -       
18344 +
18345         return p;
18346  }
18347  
18348  /* detroy the plugin data */
18349  FREE_FUNC(mod_cml_free) {
18350         plugin_data *p = p_d;
18351 -       
18352 +
18353         UNUSED(srv);
18354  
18355         if (!p) return HANDLER_GO_ON;
18356 -       
18357 +
18358         if (p->config_storage) {
18359                 size_t i;
18360                 for (i = 0; i < srv->config_context->used; i++) {
18361                         plugin_config *s = p->config_storage[i];
18362 -                       
18363 +
18364                         buffer_free(s->ext);
18365 -                       
18366 +
18367                         buffer_free(s->mc_namespace);
18368                         buffer_free(s->power_magnet);
18369                         array_free(s->mc_hosts);
18370 -                       
18371 +
18372  #if defined(HAVE_MEMCACHE_H)
18373                         if (s->mc) mc_free(s->mc);
18374  #endif
18375 -                       
18376 +
18377                         free(s);
18378                 }
18379                 free(p->config_storage);
18380         }
18381 -       
18382 +
18383         buffer_free(p->trigger_handler);
18384         buffer_free(p->basedir);
18385         buffer_free(p->baseurl);
18386 -       
18387 +
18388         free(p);
18389 -       
18390 +
18391         return HANDLER_GO_ON;
18392  }
18393  
18394 @@ -72,22 +71,22 @@
18395  SETDEFAULTS_FUNC(mod_cml_set_defaults) {
18396         plugin_data *p = p_d;
18397         size_t i = 0;
18398 -       
18399 -       config_values_t cv[] = { 
18400 +
18401 +       config_values_t cv[] = {
18402                 { "cml.extension",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
18403                 { "cml.memcache-hosts",         NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },        /* 1 */
18404                 { "cml.memcache-namespace",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
18405                 { "cml.power-magnet",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
18406                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
18407         };
18408 -       
18409 +
18410         if (!p) return HANDLER_ERROR;
18411 -       
18412 +
18413         p->config_storage = malloc(srv->config_context->used * sizeof(specific_config *));
18414 -       
18415 +
18416         for (i = 0; i < srv->config_context->used; i++) {
18417                 plugin_config *s;
18418 -               
18419 +
18420                 s = malloc(sizeof(plugin_config));
18421                 s->ext    = buffer_init();
18422                 s->mc_hosts       = array_init();
18423 @@ -96,87 +95,84 @@
18424  #if defined(HAVE_MEMCACHE_H)
18425                 s->mc = NULL;
18426  #endif
18427 -               
18428 +
18429                 cv[0].destination = s->ext;
18430                 cv[1].destination = s->mc_hosts;
18431                 cv[2].destination = s->mc_namespace;
18432                 cv[3].destination = s->power_magnet;
18433 -               
18434 +
18435                 p->config_storage[i] = s;
18436 -       
18437 +
18438                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
18439                         return HANDLER_ERROR;
18440                 }
18441 -               
18442 +
18443                 if (s->mc_hosts->used) {
18444  #if defined(HAVE_MEMCACHE_H)
18445                         size_t k;
18446                         s->mc = mc_new();
18447 -               
18448 +
18449                         for (k = 0; k < s->mc_hosts->used; k++) {
18450                                 data_string *ds = (data_string *)s->mc_hosts->data[k];
18451 -                               
18452 +
18453                                 if (0 != mc_server_add4(s->mc, ds->value->ptr)) {
18454 -                                       log_error_write(srv, __FILE__, __LINE__, "sb", 
18455 -                                                       "connection to host failed:", 
18456 +                                       log_error_write(srv, __FILE__, __LINE__, "sb",
18457 +                                                       "connection to host failed:",
18458                                                         ds->value);
18459 -                                       
18460 +
18461                                         return HANDLER_ERROR;
18462                                 }
18463                         }
18464  #else
18465 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
18466 +                       log_error_write(srv, __FILE__, __LINE__, "s",
18467                                         "memcache support is not compiled in but cml.memcache-hosts is set, aborting");
18468                         return HANDLER_ERROR;
18469  #endif
18470                 }
18471         }
18472 -       
18473 +
18474         return HANDLER_GO_ON;
18475  }
18476  
18477 -#define PATCH(x) \
18478 -       p->conf.x = s->x;
18479  static int mod_cml_patch_connection(server *srv, connection *con, plugin_data *p) {
18480         size_t i, j;
18481         plugin_config *s = p->config_storage[0];
18482 -       
18483 -       PATCH(ext);
18484 +
18485 +       PATCH_OPTION(ext);
18486  #if defined(HAVE_MEMCACHE_H)
18487 -       PATCH(mc);
18488 +       PATCH_OPTION(mc);
18489  #endif
18490 -       PATCH(mc_namespace);
18491 -       PATCH(power_magnet);
18492 -       
18493 +       PATCH_OPTION(mc_namespace);
18494 +       PATCH_OPTION(power_magnet);
18495 +
18496         /* skip the first, the global context */
18497         for (i = 1; i < srv->config_context->used; i++) {
18498                 data_config *dc = (data_config *)srv->config_context->data[i];
18499                 s = p->config_storage[i];
18500 -               
18501 +
18502                 /* condition didn't match */
18503                 if (!config_check_cond(srv, con, dc)) continue;
18504 -               
18505 +
18506                 /* merge config */
18507                 for (j = 0; j < dc->value->used; j++) {
18508                         data_unset *du = dc->value->data[j];
18509 -                       
18510 +
18511                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.extension"))) {
18512 -                               PATCH(ext);
18513 +                               PATCH_OPTION(ext);
18514                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-hosts"))) {
18515  #if defined(HAVE_MEMCACHE_H)
18516 -                               PATCH(mc);
18517 +                               PATCH_OPTION(mc);
18518  #endif
18519                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-namespace"))) {
18520 -                               PATCH(mc_namespace);
18521 +                               PATCH_OPTION(mc_namespace);
18522                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.power-magnet"))) {
18523 -                               PATCH(power_magnet);
18524 +                               PATCH_OPTION(power_magnet);
18525                         }
18526                 }
18527         }
18528 -       
18529 +
18530         return 0;
18531  }
18532 -#undef PATCH
18533  
18534  int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *cml_file) {
18535         buffer *b;
18536 @@ -187,57 +183,57 @@
18537         b = p->baseurl;
18538         buffer_copy_string_buffer(b, con->uri.path);
18539         for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
18540 -       
18541 +
18542         if (*c == '/') {
18543                 b->used = c - b->ptr + 2;
18544                 *(c+1) = '\0';
18545         }
18546 -       
18547 +
18548         b = p->basedir;
18549         buffer_copy_string_buffer(b, con->physical.path);
18550         for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
18551 -       
18552 +
18553         if (*c == '/') {
18554                 b->used = c - b->ptr + 2;
18555                 *(c+1) = '\0';
18556         }
18557 -       
18558 +
18559  
18560         /* prepare variables
18561          *   - cookie-based
18562          *   - get-param-based
18563          */
18564 -       
18565 +
18566         return cache_parse_lua(srv, con, p, cml_file);
18567 -       
18568 +
18569  }
18570  
18571  URIHANDLER_FUNC(mod_cml_power_magnet) {
18572         plugin_data *p = p_d;
18573 -       
18574 +
18575         mod_cml_patch_connection(srv, con, p);
18576 -       
18577 +
18578         buffer_reset(p->basedir);
18579         buffer_reset(p->baseurl);
18580         buffer_reset(p->trigger_handler);
18581  
18582         if (buffer_is_empty(p->conf.power_magnet)) return HANDLER_GO_ON;
18583 -       
18584 -       /* 
18585 +
18586 +       /*
18587          * power-magnet:
18588          * cml.power-magnet = server.docroot + "/rewrite.cml"
18589          *
18590          * is called on EACH request, take the original REQUEST_URI and modifies the
18591 -        * request header as neccesary. 
18592 +        * request header as neccesary.
18593          *
18594          * First use:
18595          * if file_exists("/maintainance.html") {
18596          *   output_include = ( "/maintainance.html" )
18597 -        *   return CACHE_HIT 
18598 +        *   return CACHE_HIT
18599          * }
18600          *
18601          * as we only want to rewrite HTML like requests we should cover it in a conditional
18602 -        * 
18603 +        *
18604          * */
18605  
18606         switch(cache_call_lua(srv, con, p, p->conf.power_magnet)) {
18607 @@ -266,20 +262,20 @@
18608  
18609  URIHANDLER_FUNC(mod_cml_is_handled) {
18610         plugin_data *p = p_d;
18611 -       
18612 +
18613         if (buffer_is_empty(con->physical.path)) return HANDLER_ERROR;
18614 -       
18615 +
18616         mod_cml_patch_connection(srv, con, p);
18617 -       
18618 +
18619         buffer_reset(p->basedir);
18620         buffer_reset(p->baseurl);
18621         buffer_reset(p->trigger_handler);
18622  
18623         if (buffer_is_empty(p->conf.ext)) return HANDLER_GO_ON;
18624 -       
18625 +
18626         if (!buffer_is_equal_right_len(con->physical.path, p->conf.ext, p->conf.ext->used - 1)) {
18627                 return HANDLER_GO_ON;
18628 -       } 
18629 +       }
18630  
18631         switch(cache_call_lua(srv, con, p, con->physical.path)) {
18632         case -1:
18633 @@ -311,15 +307,15 @@
18634  int mod_cml_plugin_init(plugin *p) {
18635         p->version     = LIGHTTPD_VERSION_ID;
18636         p->name        = buffer_init_string("cache");
18637 -       
18638 +
18639         p->init        = mod_cml_init;
18640         p->cleanup     = mod_cml_free;
18641         p->set_defaults  = mod_cml_set_defaults;
18642 -       
18643 +
18644         p->handle_subrequest_start = mod_cml_is_handled;
18645         p->handle_physical         = mod_cml_power_magnet;
18646 -       
18647 +
18648         p->data        = NULL;
18649 -       
18650 +
18651         return 0;
18652  }
18653 --- ../lighttpd-1.4.11/src/mod_cml.h    2006-01-30 13:51:35.000000000 +0200
18654 +++ lighttpd-1.4.12/src/mod_cml.h       2006-07-16 00:26:03.000000000 +0300
18655 @@ -16,10 +16,10 @@
18656  
18657  typedef struct {
18658         buffer *ext;
18659 -       
18660 +
18661         array  *mc_hosts;
18662         buffer *mc_namespace;
18663 -#if defined(HAVE_MEMCACHE_H) 
18664 +#if defined(HAVE_MEMCACHE_H)
18665         struct memcache *mc;
18666  #endif
18667         buffer *power_magnet;
18668 @@ -27,15 +27,15 @@
18669  
18670  typedef struct {
18671         PLUGIN_DATA;
18672 -       
18673 +
18674         buffer *basedir;
18675         buffer *baseurl;
18676 -       
18677 +
18678         buffer *trigger_handler;
18679 -       
18680 +
18681         plugin_config **config_storage;
18682 -       
18683 -       plugin_config conf; 
18684 +
18685 +       plugin_config conf;
18686  } plugin_data;
18687  
18688  int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn);
18689 --- ../lighttpd-1.4.11/src/mod_cml_funcs.c      2005-11-17 16:15:08.000000000 +0200
18690 +++ lighttpd-1.4.12/src/mod_cml_funcs.c 2006-07-16 00:26:04.000000000 +0300
18691 @@ -4,8 +4,7 @@
18692  #include <stdlib.h>
18693  #include <string.h>
18694  #include <errno.h>
18695 -#include <unistd.h>
18696 -#include <dirent.h>
18697 +
18698  #include <stdio.h>
18699  
18700  #include "buffer.h"
18701 @@ -13,6 +12,7 @@
18702  #include "log.h"
18703  #include "plugin.h"
18704  #include "response.h"
18705 +#include "sys-files.h"
18706  
18707  #include "mod_cml.h"
18708  #include "mod_cml_funcs.h"
18709 @@ -30,7 +30,7 @@
18710  #ifdef USE_OPENSSL
18711  #define IN const
18712  #else
18713 -#define IN 
18714 +#define IN
18715  #endif
18716  #define OUT
18717  
18718 @@ -42,29 +42,29 @@
18719         buffer b;
18720         char hex[33];
18721         int n = lua_gettop(L);
18722 -       
18723 +
18724         b.ptr = hex;
18725         b.used = 0;
18726         b.size = sizeof(hex);
18727 -       
18728 +
18729         if (n != 1) {
18730                 lua_pushstring(L, "md5: expected one argument");
18731                 lua_error(L);
18732         }
18733 -       
18734 +
18735         if (!lua_isstring(L, 1)) {
18736                 lua_pushstring(L, "md5: argument has to be a string");
18737                 lua_error(L);
18738         }
18739 -       
18740 +
18741         MD5_Init(&Md5Ctx);
18742         MD5_Update(&Md5Ctx, (unsigned char *)lua_tostring(L, 1), lua_strlen(L, 1));
18743         MD5_Final(HA1, &Md5Ctx);
18744 -       
18745 +
18746         buffer_copy_string_hex(&b, (char *)HA1, 16);
18747 -       
18748 +
18749         lua_pushstring(L, b.ptr);
18750 -       
18751 +
18752         return 1;
18753  }
18754  
18755 @@ -72,37 +72,37 @@
18756  int f_file_mtime(lua_State *L) {
18757         struct stat st;
18758         int n = lua_gettop(L);
18759 -       
18760 +
18761         if (n != 1) {
18762                 lua_pushstring(L, "file_mtime: expected one argument");
18763                 lua_error(L);
18764         }
18765 -       
18766 +
18767         if (!lua_isstring(L, 1)) {
18768                 lua_pushstring(L, "file_mtime: argument has to be a string");
18769                 lua_error(L);
18770         }
18771 -       
18772 +
18773         if (-1 == stat(lua_tostring(L, 1), &st)) {
18774                 lua_pushnil(L);
18775                 return 1;
18776         }
18777 -       
18778 +
18779         lua_pushnumber(L, st.st_mtime);
18780 -       
18781 +
18782         return 1;
18783  }
18784 -
18785 +#ifndef _WIN32
18786  int f_dir_files_iter(lua_State *L) {
18787         DIR *d;
18788         struct dirent *de;
18789 -       
18790 +
18791         d = lua_touserdata(L, lua_upvalueindex(1));
18792 -       
18793 +
18794         if (NULL == (de = readdir(d))) {
18795                 /* EOF */
18796                 closedir(d);
18797 -               
18798 +
18799                 return 0;
18800         } else {
18801                 lua_pushstring(L, de->d_name);
18802 @@ -113,75 +113,75 @@
18803  int f_dir_files(lua_State *L) {
18804         DIR *d;
18805         int n = lua_gettop(L);
18806 -       
18807 +
18808         if (n != 1) {
18809                 lua_pushstring(L, "dir_files: expected one argument");
18810                 lua_error(L);
18811         }
18812 -       
18813 +
18814         if (!lua_isstring(L, 1)) {
18815                 lua_pushstring(L, "dir_files: argument has to be a string");
18816                 lua_error(L);
18817         }
18818 -       
18819 -       /* check if there is a valid DIR handle on the stack */ 
18820 +
18821 +       /* check if there is a valid DIR handle on the stack */
18822         if (NULL == (d = opendir(lua_tostring(L, 1)))) {
18823                 lua_pushnil(L);
18824                 return 1;
18825         }
18826 -       
18827 +
18828         /* push d into registry */
18829         lua_pushlightuserdata(L, d);
18830         lua_pushcclosure(L, f_dir_files_iter, 1);
18831 -       
18832 +
18833         return 1;
18834  }
18835 -
18836 +#endif
18837  int f_file_isreg(lua_State *L) {
18838         struct stat st;
18839         int n = lua_gettop(L);
18840 -       
18841 +
18842         if (n != 1) {
18843                 lua_pushstring(L, "file_isreg: expected one argument");
18844                 lua_error(L);
18845         }
18846 -       
18847 +
18848         if (!lua_isstring(L, 1)) {
18849                 lua_pushstring(L, "file_isreg: argument has to be a string");
18850                 lua_error(L);
18851         }
18852 -       
18853 +
18854         if (-1 == stat(lua_tostring(L, 1), &st)) {
18855                 lua_pushnil(L);
18856                 return 1;
18857         }
18858 -       
18859 +
18860         lua_pushnumber(L, S_ISREG(st.st_mode));
18861 -       
18862 +
18863         return 1;
18864  }
18865  
18866  int f_file_isdir(lua_State *L) {
18867         struct stat st;
18868         int n = lua_gettop(L);
18869 -       
18870 +
18871         if (n != 1) {
18872                 lua_pushstring(L, "file_isreg: expected one argument");
18873                 lua_error(L);
18874         }
18875 -       
18876 +
18877         if (!lua_isstring(L, 1)) {
18878                 lua_pushstring(L, "file_isreg: argument has to be a string");
18879                 lua_error(L);
18880         }
18881 -       
18882 +
18883         if (-1 == stat(lua_tostring(L, 1), &st)) {
18884                 lua_pushnil(L);
18885                 return 1;
18886         }
18887 -       
18888 +
18889         lua_pushnumber(L, S_ISDIR(st.st_mode));
18890 -       
18891 +
18892         return 1;
18893  }
18894  
18895 @@ -192,33 +192,33 @@
18896         char *r;
18897         int n = lua_gettop(L);
18898         struct memcache *mc;
18899 -       
18900 +
18901         if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
18902                 lua_pushstring(L, "where is my userdata ?");
18903                 lua_error(L);
18904         }
18905 -       
18906 +
18907         mc = lua_touserdata(L, lua_upvalueindex(1));
18908 -       
18909 +
18910         if (n != 1) {
18911                 lua_pushstring(L, "expected one argument");
18912                 lua_error(L);
18913         }
18914 -       
18915 +
18916         if (!lua_isstring(L, 1)) {
18917                 lua_pushstring(L, "argument has to be a string");
18918                 lua_error(L);
18919         }
18920 -       
18921 -       if (NULL == (r = mc_aget(mc, 
18922 +
18923 +       if (NULL == (r = mc_aget(mc,
18924                                  lua_tostring(L, 1), lua_strlen(L, 1)))) {
18925 -                               
18926 +
18927                 lua_pushboolean(L, 0);
18928                 return 1;
18929         }
18930 -       
18931 +
18932         free(r);
18933 -       
18934 +
18935         lua_pushboolean(L, 1);
18936         return 1;
18937  }
18938 @@ -226,74 +226,74 @@
18939  int f_memcache_get_string(lua_State *L) {
18940         char *r;
18941         int n = lua_gettop(L);
18942 -       
18943 +
18944         struct memcache *mc;
18945 -       
18946 +
18947         if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
18948                 lua_pushstring(L, "where is my userdata ?");
18949                 lua_error(L);
18950         }
18951 -       
18952 +
18953         mc = lua_touserdata(L, lua_upvalueindex(1));
18954 -       
18955 -       
18956 +
18957 +
18958         if (n != 1) {
18959                 lua_pushstring(L, "expected one argument");
18960                 lua_error(L);
18961         }
18962 -       
18963 +
18964         if (!lua_isstring(L, 1)) {
18965                 lua_pushstring(L, "argument has to be a string");
18966                 lua_error(L);
18967         }
18968 -       
18969 -       if (NULL == (r = mc_aget(mc, 
18970 +
18971 +       if (NULL == (r = mc_aget(mc,
18972                                  lua_tostring(L, 1), lua_strlen(L, 1)))) {
18973                 lua_pushnil(L);
18974                 return 1;
18975         }
18976 -       
18977 +
18978         lua_pushstring(L, r);
18979 -       
18980 +
18981         free(r);
18982 -       
18983 +
18984         return 1;
18985  }
18986  
18987  int f_memcache_get_long(lua_State *L) {
18988         char *r;
18989         int n = lua_gettop(L);
18990 -       
18991 +
18992         struct memcache *mc;
18993 -       
18994 +
18995         if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
18996                 lua_pushstring(L, "where is my userdata ?");
18997                 lua_error(L);
18998         }
18999 -       
19000 +
19001         mc = lua_touserdata(L, lua_upvalueindex(1));
19002 -       
19003 -       
19004 +
19005 +
19006         if (n != 1) {
19007                 lua_pushstring(L, "expected one argument");
19008                 lua_error(L);
19009         }
19010 -       
19011 +
19012         if (!lua_isstring(L, 1)) {
19013                 lua_pushstring(L, "argument has to be a string");
19014                 lua_error(L);
19015         }
19016 -       
19017 -       if (NULL == (r = mc_aget(mc, 
19018 +
19019 +       if (NULL == (r = mc_aget(mc,
19020                                  lua_tostring(L, 1), lua_strlen(L, 1)))) {
19021                 lua_pushnil(L);
19022                 return 1;
19023         }
19024 -       
19025 +
19026         lua_pushnumber(L, strtol(r, NULL, 10));
19027 -       
19028 +
19029         free(r);
19030 -       
19031 +
19032         return 1;
19033  }
19034  #endif
19035 --- ../lighttpd-1.4.11/src/mod_cml_lua.c        2006-01-30 13:56:40.000000000 +0200
19036 +++ lighttpd-1.4.12/src/mod_cml_lua.c   2006-07-16 00:26:04.000000000 +0300
19037 @@ -23,7 +23,7 @@
19038  #ifdef USE_OPENSSL
19039  #define IN const
19040  #else
19041 -#define IN 
19042 +#define IN
19043  #endif
19044  #define OUT
19045  
19046 @@ -31,6 +31,7 @@
19047  
19048  #include <lua.h>
19049  #include <lualib.h>
19050 +#include <lauxlib.h>
19051  
19052  typedef struct {
19053         stream st;
19054 @@ -39,11 +40,11 @@
19055  
19056  static const char * load_file(lua_State *L, void *data, size_t *size) {
19057         readme *rm = data;
19058 -       
19059 +
19060         UNUSED(L);
19061 -       
19062 +
19063         if (rm->done) return 0;
19064 -       
19065 +
19066         *size = rm->st.size;
19067         rm->done = 1;
19068         return rm->st.start;
19069 @@ -51,47 +52,47 @@
19070  
19071  static int lua_to_c_get_string(lua_State *L, const char *varname, buffer *b) {
19072         int curelem;
19073 -       
19074 +
19075         lua_pushstring(L, varname);
19076 -       
19077 +
19078         curelem = lua_gettop(L);
19079         lua_gettable(L, LUA_GLOBALSINDEX);
19080 -       
19081 +
19082         /* it should be a table */
19083         if (!lua_isstring(L, curelem)) {
19084                 lua_settop(L, curelem - 1);
19085 -               
19086 +
19087                 return -1;
19088         }
19089 -       
19090 +
19091         buffer_copy_string(b, lua_tostring(L, curelem));
19092 -       
19093 +
19094         lua_pop(L, 1);
19095 -       
19096 +
19097         assert(curelem - 1 == lua_gettop(L));
19098 -       
19099 +
19100         return 0;
19101  }
19102  
19103  static int lua_to_c_is_table(lua_State *L, const char *varname) {
19104         int curelem;
19105 -       
19106 +
19107         lua_pushstring(L, varname);
19108 -       
19109 +
19110         curelem = lua_gettop(L);
19111         lua_gettable(L, LUA_GLOBALSINDEX);
19112 -       
19113 +
19114         /* it should be a table */
19115         if (!lua_istable(L, curelem)) {
19116                 lua_settop(L, curelem - 1);
19117 -               
19118 +
19119                 return 0;
19120         }
19121 -       
19122 +
19123         lua_settop(L, curelem - 1);
19124 -       
19125 +
19126         assert(curelem - 1 == lua_gettop(L));
19127 -       
19128 +
19129         return 1;
19130  }
19131  
19132 @@ -99,7 +100,7 @@
19133         lua_pushlstring(L, key, key_len);
19134         lua_pushlstring(L, val, val_len);
19135         lua_settable(L, tbl);
19136 -       
19137 +
19138         return 0;
19139  }
19140  
19141 @@ -108,21 +109,21 @@
19142         size_t is_key = 1;
19143         size_t i;
19144         char *key = NULL, *val = NULL;
19145 -       
19146 +
19147         key = qrystr->ptr;
19148 -       
19149 +
19150         /* we need the \0 */
19151         for (i = 0; i < qrystr->used; i++) {
19152                 switch(qrystr->ptr[i]) {
19153                 case '=':
19154                         if (is_key) {
19155                                 val = qrystr->ptr + i + 1;
19156 -                               
19157 +
19158                                 qrystr->ptr[i] = '\0';
19159 -                               
19160 +
19161                                 is_key = 0;
19162                         }
19163 -                       
19164 +
19165                         break;
19166                 case '&':
19167                 case '\0': /* fin symbol */
19168 @@ -131,19 +132,19 @@
19169  
19170                                 /* terminate the value */
19171                                 qrystr->ptr[i] = '\0';
19172 -                               
19173 -                               c_to_lua_push(L, tbl, 
19174 +
19175 +                               c_to_lua_push(L, tbl,
19176                                               key, strlen(key),
19177                                               val, strlen(val));
19178                         }
19179 -                       
19180 +
19181                         key = qrystr->ptr + i + 1;
19182                         val = NULL;
19183                         is_key = 1;
19184                         break;
19185                 }
19186         }
19187 -       
19188 +
19189         return 0;
19190  }
19191  #if 0
19192 @@ -151,21 +152,21 @@
19193         data_unset *d;
19194  
19195         UNUSED(srv);
19196 -       
19197 +
19198         if (NULL != (d = array_get_element(con->request.headers, "Cookie"))) {
19199                 data_string *ds = (data_string *)d;
19200                 size_t key = 0, value = 0;
19201                 size_t is_key = 1, is_sid = 0;
19202                 size_t i;
19203 -               
19204 +
19205                 /* found COOKIE */
19206                 if (!DATA_IS_STRING(d)) return -1;
19207                 if (ds->value->used == 0) return -1;
19208 -                       
19209 +
19210                 if (ds->value->ptr[0] == '\0' ||
19211                     ds->value->ptr[0] == '=' ||
19212                     ds->value->ptr[0] == ';') return -1;
19213 -               
19214 +
19215                 buffer_reset(p->session_id);
19216                 for (i = 0; i < ds->value->used; i++) {
19217                         switch(ds->value->ptr[i]) {
19218 @@ -176,16 +177,16 @@
19219                                                 is_sid = 1;
19220                                         }
19221                                         value = i + 1;
19222 -                               
19223 +
19224                                         is_key = 0;
19225                                 }
19226 -                               
19227 +
19228                                 break;
19229                         case ';':
19230                                 if (is_sid) {
19231                                         buffer_copy_string_len(p->session_id, ds->value->ptr + value, i - value);
19232                                 }
19233 -                               
19234 +
19235                                 is_sid = 0;
19236                                 key = i + 1;
19237                                 value = 0;
19238 @@ -204,48 +205,43 @@
19239                         }
19240                 }
19241         }
19242 -       
19243 +
19244         return 0;
19245  }
19246  #endif
19247  
19248  int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
19249 -       lua_State *L; 
19250 +       lua_State *L;
19251         readme rm;
19252         int ret = -1;
19253         buffer *b = buffer_init();
19254         int header_tbl = 0;
19255 -       
19256 +
19257         rm.done = 0;
19258         stream_open(&rm.st, fn);
19259 -       
19260 +
19261         /* push the lua file to the interpreter and see what happends */
19262 -       L = lua_open();
19263 -       
19264 -       luaopen_base(L);
19265 -       luaopen_table(L);
19266 -       luaopen_string(L);
19267 -       luaopen_math(L);
19268 -       luaopen_io(L);
19269 -       
19270 +       L = luaL_newstate();
19271 +       luaL_openlibs(L);
19272 +
19273         /* register functions */
19274         lua_register(L, "md5", f_crypto_md5);
19275         lua_register(L, "file_mtime", f_file_mtime);
19276         lua_register(L, "file_isreg", f_file_isreg);
19277         lua_register(L, "file_isdir", f_file_isreg);
19278         lua_register(L, "dir_files", f_dir_files);
19279 -       
19280 +
19281  #ifdef HAVE_MEMCACHE_H
19282         lua_pushliteral(L, "memcache_get_long");
19283         lua_pushlightuserdata(L, p->conf.mc);
19284         lua_pushcclosure(L, f_memcache_get_long, 1);
19285         lua_settable(L, LUA_GLOBALSINDEX);
19286 -       
19287 +
19288         lua_pushliteral(L, "memcache_get_string");
19289         lua_pushlightuserdata(L, p->conf.mc);
19290         lua_pushcclosure(L, f_memcache_get_string, 1);
19291         lua_settable(L, LUA_GLOBALSINDEX);
19292 -       
19293 +
19294         lua_pushliteral(L, "memcache_exists");
19295         lua_pushlightuserdata(L, p->conf.mc);
19296         lua_pushcclosure(L, f_memcache_exists, 1);
19297 @@ -255,11 +251,11 @@
19298         lua_pushliteral(L, "request");
19299         lua_newtable(L);
19300         lua_settable(L, LUA_GLOBALSINDEX);
19301 -       
19302 +
19303         lua_pushliteral(L, "request");
19304         header_tbl = lua_gettop(L);
19305         lua_gettable(L, LUA_GLOBALSINDEX);
19306 -       
19307 +
19308         c_to_lua_push(L, header_tbl, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
19309         c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
19310         c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
19311 @@ -267,84 +263,84 @@
19312         if (!buffer_is_empty(con->request.pathinfo)) {
19313                 c_to_lua_push(L, header_tbl, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
19314         }
19315 -       
19316 +
19317         c_to_lua_push(L, header_tbl, CONST_STR_LEN("CWD"), CONST_BUF_LEN(p->basedir));
19318         c_to_lua_push(L, header_tbl, CONST_STR_LEN("BASEURL"), CONST_BUF_LEN(p->baseurl));
19319 -       
19320 +
19321         /* register GET parameter */
19322         lua_pushliteral(L, "get");
19323         lua_newtable(L);
19324         lua_settable(L, LUA_GLOBALSINDEX);
19325 -       
19326 +
19327         lua_pushliteral(L, "get");
19328         header_tbl = lua_gettop(L);
19329         lua_gettable(L, LUA_GLOBALSINDEX);
19330 -       
19331 +
19332         buffer_copy_string_buffer(b, con->uri.query);
19333         cache_export_get_params(L, header_tbl, b);
19334         buffer_reset(b);
19335  
19336 -       /* 2 default constants */       
19337 +       /* 2 default constants */
19338         lua_pushliteral(L, "CACHE_HIT");
19339         lua_pushboolean(L, 0);
19340         lua_settable(L, LUA_GLOBALSINDEX);
19341 -       
19342 +
19343         lua_pushliteral(L, "CACHE_MISS");
19344         lua_pushboolean(L, 1);
19345         lua_settable(L, LUA_GLOBALSINDEX);
19346 -       
19347 +
19348         /* load lua program */
19349         if (lua_load(L, load_file, &rm, fn->ptr) || lua_pcall(L,0,1,0)) {
19350                 log_error_write(srv, __FILE__, __LINE__, "s",
19351                                 lua_tostring(L,-1));
19352 -               
19353 +
19354                 goto error;
19355         }
19356 -       
19357 +
19358         /* get return value */
19359         ret = (int)lua_tonumber(L, -1);
19360         lua_pop(L, 1);
19361 -       
19362 -       /* fetch the data from lua */ 
19363 +
19364 +       /* fetch the data from lua */
19365         lua_to_c_get_string(L, "trigger_handler", p->trigger_handler);
19366 -       
19367 +
19368         if (0 == lua_to_c_get_string(L, "output_contenttype", b)) {
19369                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(b));
19370         }
19371 -       
19372 +
19373         if (ret == 0) {
19374                 /* up to now it is a cache-hit, check if all files exist */
19375 -               
19376 +
19377                 int curelem;
19378                 time_t mtime = 0;
19379 -       
19380 +
19381                 if (!lua_to_c_is_table(L, "output_include")) {
19382                         log_error_write(srv, __FILE__, __LINE__, "s",
19383                                 "output_include is missing or not a table");
19384                         ret = -1;
19385 -               
19386 +
19387                         goto error;
19388                 }
19389 -               
19390 +
19391                 lua_pushstring(L, "output_include");
19392 -               
19393 +
19394                 curelem = lua_gettop(L);
19395                 lua_gettable(L, LUA_GLOBALSINDEX);
19396  
19397                 /* HOW-TO build a etag ?
19398 -                * as we don't just have one file we have to take the stat() 
19399 +                * as we don't just have one file we have to take the stat()
19400                  * from all base files, merge them and build the etag from
19401                  * it later.
19402 -                * 
19403 +                *
19404                  * The mtime of the content is the mtime of the freshest base file
19405 -                * 
19406 +                *
19407                  * */
19408 -               
19409 +
19410                 lua_pushnil(L);  /* first key */
19411                 while (lua_next(L, curelem) != 0) {
19412                         stat_cache_entry *sce = NULL;
19413                         /* key' is at index -2 and value' at index -1 */
19414 -                       
19415 +
19416                         if (lua_isstring(L, -1)) {
19417                                 const char *s = lua_tostring(L, -1);
19418  
19419 @@ -364,18 +360,18 @@
19420                                                 /* a file is missing, call the handler to generate it */
19421                                                 if (!buffer_is_empty(p->trigger_handler)) {
19422                                                         ret = 1; /* cache-miss */
19423 -                                                       
19424 +
19425                                                         log_error_write(srv, __FILE__, __LINE__, "s",
19426                                                                         "a file is missing, calling handler");
19427 -                                                       
19428 +
19429                                                         break;
19430                                                 } else {
19431                                                         /* handler not set -> 500 */
19432                                                         ret = -1;
19433 -                                                       
19434 +
19435                                                         log_error_write(srv, __FILE__, __LINE__, "s",
19436                                                                         "a file missing and no handler set");
19437 -                                                       
19438 +
19439                                                         break;
19440                                                 }
19441                                                 break;
19442 @@ -393,12 +389,12 @@
19443                                                 "not a string");
19444                                 break;
19445                         }
19446 -               
19447 +
19448                         lua_pop(L, 1);  /* removes value'; keeps key' for next iteration */
19449                 }
19450 -               
19451 +
19452                 lua_settop(L, curelem - 1);
19453 -               
19454 +
19455                 if (ret == 0) {
19456                         data_string *ds;
19457                         char timebuf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
19458 @@ -410,9 +406,9 @@
19459  
19460                         /* no Last-Modified specified */
19461                         if ((mtime) && (NULL == ds)) {
19462 -               
19463 +
19464                                 strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&mtime));
19465 -                               
19466 +
19467                                 response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), timebuf, sizeof(timebuf) - 1);
19468  
19469  
19470 @@ -428,9 +424,9 @@
19471                                 tbuf.used = 0;
19472                                 tbuf.ptr = NULL;
19473                         }
19474 -                       
19475 +
19476                         if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, &tbuf)) {
19477 -                               /* ok, the client already has our content, 
19478 +                               /* ok, the client already has our content,
19479                                  * no need to send it again */
19480  
19481                                 chunkqueue_reset(con->write_queue);
19482 @@ -440,24 +436,24 @@
19483                         chunkqueue_reset(con->write_queue);
19484                 }
19485         }
19486 -       
19487 +
19488         if (ret == 1 && !buffer_is_empty(p->trigger_handler)) {
19489                 /* cache-miss */
19490                 buffer_copy_string_buffer(con->uri.path, p->baseurl);
19491                 buffer_append_string_buffer(con->uri.path, p->trigger_handler);
19492 -       
19493 +
19494                 buffer_copy_string_buffer(con->physical.path, p->basedir);
19495                 buffer_append_string_buffer(con->physical.path, p->trigger_handler);
19496 -               
19497 +
19498                 chunkqueue_reset(con->write_queue);
19499         }
19500 -       
19501 +
19502  error:
19503         lua_close(L);
19504 -       
19505 +
19506         stream_close(&rm.st);
19507         buffer_free(b);
19508 -       
19509 +
19510         return ret /* cache-error */;
19511  }
19512  #else
19513 --- ../lighttpd-1.4.11/src/mod_compress.c       2005-11-18 13:49:14.000000000 +0200
19514 +++ lighttpd-1.4.12/src/mod_compress.c  2006-07-16 00:26:04.000000000 +0300
19515 @@ -2,7 +2,6 @@
19516  #include <sys/stat.h>
19517  
19518  #include <fcntl.h>
19519 -#include <unistd.h>
19520  #include <ctype.h>
19521  #include <stdlib.h>
19522  #include <string.h>
19523 @@ -14,6 +13,7 @@
19524  #include "buffer.h"
19525  #include "response.h"
19526  #include "stat_cache.h"
19527 +#include "http_chunk.h"
19528  
19529  #include "plugin.h"
19530  
19531 @@ -33,6 +33,7 @@
19532  #endif
19533  
19534  #include "sys-mmap.h"
19535 +#include "sys-files.h"
19536  
19537  /* request: accept-encoding */
19538  #define HTTP_ACCEPT_ENCODING_IDENTITY BV(0)
19539 @@ -55,97 +56,127 @@
19540         PLUGIN_DATA;
19541         buffer *ofn;
19542         buffer *b;
19543 -       
19544 +
19545         plugin_config **config_storage;
19546 -       plugin_config conf; 
19547 +       plugin_config conf;
19548  } plugin_data;
19549  
19550  INIT_FUNC(mod_compress_init) {
19551         plugin_data *p;
19552 -       
19553 +
19554         p = calloc(1, sizeof(*p));
19555 -       
19556 +
19557         p->ofn = buffer_init();
19558         p->b = buffer_init();
19559 -       
19560 +
19561         return p;
19562  }
19563  
19564  FREE_FUNC(mod_compress_free) {
19565         plugin_data *p = p_d;
19566 -       
19567 +
19568         UNUSED(srv);
19569  
19570         if (!p) return HANDLER_GO_ON;
19571 -       
19572 +
19573         buffer_free(p->ofn);
19574         buffer_free(p->b);
19575 -       
19576 +
19577         if (p->config_storage) {
19578                 size_t i;
19579                 for (i = 0; i < srv->config_context->used; i++) {
19580                         plugin_config *s = p->config_storage[i];
19581  
19582                         if (!s) continue;
19583 -                       
19584 +
19585                         array_free(s->compress);
19586                         buffer_free(s->compress_cache_dir);
19587 -                       
19588 +
19589                         free(s);
19590                 }
19591                 free(p->config_storage);
19592         }
19593 -       
19594 -       
19595 +
19596 +
19597         free(p);
19598 -       
19599 +
19600         return HANDLER_GO_ON;
19601  }
19602  
19603 +void mkdir_recursive(const char *dir) {
19604 +
19605 +       char dir_copy[256];
19606 +       char *p = dir_copy;
19607 +
19608 +       if (!dir || !dir[0])
19609 +               return;
19610 +
19611 +       strncpy(dir_copy, dir, sizeof(dir_copy) / sizeof(dir_copy[0]));
19612 +
19613 +       while ((p = strchr(p + 1, '/')) != NULL) {
19614 +
19615 +               *p = '\0';
19616 +               if ((mkdir(dir_copy, 0700) != 0) && (errno != EEXIST))
19617 +                       return;
19618 +
19619 +               *p++ = '/';
19620 +       }
19621 +
19622 +       mkdir(dir, 0700);
19623 +}
19624 +
19625  SETDEFAULTS_FUNC(mod_compress_setdefaults) {
19626         plugin_data *p = p_d;
19627         size_t i = 0;
19628 -       
19629 -       config_values_t cv[] = { 
19630 +
19631 +       config_values_t cv[] = {
19632                 { "compress.cache-dir",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
19633                 { "compress.filetype",              NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
19634                 { "compress.max-filesize",          NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
19635                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
19636         };
19637 -       
19638 +
19639         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
19640 -       
19641 +
19642         for (i = 0; i < srv->config_context->used; i++) {
19643                 plugin_config *s;
19644 -               
19645 +
19646                 s = calloc(1, sizeof(plugin_config));
19647                 s->compress_cache_dir = buffer_init();
19648                 s->compress = array_init();
19649                 s->compress_max_filesize = 0;
19650 -               
19651 +
19652                 cv[0].destination = s->compress_cache_dir;
19653                 cv[1].destination = s->compress;
19654                 cv[2].destination = &(s->compress_max_filesize);
19655 -               
19656 +
19657                 p->config_storage[i] = s;
19658 -       
19659 +
19660                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
19661                         return HANDLER_ERROR;
19662                 }
19663 -               
19664 +
19665                 if (!buffer_is_empty(s->compress_cache_dir)) {
19666                         struct stat st;
19667                         if (0 != stat(s->compress_cache_dir->ptr, &st)) {
19668 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir", 
19669 +
19670 +                               log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir, attempting to create",
19671                                                 s->compress_cache_dir, strerror(errno));
19672 -                               
19673 -                               return HANDLER_ERROR;
19674 +                               mkdir_recursive(s->compress_cache_dir->ptr);
19675 +
19676 +                               if (0 != stat(s->compress_cache_dir->ptr, &st)) {
19677 +
19678 +                                       log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir, create failed",
19679 +                                                                       s->compress_cache_dir, strerror(errno));
19680 +
19681 +                                       return HANDLER_ERROR;
19682 +                               }
19683                         }
19684                 }
19685         }
19686 -       
19687 +
19688         return HANDLER_GO_ON;
19689 -       
19690 +
19691  }
19692  
19693  #ifdef USE_ZLIB
19694 @@ -153,32 +184,32 @@
19695         unsigned char *c;
19696         unsigned long crc;
19697         z_stream z;
19698 -       
19699 +
19700         UNUSED(srv);
19701         UNUSED(con);
19702  
19703         z.zalloc = Z_NULL;
19704         z.zfree = Z_NULL;
19705         z.opaque = Z_NULL;
19706 -       
19707 -       if (Z_OK != deflateInit2(&z, 
19708 +
19709 +       if (Z_OK != deflateInit2(&z,
19710                                  Z_DEFAULT_COMPRESSION,
19711 -                                Z_DEFLATED, 
19712 +                                Z_DEFLATED,
19713                                  -MAX_WBITS,  /* supress zlib-header */
19714                                  8,
19715                                  Z_DEFAULT_STRATEGY)) {
19716                 return -1;
19717         }
19718 -               
19719 +
19720         z.next_in = (unsigned char *)start;
19721         z.avail_in = st_size;
19722         z.total_in = 0;
19723 -               
19724 -                       
19725 +
19726 +
19727         buffer_prepare_copy(p->b, (z.avail_in * 1.1) + 12 + 18);
19728 -               
19729 +
19730         /* write gzip header */
19731 -               
19732 +
19733         c = (unsigned char *)p->b->ptr;
19734         c[0] = 0x1f;
19735         c[1] = 0x8b;
19736 @@ -190,24 +221,24 @@
19737         c[7] = (mtime >> 24) & 0xff;
19738         c[8] = 0x00; /* extra flags */
19739         c[9] = 0x03; /* UNIX */
19740 -       
19741 +
19742         p->b->used = 10;
19743         z.next_out = (unsigned char *)p->b->ptr + p->b->used;
19744         z.avail_out = p->b->size - p->b->used - 8;
19745         z.total_out = 0;
19746 -       
19747 +
19748         if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
19749                 deflateEnd(&z);
19750                 return -1;
19751         }
19752 -       
19753 +
19754         /* trailer */
19755         p->b->used += z.total_out;
19756 -       
19757 +
19758         crc = generate_crc32c(start, st_size);
19759 -               
19760 +
19761         c = (unsigned char *)p->b->ptr + p->b->used;
19762 -               
19763 +
19764         c[0] = (crc >>  0) & 0xff;
19765         c[1] = (crc >>  8) & 0xff;
19766         c[2] = (crc >> 16) & 0xff;
19767 @@ -221,51 +252,51 @@
19768         if (Z_OK != deflateEnd(&z)) {
19769                 return -1;
19770         }
19771 -       
19772 +
19773         return 0;
19774  }
19775  
19776  static int deflate_file_to_buffer_deflate(server *srv, connection *con, plugin_data *p, unsigned char *start, off_t st_size) {
19777         z_stream z;
19778 -       
19779 +
19780         UNUSED(srv);
19781         UNUSED(con);
19782  
19783         z.zalloc = Z_NULL;
19784         z.zfree = Z_NULL;
19785         z.opaque = Z_NULL;
19786 -       
19787 -       if (Z_OK != deflateInit2(&z, 
19788 +
19789 +       if (Z_OK != deflateInit2(&z,
19790                                  Z_DEFAULT_COMPRESSION,
19791 -                                Z_DEFLATED, 
19792 +                                Z_DEFLATED,
19793                                  -MAX_WBITS,  /* supress zlib-header */
19794                                  8,
19795                                  Z_DEFAULT_STRATEGY)) {
19796                 return -1;
19797         }
19798 -               
19799 +
19800         z.next_in = start;
19801         z.avail_in = st_size;
19802         z.total_in = 0;
19803 -               
19804 +
19805         buffer_prepare_copy(p->b, (z.avail_in * 1.1) + 12);
19806 -       
19807 +
19808         z.next_out = (unsigned char *)p->b->ptr;
19809         z.avail_out = p->b->size;
19810         z.total_out = 0;
19811 -       
19812 +
19813         if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
19814                 deflateEnd(&z);
19815                 return -1;
19816         }
19817 -       
19818 +
19819         /* trailer */
19820         p->b->used += z.total_out;
19821 -       
19822 +
19823         if (Z_OK != deflateEnd(&z)) {
19824                 return -1;
19825         }
19826 -       
19827 +
19828         return 0;
19829  }
19830  
19831 @@ -274,48 +305,48 @@
19832  #ifdef USE_BZ2LIB
19833  static int deflate_file_to_buffer_bzip2(server *srv, connection *con, plugin_data *p, unsigned char *start, off_t st_size) {
19834         bz_stream bz;
19835 -       
19836 +
19837         UNUSED(srv);
19838         UNUSED(con);
19839  
19840         bz.bzalloc = NULL;
19841         bz.bzfree = NULL;
19842         bz.opaque = NULL;
19843 -       
19844 -       if (BZ_OK != BZ2_bzCompressInit(&bz, 
19845 +
19846 +       if (BZ_OK != BZ2_bzCompressInit(&bz,
19847                                         9, /* blocksize = 900k */
19848                                         0, /* no output */
19849                                         0)) { /* workFactor: default */
19850                 return -1;
19851         }
19852 -               
19853 +
19854         bz.next_in = (char *)start;
19855         bz.avail_in = st_size;
19856         bz.total_in_lo32 = 0;
19857         bz.total_in_hi32 = 0;
19858 -               
19859 +
19860         buffer_prepare_copy(p->b, (bz.avail_in * 1.1) + 12);
19861 -       
19862 +
19863         bz.next_out = p->b->ptr;
19864         bz.avail_out = p->b->size;
19865         bz.total_out_lo32 = 0;
19866         bz.total_out_hi32 = 0;
19867 -       
19868 +
19869         if (BZ_STREAM_END != BZ2_bzCompress(&bz, BZ_FINISH)) {
19870                 BZ2_bzCompressEnd(&bz);
19871                 return -1;
19872         }
19873 -       
19874 +
19875         /* file is too large for now */
19876         if (bz.total_out_hi32) return -1;
19877 -       
19878 +
19879         /* trailer */
19880         p->b->used = bz.total_out_lo32;
19881 -       
19882 +
19883         if (BZ_OK != BZ2_bzCompressEnd(&bz)) {
19884                 return -1;
19885         }
19886 -       
19887 +
19888         return 0;
19889  }
19890  #endif
19891 @@ -326,47 +357,50 @@
19892         void *start;
19893         const char *filename = fn->ptr;
19894         ssize_t r;
19895 -       
19896 +       stat_cache_entry *compressed_sce = NULL;
19897 +
19898 +       if (buffer_is_empty(p->conf.compress_cache_dir)) return -1;
19899 +
19900         /* overflow */
19901         if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
19902 -       
19903 -       /* don't mmap files > 128Mb 
19904 -        * 
19905 +
19906 +       /* don't mmap files > 128Mb
19907 +        *
19908          * we could use a sliding window, but currently there is no need for it
19909          */
19910 -       
19911 +
19912         if (sce->st.st_size > 128 * 1024 * 1024) return -1;
19913 -       
19914 +
19915         buffer_reset(p->ofn);
19916         buffer_copy_string_buffer(p->ofn, p->conf.compress_cache_dir);
19917 -       BUFFER_APPEND_SLASH(p->ofn);
19918 -       
19919 +       PATHNAME_APPEND_SLASH(p->ofn);
19920 +
19921         if (0 == strncmp(con->physical.path->ptr, con->physical.doc_root->ptr, con->physical.doc_root->used-1)) {
19922                 size_t offset = p->ofn->used - 1;
19923                 char *dir, *nextdir;
19924 -               
19925 +
19926                 buffer_append_string(p->ofn, con->physical.path->ptr + con->physical.doc_root->used - 1);
19927 -               
19928 +
19929                 buffer_copy_string_buffer(p->b, p->ofn);
19930 -               
19931 +
19932                 /* mkdir -p ... */
19933                 for (dir = p->b->ptr + offset; NULL != (nextdir = strchr(dir, '/')); dir = nextdir + 1) {
19934                         *nextdir = '\0';
19935 -                       
19936 +
19937                         if (-1 == mkdir(p->b->ptr, 0700)) {
19938                                 if (errno != EEXIST) {
19939                                         log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cache-directory", p->b, "failed", strerror(errno));
19940 -                                       
19941 +
19942                                         return -1;
19943                                 }
19944                         }
19945 -                       
19946 +
19947                         *nextdir = '/';
19948                 }
19949         } else {
19950                 buffer_append_string_buffer(p->ofn, con->uri.path);
19951         }
19952 -       
19953 +
19954         switch(type) {
19955         case HTTP_ACCEPT_ENCODING_GZIP:
19956                 buffer_append_string(p->ofn, "-gzip-");
19957 @@ -381,55 +415,64 @@
19958                 log_error_write(srv, __FILE__, __LINE__, "sd", "unknown compression type", type);
19959                 return -1;
19960         }
19961 -       
19962 +
19963         buffer_append_string_buffer(p->ofn, sce->etag);
19964 -       
19965 +
19966 +
19967 +       if (HANDLER_ERROR != stat_cache_get_entry(srv, con, p->ofn, &compressed_sce)) {
19968 +               /* file exists */
19969 +
19970 +               http_chunk_append_file(srv, con, p->ofn, 0, compressed_sce->st.st_size);
19971 +               con->file_finished = 1;
19972 +
19973 +               return 0;
19974 +       }
19975 +
19976         if (-1 == (ofd = open(p->ofn->ptr, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0600))) {
19977                 if (errno == EEXIST) {
19978                         /* cache-entry exists */
19979 -#if 0
19980 -                       log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache hit");
19981 -#endif
19982 -                       buffer_copy_string_buffer(con->physical.path, p->ofn);
19983 -                       
19984 -                       return 0;
19985 +
19986                 }
19987 -               
19988 -               log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cachefile", p->ofn, "failed", strerror(errno));
19989 -               
19990 +
19991 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
19992 +                               "creating cachefile", p->ofn,
19993 +                               "failed", strerror(errno));
19994 +
19995                 return -1;
19996         }
19997 -#if 0
19998 -       log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache miss");
19999 -#endif 
20000 +
20001         if (-1 == (ifd = open(filename, O_RDONLY | O_BINARY))) {
20002 -               log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-file", fn, "failed", strerror(errno));
20003 -               
20004 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
20005 +                               "opening plain-file", fn,
20006 +                               "failed", strerror(errno));
20007 +
20008                 close(ofd);
20009 -               
20010 +
20011                 return -1;
20012         }
20013 -       
20014 -       
20015 +
20016 +
20017         if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
20018 -               log_error_write(srv, __FILE__, __LINE__, "sbss", "mmaping", fn, "failed", strerror(errno));
20019 -               
20020 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
20021 +                               "mmaping", fn,
20022 +                               "failed", strerror(errno));
20023 +
20024                 close(ofd);
20025                 close(ifd);
20026                 return -1;
20027         }
20028 -       
20029 +
20030         switch(type) {
20031  #ifdef USE_ZLIB
20032 -       case HTTP_ACCEPT_ENCODING_GZIP: 
20033 +       case HTTP_ACCEPT_ENCODING_GZIP:
20034                 ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime);
20035                 break;
20036 -       case HTTP_ACCEPT_ENCODING_DEFLATE: 
20037 +       case HTTP_ACCEPT_ENCODING_DEFLATE:
20038                 ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size);
20039                 break;
20040  #endif
20041  #ifdef USE_BZ2LIB
20042 -       case HTTP_ACCEPT_ENCODING_BZIP2: 
20043 +       case HTTP_ACCEPT_ENCODING_BZIP2:
20044                 ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
20045                 break;
20046  #endif
20047 @@ -437,26 +480,27 @@
20048                 ret = -1;
20049                 break;
20050         }
20051 -       
20052 +
20053         if (-1 == (r = write(ofd, p->b->ptr, p->b->used))) {
20054 -               munmap(start, sce->st.st_size); 
20055 +               munmap(start, sce->st.st_size);
20056                 close(ofd);
20057                 close(ifd);
20058                 return -1;
20059         }
20060 -       
20061 +
20062         if ((size_t)r != p->b->used) {
20063 -               
20064 +
20065         }
20066 -               
20067 +
20068         munmap(start, sce->st.st_size);
20069         close(ofd);
20070         close(ifd);
20071 -       
20072 +
20073         if (ret != 0) return -1;
20074 -       
20075 -       buffer_copy_string_buffer(con->physical.path, p->ofn);
20076 -       
20077 +
20078 +       http_chunk_append_file(srv, con, p->ofn, 0, r);
20079 +       con->file_finished = 1;
20080 +
20081         return 0;
20082  }
20083  
20084 @@ -465,43 +509,44 @@
20085         int ret = -1;
20086         void *start;
20087         buffer *b;
20088 -       
20089 +
20090         /* overflow */
20091         if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
20092 -       
20093 +
20094         /* don't mmap files > 128M
20095 -        * 
20096 +        *
20097          * we could use a sliding window, but currently there is no need for it
20098          */
20099 -       
20100 +
20101         if (sce->st.st_size > 128 * 1024 * 1024) return -1;
20102 -       
20103 -       
20104 +
20105         if (-1 == (ifd = open(fn->ptr, O_RDONLY | O_BINARY))) {
20106                 log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-file", fn, "failed", strerror(errno));
20107 -               
20108 +
20109                 return -1;
20110         }
20111 -       
20112 -       
20113 -       if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
20114 +
20115 +       start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0);
20116 +
20117 +       close(ifd);
20118 +
20119 +       if (MAP_FAILED == start) {
20120                 log_error_write(srv, __FILE__, __LINE__, "sbss", "mmaping", fn, "failed", strerror(errno));
20121 -               
20122 -               close(ifd);
20123 +
20124                 return -1;
20125         }
20126 -       
20127 +
20128         switch(type) {
20129  #ifdef USE_ZLIB
20130 -       case HTTP_ACCEPT_ENCODING_GZIP: 
20131 +       case HTTP_ACCEPT_ENCODING_GZIP:
20132                 ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime);
20133                 break;
20134 -       case HTTP_ACCEPT_ENCODING_DEFLATE: 
20135 +       case HTTP_ACCEPT_ENCODING_DEFLATE:
20136                 ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size);
20137                 break;
20138  #endif
20139  #ifdef USE_BZ2LIB
20140 -       case HTTP_ACCEPT_ENCODING_BZIP2: 
20141 +       case HTTP_ACCEPT_ENCODING_BZIP2:
20142                 ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
20143                 break;
20144  #endif
20145 @@ -509,69 +554,64 @@
20146                 ret = -1;
20147                 break;
20148         }
20149 -               
20150 +
20151         munmap(start, sce->st.st_size);
20152 -       close(ifd);
20153 -       
20154 +
20155         if (ret != 0) return -1;
20156 -       
20157 +
20158         chunkqueue_reset(con->write_queue);
20159         b = chunkqueue_get_append_buffer(con->write_queue);
20160         buffer_copy_memory(b, p->b->ptr, p->b->used + 1);
20161 -       
20162 +
20163         buffer_reset(con->physical.path);
20164 -       
20165 +
20166         con->file_finished = 1;
20167         con->file_started  = 1;
20168 -       
20169 +
20170         return 0;
20171  }
20172  
20173 -
20174 -#define PATCH(x) \
20175 -       p->conf.x = s->x;
20176  static int mod_compress_patch_connection(server *srv, connection *con, plugin_data *p) {
20177         size_t i, j;
20178         plugin_config *s = p->config_storage[0];
20179  
20180 -       PATCH(compress_cache_dir);
20181 -       PATCH(compress);
20182 -       PATCH(compress_max_filesize);
20183 -       
20184 +       PATCH_OPTION(compress_cache_dir);
20185 +       PATCH_OPTION(compress);
20186 +       PATCH_OPTION(compress_max_filesize);
20187 +
20188         /* skip the first, the global context */
20189         for (i = 1; i < srv->config_context->used; i++) {
20190                 data_config *dc = (data_config *)srv->config_context->data[i];
20191                 s = p->config_storage[i];
20192 -               
20193 +
20194                 /* condition didn't match */
20195                 if (!config_check_cond(srv, con, dc)) continue;
20196 -               
20197 +
20198                 /* merge config */
20199                 for (j = 0; j < dc->value->used; j++) {
20200                         data_unset *du = dc->value->data[j];
20201 -                       
20202 +
20203                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.cache-dir"))) {
20204 -                               PATCH(compress_cache_dir);
20205 +                               PATCH_OPTION(compress_cache_dir);
20206                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.filetype"))) {
20207 -                               PATCH(compress);
20208 +                               PATCH_OPTION(compress);
20209                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.max-filesize"))) {
20210 -                               PATCH(compress_max_filesize);
20211 +                               PATCH_OPTION(compress_max_filesize);
20212                         }
20213                 }
20214         }
20215 -       
20216 +
20217         return 0;
20218  }
20219 -#undef PATCH
20220  
20221  PHYSICALPATH_FUNC(mod_compress_physical) {
20222         plugin_data *p = p_d;
20223         size_t m;
20224         off_t max_fsize;
20225         stat_cache_entry *sce = NULL;
20226 -       
20227 +
20228         /* only GET and POST can get compressed */
20229 -       if (con->request.http_method != HTTP_METHOD_GET && 
20230 +       if (con->request.http_method != HTTP_METHOD_GET &&
20231             con->request.http_method != HTTP_METHOD_POST) {
20232                 return HANDLER_GO_ON;
20233         }
20234 @@ -579,46 +619,49 @@
20235         if (buffer_is_empty(con->physical.path)) {
20236                 return HANDLER_GO_ON;
20237         }
20238 -       
20239 +
20240         mod_compress_patch_connection(srv, con, p);
20241 -       
20242 +
20243         max_fsize = p->conf.compress_max_filesize;
20244  
20245         stat_cache_get_entry(srv, con, con->physical.path, &sce);
20246  
20247         /* don't compress files that are too large as we need to much time to handle them */
20248         if (max_fsize && (sce->st.st_size >> 10) > max_fsize) return HANDLER_GO_ON;
20249 -               
20250 +
20251 +       /* compressing the file might lead to larger files instead */
20252 +       if (sce->st.st_size < 128) return HANDLER_GO_ON;
20253 +
20254         /* check if mimetype is in compress-config */
20255         for (m = 0; m < p->conf.compress->used; m++) {
20256                 data_string *compress_ds = (data_string *)p->conf.compress->data[m];
20257 -                       
20258 +
20259                 if (!compress_ds) {
20260                         log_error_write(srv, __FILE__, __LINE__, "sbb", "evil", con->physical.path, con->uri.path);
20261 -                       
20262 +
20263                         return HANDLER_GO_ON;
20264                 }
20265 -               
20266 +
20267                 if (buffer_is_equal(compress_ds->value, sce->content_type)) {
20268                         /* mimetype found */
20269                         data_string *ds;
20270 -                               
20271 +
20272                         /* the response might change according to Accept-Encoding */
20273                         response_header_insert(srv, con, CONST_STR_LEN("Vary"), CONST_STR_LEN("Accept-Encoding"));
20274 -                               
20275 +
20276                         if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Accept-Encoding"))) {
20277                                 int accept_encoding = 0;
20278                                 char *value = ds->value->ptr;
20279                                 int srv_encodings = 0;
20280                                 int matched_encodings = 0;
20281 -                               
20282 +
20283                                 /* get client side support encodings */
20284                                 if (NULL != strstr(value, "gzip")) accept_encoding |= HTTP_ACCEPT_ENCODING_GZIP;
20285                                 if (NULL != strstr(value, "deflate")) accept_encoding |= HTTP_ACCEPT_ENCODING_DEFLATE;
20286                                 if (NULL != strstr(value, "compress")) accept_encoding |= HTTP_ACCEPT_ENCODING_COMPRESS;
20287                                 if (NULL != strstr(value, "bzip2")) accept_encoding |= HTTP_ACCEPT_ENCODING_BZIP2;
20288                                 if (NULL != strstr(value, "identity")) accept_encoding |= HTTP_ACCEPT_ENCODING_IDENTITY;
20289 -                               
20290 +
20291                                 /* get server side supported ones */
20292  #ifdef USE_BZ2LIB
20293                                 srv_encodings |= HTTP_ACCEPT_ENCODING_BZIP2;
20294 @@ -627,18 +670,31 @@
20295                                 srv_encodings |= HTTP_ACCEPT_ENCODING_GZIP;
20296                                 srv_encodings |= HTTP_ACCEPT_ENCODING_DEFLATE;
20297  #endif
20298 -                               
20299 +
20300                                 /* find matching entries */
20301                                 matched_encodings = accept_encoding & srv_encodings;
20302 -                               
20303 +
20304                                 if (matched_encodings) {
20305                                         const char *dflt_gzip = "gzip";
20306                                         const char *dflt_deflate = "deflate";
20307                                         const char *dflt_bzip2 = "bzip2";
20308 -                                       
20309 +
20310                                         const char *compression_name = NULL;
20311                                         int compression_type = 0;
20312 -                                       
20313 +                                       buffer *mtime;
20314 +
20315 +                                       mtime = strftime_cache_get(srv, sce->st.st_mtime);
20316 +                                       etag_mutate(con->physical.etag, sce->etag);
20317 +
20318 +                                       response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
20319 +                                       response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
20320 +
20321 +                                       /* perhaps we don't even have to compress the file as the browser still has the
20322 +                                        * current version */
20323 +                                       if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
20324 +                                               return HANDLER_FINISHED;
20325 +                                       }
20326 +
20327                                         /* select best matching encoding */
20328                                         if (matched_encodings & HTTP_ACCEPT_ENCODING_BZIP2) {
20329                                                 compression_type = HTTP_ACCEPT_ENCODING_BZIP2;
20330 @@ -650,31 +706,21 @@
20331                                                 compression_type = HTTP_ACCEPT_ENCODING_DEFLATE;
20332                                                 compression_name = dflt_deflate;
20333                                         }
20334 -                                       
20335 -                                       /* deflate it */
20336 -                                       if (p->conf.compress_cache_dir->used) {
20337 -                                               if (0 == deflate_file_to_file(srv, con, p,
20338 -                                                                             con->physical.path, sce, compression_type)) {
20339 -                                                       buffer *mtime;
20340 -                                                       
20341 -                                                       response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
20342 -                                                       
20343 -                                                       mtime = strftime_cache_get(srv, sce->st.st_mtime);
20344 -                                                       response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
20345 -
20346 -                                                       etag_mutate(con->physical.etag, sce->etag);
20347 -                                                       response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
20348 -
20349 -                                                       response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
20350 -
20351 -                                                       return HANDLER_GO_ON;
20352 -                                               }
20353 -                                       } else if (0 == deflate_file_to_buffer(srv, con, p,
20354 -                                                                              con->physical.path, sce, compression_type)) {
20355 -                                                       
20356 -                                               response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
20357 -                                               response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
20358 -                                               
20359 +
20360 +                                       /* deflate it to file (cached) or to memory */
20361 +                                       if (0 == deflate_file_to_file(srv, con, p,
20362 +                                                       con->physical.path, sce, compression_type) ||
20363 +                                           0 == deflate_file_to_buffer(srv, con, p,
20364 +                                                       con->physical.path, sce, compression_type)) {
20365 +
20366 +                                               response_header_overwrite(srv, con,
20367 +                                                               CONST_STR_LEN("Content-Encoding"),
20368 +                                                               compression_name, strlen(compression_name));
20369 +
20370 +                                               response_header_overwrite(srv, con,
20371 +                                                               CONST_STR_LEN("Content-Type"),
20372 +                                                               CONST_BUF_LEN(sce->content_type));
20373 +
20374                                                 return HANDLER_FINISHED;
20375                                         }
20376                                         break;
20377 @@ -682,20 +728,20 @@
20378                         }
20379                 }
20380         }
20381 -       
20382 +
20383         return HANDLER_GO_ON;
20384  }
20385  
20386  int mod_compress_plugin_init(plugin *p) {
20387         p->version     = LIGHTTPD_VERSION_ID;
20388         p->name        = buffer_init_string("compress");
20389 -       
20390 +
20391         p->init        = mod_compress_init;
20392         p->set_defaults = mod_compress_setdefaults;
20393         p->handle_subrequest_start  = mod_compress_physical;
20394         p->cleanup     = mod_compress_free;
20395 -       
20396 +
20397         p->data        = NULL;
20398 -       
20399 +
20400         return 0;
20401  }
20402 --- ../lighttpd-1.4.11/src/mod_dirlisting.c     2006-01-13 00:00:45.000000000 +0200
20403 +++ lighttpd-1.4.12/src/mod_dirlisting.c        2006-07-16 00:26:04.000000000 +0300
20404 @@ -1,11 +1,9 @@
20405  #include <ctype.h>
20406  #include <stdlib.h>
20407  #include <string.h>
20408 -#include <dirent.h>
20409  #include <assert.h>
20410  #include <errno.h>
20411  #include <stdio.h>
20412 -#include <unistd.h>
20413  #include <time.h>
20414  
20415  #include "base.h"
20416 @@ -17,6 +15,9 @@
20417  #include "response.h"
20418  #include "stat_cache.h"
20419  #include "stream.h"
20420 +#include "etag.h"
20421 +
20422 +#include "sys-strings.h"
20423  
20424  /**
20425   * this is a dirlisting for a lighttpd plugin
20426 @@ -27,10 +28,13 @@
20427  #include <sys/syslimits.h>
20428  #endif
20429  
20430 -#ifdef HAVE_ATTR_ATTRIBUTES_H
20431 +#ifdef HAVE_XATTR
20432  #include <attr/attributes.h>
20433  #endif
20434  
20435 +#include "sys-files.h"
20436 +#include "sys-strings.h"
20437 +
20438  /* plugin config for all request/connections */
20439  
20440  typedef struct {
20441 @@ -54,7 +58,7 @@
20442         unsigned short hide_readme_file;
20443         unsigned short show_header;
20444         unsigned short hide_header_file;
20445 -       
20446 +
20447         excludes_buffer *excludes;
20448  
20449         buffer *external_css;
20450 @@ -63,13 +67,14 @@
20451  
20452  typedef struct {
20453         PLUGIN_DATA;
20454 -       
20455 +
20456         buffer *tmp_buf;
20457         buffer *content_charset;
20458 -       
20459 +       buffer *path;
20460 +
20461         plugin_config **config_storage;
20462 -       
20463 -       plugin_config conf; 
20464 +
20465 +       plugin_config conf;
20466  } plugin_data;
20467  
20468  excludes_buffer *excludes_buffer_init(void) {
20469 @@ -146,44 +151,46 @@
20470  /* init the plugin data */
20471  INIT_FUNC(mod_dirlisting_init) {
20472         plugin_data *p;
20473 -       
20474 +
20475         p = calloc(1, sizeof(*p));
20476  
20477         p->tmp_buf = buffer_init();
20478         p->content_charset = buffer_init();
20479 -       
20480 +       p->path = buffer_init();
20481 +
20482         return p;
20483  }
20484  
20485  /* detroy the plugin data */
20486  FREE_FUNC(mod_dirlisting_free) {
20487         plugin_data *p = p_d;
20488 -       
20489 +
20490         UNUSED(srv);
20491  
20492         if (!p) return HANDLER_GO_ON;
20493 -       
20494 +
20495         if (p->config_storage) {
20496                 size_t i;
20497                 for (i = 0; i < srv->config_context->used; i++) {
20498                         plugin_config *s = p->config_storage[i];
20499 -                       
20500 +
20501                         if (!s) continue;
20502 -                       
20503 +
20504                         excludes_buffer_free(s->excludes);
20505                         buffer_free(s->external_css);
20506                         buffer_free(s->encoding);
20507 -                       
20508 +
20509                         free(s);
20510                 }
20511                 free(p->config_storage);
20512         }
20513 -       
20514 +
20515         buffer_free(p->tmp_buf);
20516 +       buffer_free(p->path);
20517         buffer_free(p->content_charset);
20518 -       
20519 +
20520         free(p);
20521 -       
20522 +
20523         return HANDLER_GO_ON;
20524  }
20525  
20526 @@ -215,10 +222,10 @@
20527                         if (0 != excludes_buffer_append(s->excludes,
20528                                     ((data_string *)(da->value->data[j]))->value)) {
20529  #ifdef HAVE_PCRE_H
20530 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
20531 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
20532                                                 "pcre-compile failed for", ((data_string *)(da->value->data[j]))->value);
20533  #else
20534 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
20535 +                               log_error_write(srv, __FILE__, __LINE__, "s",
20536                                                 "pcre support is missing, please install libpcre and the headers");
20537  #endif
20538                         }
20539 @@ -233,8 +240,8 @@
20540  SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
20541         plugin_data *p = p_d;
20542         size_t i = 0;
20543 -       
20544 -       config_values_t cv[] = { 
20545 +
20546 +       config_values_t cv[] = {
20547                 { "dir-listing.exclude",          NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },   /* 0 */
20548                 { "dir-listing.activate",         NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
20549                 { "dir-listing.hide-dotfiles",    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
20550 @@ -245,18 +252,18 @@
20551                 { "dir-listing.show-header",      NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
20552                 { "dir-listing.hide-header-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
20553                 { "server.dir-listing",           NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
20554 -               
20555 +
20556                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
20557         };
20558 -       
20559 +
20560         if (!p) return HANDLER_ERROR;
20561 -       
20562 +
20563         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
20564 -       
20565 +
20566         for (i = 0; i < srv->config_context->used; i++) {
20567                 plugin_config *s;
20568                 array *ca;
20569 -               
20570 +
20571                 s = calloc(1, sizeof(plugin_config));
20572                 s->excludes = excludes_buffer_init();
20573                 s->dir_listing = 0;
20574 @@ -267,7 +274,7 @@
20575                 s->show_header = 0;
20576                 s->hide_header_file = 0;
20577                 s->encoding = buffer_init();
20578 -               
20579 +
20580                 cv[0].destination = s->excludes;
20581                 cv[1].destination = &(s->dir_listing);
20582                 cv[2].destination = &(s->hide_dot_files);
20583 @@ -292,60 +299,57 @@
20584         return HANDLER_GO_ON;
20585  }
20586  
20587 -#define PATCH(x) \
20588 -       p->conf.x = s->x;
20589  static int mod_dirlisting_patch_connection(server *srv, connection *con, plugin_data *p) {
20590         size_t i, j;
20591         plugin_config *s = p->config_storage[0];
20592  
20593 -       PATCH(dir_listing);
20594 -       PATCH(external_css);
20595 -       PATCH(hide_dot_files);
20596 -       PATCH(encoding);
20597 -       PATCH(show_readme);
20598 -       PATCH(hide_readme_file);
20599 -       PATCH(show_header);
20600 -       PATCH(hide_header_file);
20601 -       PATCH(excludes);
20602 -       
20603 +       PATCH_OPTION(dir_listing);
20604 +       PATCH_OPTION(external_css);
20605 +       PATCH_OPTION(hide_dot_files);
20606 +       PATCH_OPTION(encoding);
20607 +       PATCH_OPTION(show_readme);
20608 +       PATCH_OPTION(hide_readme_file);
20609 +       PATCH_OPTION(show_header);
20610 +       PATCH_OPTION(hide_header_file);
20611 +       PATCH_OPTION(excludes);
20612 +
20613         /* skip the first, the global context */
20614         for (i = 1; i < srv->config_context->used; i++) {
20615                 data_config *dc = (data_config *)srv->config_context->data[i];
20616                 s = p->config_storage[i];
20617 -               
20618 +
20619                 /* condition didn't match */
20620                 if (!config_check_cond(srv, con, dc)) continue;
20621 -               
20622 +
20623                 /* merge config */
20624                 for (j = 0; j < dc->value->used; j++) {
20625                         data_unset *du = dc->value->data[j];
20626 -                       
20627 +
20628                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.activate")) ||
20629                             buffer_is_equal_string(du->key, CONST_STR_LEN("server.dir-listing"))) {
20630 -                               PATCH(dir_listing);
20631 +                               PATCH_OPTION(dir_listing);
20632                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-dotfiles"))) {
20633 -                               PATCH(hide_dot_files);
20634 +                               PATCH_OPTION(hide_dot_files);
20635                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.external-css"))) {
20636 -                               PATCH(external_css);
20637 +                               PATCH_OPTION(external_css);
20638                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.encoding"))) {
20639 -                               PATCH(encoding);
20640 +                               PATCH_OPTION(encoding);
20641                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-readme"))) {
20642 -                               PATCH(show_readme);
20643 +                               PATCH_OPTION(show_readme);
20644                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-readme-file"))) {
20645 -                               PATCH(hide_readme_file);
20646 +                               PATCH_OPTION(hide_readme_file);
20647                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-header"))) {
20648 -                               PATCH(show_header);
20649 +                               PATCH_OPTION(show_header);
20650                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-header-file"))) {
20651 -                               PATCH(hide_header_file);
20652 +                               PATCH_OPTION(hide_header_file);
20653                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.excludes"))) {
20654 -                               PATCH(excludes);
20655 +                               PATCH_OPTION(excludes);
20656                         }
20657                 }
20658         }
20659 -       
20660 +
20661         return 0;
20662  }
20663 -#undef PATCH
20664  
20665  typedef struct {
20666         size_t  namelen;
20667 @@ -432,7 +436,7 @@
20668  
20669  static void http_list_directory_header(server *srv, connection *con, plugin_data *p, buffer *out) {
20670         UNUSED(srv);
20671 -       
20672 +
20673         BUFFER_APPEND_STRING_CONST(out,
20674                 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
20675                 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n"
20676 @@ -492,11 +496,11 @@
20677         if (p->conf.show_header) {
20678                 stream s;
20679                 /* if we have a HEADER file, display it in <pre class="header"></pre> */
20680 -               
20681 +
20682                 buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
20683 -               BUFFER_APPEND_SLASH(p->tmp_buf);
20684 +               PATHNAME_APPEND_SLASH(p->tmp_buf);
20685                 BUFFER_APPEND_STRING_CONST(p->tmp_buf, "HEADER.txt");
20686 -               
20687 +
20688                 if (-1 != stream_open(&s, p->tmp_buf)) {
20689                         BUFFER_APPEND_STRING_CONST(out, "<pre class=\"header\">");
20690                         buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
20691 @@ -531,21 +535,21 @@
20692  
20693  static void http_list_directory_footer(server *srv, connection *con, plugin_data *p, buffer *out) {
20694         UNUSED(srv);
20695 -       
20696 +
20697         BUFFER_APPEND_STRING_CONST(out,
20698                 "</tbody>\n"
20699                 "</table>\n"
20700                 "</div>\n"
20701         );
20702 -       
20703 +
20704         if (p->conf.show_readme) {
20705                 stream s;
20706                 /* if we have a README file, display it in <pre class="readme"></pre> */
20707 -               
20708 +
20709                 buffer_copy_string_buffer(p->tmp_buf,  con->physical.path);
20710 -               BUFFER_APPEND_SLASH(p->tmp_buf);
20711 +               PATHNAME_APPEND_SLASH(p->tmp_buf);
20712                 BUFFER_APPEND_STRING_CONST(p->tmp_buf, "README.txt");
20713 -               
20714 +
20715                 if (-1 != stream_open(&s, p->tmp_buf)) {
20716                         BUFFER_APPEND_STRING_CONST(out, "<pre class=\"readme\">");
20717                         buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
20718 @@ -553,7 +557,7 @@
20719                 }
20720                 stream_close(&s);
20721         }
20722 -       
20723 +
20724         BUFFER_APPEND_STRING_CONST(out,
20725                 "<div class=\"foot\">"
20726         );
20727 @@ -576,7 +580,6 @@
20728         buffer *out;
20729         struct dirent *dent;
20730         struct stat st;
20731 -       char *path, *path_file;
20732         size_t i;
20733         int hide_dotfiles = p->conf.hide_dot_files;
20734         dirls_list_t dirs, files, *list;
20735 @@ -586,6 +589,7 @@
20736         size_t k;
20737         const char *content_type;
20738         long name_max;
20739 +
20740  #ifdef HAVE_XATTR
20741         char attrval[128];
20742         int attrlen;
20743 @@ -594,10 +598,10 @@
20744         struct tm tm;
20745  #endif
20746  
20747 -       if (dir->used == 0) return -1;
20748 -       
20749 -       i = dir->used - 1;
20750 +       /* empty pathname, never ... */
20751 +       if (buffer_is_empty(dir)) return -1;
20752  
20753 +       /* max-length for the opendir */
20754  #ifdef HAVE_PATHCONF
20755         if (-1 == (name_max = pathconf(dir->ptr, _PC_NAME_MAX))) {
20756  #ifdef NAME_MAX
20757 @@ -606,22 +610,24 @@
20758                 name_max = 256; /* stupid default */
20759  #endif
20760         }
20761 -#elif defined __WIN32
20762 +#elif defined _WIN32
20763         name_max = FILENAME_MAX;
20764  #else
20765         name_max = NAME_MAX;
20766  #endif
20767 -       
20768 -       path = malloc(dir->used + name_max);
20769 -       assert(path);
20770 -       strcpy(path, dir->ptr);
20771 -       path_file = path + i;
20772  
20773 -       if (NULL == (dp = opendir(path))) {
20774 -               log_error_write(srv, __FILE__, __LINE__, "sbs", 
20775 +       buffer_copy_string_buffer(p->path, dir);
20776 +       PATHNAME_APPEND_SLASH(p->path);
20777 +
20778 +#ifdef _WIN32
20779 +       /* append *.* to the path */
20780 +       buffer_append_string(path, "*.*");
20781 +#endif
20782 +
20783 +       if (NULL == (dp = opendir(p->path->ptr))) {
20784 +               log_error_write(srv, __FILE__, __LINE__, "sbs",
20785                         "opendir failed:", dir, strerror(errno));
20786  
20787 -               free(path);
20788                 return -1;
20789         }
20790  
20791 @@ -633,7 +639,7 @@
20792         assert(files.ent);
20793         files.size = DIRLIST_BLOB_SIZE;
20794         files.used = 0;
20795 -       
20796 +
20797         while ((dent = readdir(dp)) != NULL) {
20798                 unsigned short exclude_match = 0;
20799  
20800 @@ -686,15 +692,21 @@
20801  #endif
20802  
20803                 i = strlen(dent->d_name);
20804 -               
20805 +
20806                 /* NOTE: the manual says, d_name is never more than NAME_MAX
20807                  *       so this should actually not be a buffer-overflow-risk
20808                  */
20809                 if (i > (size_t)name_max) continue;
20810 -               
20811 -               memcpy(path_file, dent->d_name, i + 1);
20812 -               if (stat(path, &st) != 0)
20813 +
20814 +               /* build the dirname */
20815 +               buffer_copy_string_buffer(p->path, dir);
20816 +               PATHNAME_APPEND_SLASH(p->path);
20817 +               buffer_append_string(p->path, dent->d_name);
20818 +
20819 +               if (stat(p->path->ptr, &st) != 0) {
20820 +                       fprintf(stderr, "%s.%d: %s, %s\r\n", __FILE__, __LINE__, p->path->ptr, strerror(errno));
20821                         continue;
20822 +               }
20823  
20824                 list = &files;
20825                 if (S_ISDIR(st.st_mode))
20826 @@ -740,7 +752,7 @@
20827  #else
20828                 strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime)));
20829  #endif
20830 -               
20831 +
20832                 BUFFER_APPEND_STRING_CONST(out, "<tr><td class=\"n\"><a href=\"");
20833                 buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART);
20834                 BUFFER_APPEND_STRING_CONST(out, "/\">");
20835 @@ -757,18 +769,22 @@
20836                 tmp = files.ent[i];
20837  
20838                 content_type = NULL;
20839 +
20840  #ifdef HAVE_XATTR
20841 -               
20842                 if (con->conf.use_xattr) {
20843 -                       memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1);
20844 +                       /* build the dirname */
20845 +                       buffer_copy_string_buffer(p->path, dir);
20846 +                       PATHNAME_APPEND_SLASH(p->path);
20847 +                       buffer_append_string_len(p->path, DIRLIST_ENT_NAME(tmp), tmp->namelen);
20848 +
20849                         attrlen = sizeof(attrval) - 1;
20850 -                       if (attr_get(path, "Content-Type", attrval, &attrlen, 0) == 0) {
20851 +                       if (attr_get(p->path->ptr, "Content-Type", attrval, &attrlen, 0) == 0) {
20852                                 attrval[attrlen] = '\0';
20853                                 content_type = attrval;
20854                         }
20855                 }
20856  #endif
20857 -               
20858 +
20859                 if (content_type == NULL) {
20860                         content_type = "application/octet-stream";
20861                         for (k = 0; k < con->conf.mimetypes->used; k++) {
20862 @@ -788,7 +804,7 @@
20863                                 }
20864                         }
20865                 }
20866 -                       
20867 +
20868  #ifdef HAVE_LOCALTIME_R
20869                 localtime_r(&(tmp->mtime), &tm);
20870                 strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm);
20871 @@ -814,7 +830,6 @@
20872  
20873         free(files.ent);
20874         free(dirs.ent);
20875 -       free(path);
20876  
20877         http_list_directory_footer(srv, con, p, out);
20878  
20879 @@ -837,36 +852,55 @@
20880  URIHANDLER_FUNC(mod_dirlisting_subrequest) {
20881         plugin_data *p = p_d;
20882         stat_cache_entry *sce = NULL;
20883 -       
20884 -       UNUSED(srv);
20885 -       
20886 -       if (con->physical.path->used == 0) return HANDLER_GO_ON;
20887 -       if (con->uri.path->used == 0) return HANDLER_GO_ON;
20888 +       buffer *mtime;
20889 +       data_string *ds;
20890 +
20891 +       if (con->uri.path->used < 2) return HANDLER_GO_ON;
20892         if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
20893 -       
20894 +       if (con->physical.path->used == 0) return HANDLER_GO_ON;
20895 +
20896         mod_dirlisting_patch_connection(srv, con, p);
20897  
20898         if (!p->conf.dir_listing) return HANDLER_GO_ON;
20899 -       
20900 +
20901 +       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
20902 +               /* just a second ago the file was still there */
20903 +               return HANDLER_GO_ON;
20904 +       }
20905 +
20906 +       if (!S_ISDIR(sce->st.st_mode)) return HANDLER_GO_ON;
20907 +
20908         if (con->conf.log_request_handling) {
20909                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling the request as Dir-Listing");
20910                 log_error_write(srv, __FILE__, __LINE__,  "sb", "URI          :", con->uri.path);
20911         }
20912 -       
20913 -       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
20914 -               fprintf(stderr, "%s.%d: %s\n", __FILE__, __LINE__, con->physical.path->ptr);
20915 -               SEGFAULT();
20916 +
20917 +       /* perhaps this a cachable request
20918 +        * - we use the etag of the directory
20919 +        * */
20920 +
20921 +       etag_mutate(con->physical.etag, sce->etag);
20922 +       response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
20923 +
20924 +       /* prepare header */
20925 +       if (NULL == (ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"))) {
20926 +               mtime = strftime_cache_get(srv, sce->st.st_mtime);
20927 +               response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
20928 +       } else {
20929 +               mtime = ds->value;
20930         }
20931 -       
20932 -       if (!S_ISDIR(sce->st.st_mode)) return HANDLER_GO_ON;
20933 -       
20934 +
20935 +       if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
20936 +               return HANDLER_FINISHED;
20937 +       }
20938 +
20939         if (http_list_directory(srv, con, p, con->physical.path)) {
20940                 /* dirlisting failed */
20941                 con->http_status = 403;
20942         }
20943 -       
20944 +
20945         buffer_reset(con->physical.path);
20946 -       
20947 +
20948         /* not found */
20949         return HANDLER_FINISHED;
20950  }
20951 @@ -876,13 +910,13 @@
20952  int mod_dirlisting_plugin_init(plugin *p) {
20953         p->version     = LIGHTTPD_VERSION_ID;
20954         p->name        = buffer_init_string("dirlisting");
20955 -       
20956 +
20957         p->init        = mod_dirlisting_init;
20958         p->handle_subrequest_start  = mod_dirlisting_subrequest;
20959         p->set_defaults  = mod_dirlisting_set_defaults;
20960         p->cleanup     = mod_dirlisting_free;
20961 -       
20962 +
20963         p->data        = NULL;
20964 -       
20965 +
20966         return 0;
20967  }
20968 --- ../lighttpd-1.4.11/src/mod_evasive.c        2006-01-04 15:24:51.000000000 +0200
20969 +++ lighttpd-1.4.12/src/mod_evasive.c   2006-07-16 00:26:04.000000000 +0300
20970 @@ -31,100 +31,97 @@
20971  
20972  typedef struct {
20973         PLUGIN_DATA;
20974 -       
20975 +
20976         plugin_config **config_storage;
20977 -       
20978 -       plugin_config conf; 
20979 +
20980 +       plugin_config conf;
20981  } plugin_data;
20982  
20983  INIT_FUNC(mod_evasive_init) {
20984         plugin_data *p;
20985 -       
20986 +
20987         p = calloc(1, sizeof(*p));
20988 -       
20989 +
20990         return p;
20991  }
20992  
20993  FREE_FUNC(mod_evasive_free) {
20994         plugin_data *p = p_d;
20995 -       
20996 +
20997         UNUSED(srv);
20998  
20999         if (!p) return HANDLER_GO_ON;
21000 -       
21001 +
21002         if (p->config_storage) {
21003                 size_t i;
21004                 for (i = 0; i < srv->config_context->used; i++) {
21005                         plugin_config *s = p->config_storage[i];
21006 -                                               
21007 +
21008                         free(s);
21009                 }
21010                 free(p->config_storage);
21011         }
21012 -       
21013 +
21014         free(p);
21015 -       
21016 +
21017         return HANDLER_GO_ON;
21018  }
21019  
21020  SETDEFAULTS_FUNC(mod_evasive_set_defaults) {
21021         plugin_data *p = p_d;
21022         size_t i = 0;
21023 -       
21024 -       config_values_t cv[] = { 
21025 +
21026 +       config_values_t cv[] = {
21027                 { "evasive.max-conns-per-ip",    NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
21028                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
21029         };
21030 -       
21031 +
21032         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
21033 -       
21034 +
21035         for (i = 0; i < srv->config_context->used; i++) {
21036                 plugin_config *s;
21037 -               
21038 +
21039                 s = calloc(1, sizeof(plugin_config));
21040                 s->max_conns       = 0;
21041 -               
21042 +
21043                 cv[0].destination = &(s->max_conns);
21044 -               
21045 +
21046                 p->config_storage[i] = s;
21047 -       
21048 +
21049                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
21050                         return HANDLER_ERROR;
21051                 }
21052         }
21053 -       
21054 +
21055         return HANDLER_GO_ON;
21056  }
21057  
21058 -#define PATCH(x) \
21059 -       p->conf.x = s->x;
21060  static int mod_evasive_patch_connection(server *srv, connection *con, plugin_data *p) {
21061         size_t i, j;
21062         plugin_config *s = p->config_storage[0];
21063  
21064 -       PATCH(max_conns);
21065 -       
21066 +       PATCH_OPTION(max_conns);
21067 +
21068         /* skip the first, the global context */
21069         for (i = 1; i < srv->config_context->used; i++) {
21070                 data_config *dc = (data_config *)srv->config_context->data[i];
21071                 s = p->config_storage[i];
21072 -               
21073 +
21074                 /* condition didn't match */
21075                 if (!config_check_cond(srv, con, dc)) continue;
21076 -               
21077 +
21078                 /* merge config */
21079                 for (j = 0; j < dc->value->used; j++) {
21080                         data_unset *du = dc->value->data[j];
21081 -                       
21082 +
21083                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("evasive.max-conns-per-ip"))) {
21084 -                               PATCH(max_conns);
21085 +                               PATCH_OPTION(max_conns);
21086                         }
21087                 }
21088         }
21089 -       
21090 +
21091         return 0;
21092  }
21093 -#undef PATCH
21094  
21095  URIHANDLER_FUNC(mod_evasive_uri_handler) {
21096         plugin_data *p = p_d;
21097 @@ -132,10 +129,10 @@
21098         size_t j;
21099  
21100         if (con->uri.path->used == 0) return HANDLER_GO_ON;
21101 -       
21102 +
21103         mod_evasive_patch_connection(srv, con, p);
21104 -       
21105 -       /* no limit set, nothing to block */    
21106 +
21107 +       /* no limit set, nothing to block */
21108         if (p->conf.max_conns == 0) return HANDLER_GO_ON;
21109  
21110         for (j = 0; j < srv->conns->used; j++) {
21111 @@ -147,7 +144,7 @@
21112                 if (c->dst_addr.ipv4.sin_addr.s_addr == con->dst_addr.ipv4.sin_addr.s_addr &&
21113                     c->state > CON_STATE_REQUEST_END) {
21114                         conns_by_ip++;
21115 -       
21116 +
21117                         if (conns_by_ip > p->conf.max_conns) {
21118                                 log_error_write(srv, __FILE__, __LINE__, "ss",
21119                                         inet_ntop_cache_get_ip(srv, &(con->dst_addr)),
21120 @@ -158,7 +155,7 @@
21121                         }
21122                 }
21123         }
21124 -       
21125 +
21126         return HANDLER_GO_ON;
21127  }
21128  
21129 @@ -166,13 +163,13 @@
21130  int mod_evasive_plugin_init(plugin *p) {
21131         p->version     = LIGHTTPD_VERSION_ID;
21132         p->name        = buffer_init_string("evasive");
21133 -       
21134 +
21135         p->init        = mod_evasive_init;
21136         p->set_defaults = mod_evasive_set_defaults;
21137         p->handle_uri_clean  = mod_evasive_uri_handler;
21138         p->cleanup     = mod_evasive_free;
21139 -       
21140 +
21141         p->data        = NULL;
21142 -       
21143 +
21144         return 0;
21145  }
21146 --- ../lighttpd-1.4.11/src/mod_evhost.c 2005-08-17 10:42:03.000000000 +0300
21147 +++ lighttpd-1.4.12/src/mod_evhost.c    2006-07-16 00:26:03.000000000 +0300
21148 @@ -7,10 +7,12 @@
21149  #include "response.h"
21150  #include "stat_cache.h"
21151  
21152 +#include "sys-files.h"
21153 +
21154  typedef struct {
21155         /* unparsed pieces */
21156         buffer *path_pieces_raw;
21157 -       
21158 +
21159         /* pieces for path creation */
21160         size_t len;
21161         buffer **path_pieces;
21162 @@ -21,14 +23,14 @@
21163         buffer *tmp_buf;
21164  
21165         plugin_config **config_storage;
21166 -       plugin_config conf; 
21167 +       plugin_config conf;
21168  } plugin_data;
21169  
21170  INIT_FUNC(mod_evhost_init) {
21171         plugin_data *p;
21172 -       
21173 +
21174         p = calloc(1, sizeof(*p));
21175 -       
21176 +
21177         p->tmp_buf = buffer_init();
21178  
21179         return p;
21180 @@ -36,34 +38,34 @@
21181  
21182  FREE_FUNC(mod_evhost_free) {
21183         plugin_data *p = p_d;
21184 -       
21185 +
21186         UNUSED(srv);
21187  
21188         if (!p) return HANDLER_GO_ON;
21189 -       
21190 +
21191         if (p->config_storage) {
21192                 size_t i;
21193                 for (i = 0; i < srv->config_context->used; i++) {
21194                         plugin_config *s = p->config_storage[i];
21195  
21196                         if (!s) continue;
21197 -                       
21198 +
21199                         if(s->path_pieces) {
21200                                 size_t j;
21201                                 for (j = 0; j < s->len; j++) {
21202                                         buffer_free(s->path_pieces[j]);
21203                                 }
21204 -                               
21205 +
21206                                 free(s->path_pieces);
21207                         }
21208 -                       
21209 +
21210                         buffer_free(s->path_pieces_raw);
21211 -                       
21212 +
21213                         free(s);
21214                 }
21215                 free(p->config_storage);
21216         }
21217 -       
21218 +
21219         buffer_free(p->tmp_buf);
21220  
21221         free(p);
21222 @@ -73,30 +75,30 @@
21223  
21224  static void mod_evhost_parse_pattern(plugin_config *s) {
21225         char *ptr = s->path_pieces_raw->ptr,*pos;
21226 -       
21227 +
21228         s->path_pieces = NULL;
21229 -       
21230 +
21231         for(pos=ptr;*ptr;ptr++) {
21232                 if(*ptr == '%') {
21233                         s->path_pieces = realloc(s->path_pieces,(s->len+2) * sizeof(*s->path_pieces));
21234                         s->path_pieces[s->len] = buffer_init();
21235                         s->path_pieces[s->len+1] = buffer_init();
21236 -                       
21237 +
21238                         buffer_copy_string_len(s->path_pieces[s->len],pos,ptr-pos);
21239                         pos = ptr + 2;
21240 -                       
21241 +
21242                         buffer_copy_string_len(s->path_pieces[s->len+1],ptr++,2);
21243 -                       
21244 +
21245                         s->len += 2;
21246                 }
21247         }
21248 -       
21249 +
21250         if(*pos != '\0') {
21251                 s->path_pieces = realloc(s->path_pieces,(s->len+1) * sizeof(*s->path_pieces));
21252                 s->path_pieces[s->len] = buffer_init();
21253 -               
21254 +
21255                 buffer_append_memory(s->path_pieces[s->len],pos,ptr-pos);
21256 -               
21257 +
21258                 s->len += 1;
21259         }
21260  }
21261 @@ -104,9 +106,9 @@
21262  SETDEFAULTS_FUNC(mod_evhost_set_defaults) {
21263         plugin_data *p = p_d;
21264         size_t i;
21265 -       
21266 +
21267         /**
21268 -        * 
21269 +        *
21270          * #
21271          * # define a pattern for the host url finding
21272          * # %% => % sign
21273 @@ -117,39 +119,39 @@
21274          * # %4 => subdomain 2 name
21275          * #
21276          * evhost.path-pattern = "/home/ckruse/dev/www/%3/htdocs/"
21277 -        * 
21278 +        *
21279          */
21280 -       
21281 -       config_values_t cv[] = { 
21282 +
21283 +       config_values_t cv[] = {
21284                 { "evhost.path-pattern",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
21285                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
21286         };
21287 -       
21288 +
21289         if (!p) return HANDLER_ERROR;
21290 -       
21291 +
21292         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
21293 -       
21294 +
21295         for (i = 0; i < srv->config_context->used; i++) {
21296                 plugin_config *s;
21297 -               
21298 +
21299                 s = calloc(1, sizeof(plugin_config));
21300                 s->path_pieces_raw = buffer_init();
21301                 s->path_pieces     = NULL;
21302                 s->len             = 0;
21303 -       
21304 +
21305                 cv[0].destination = s->path_pieces_raw;
21306 -               
21307 +
21308                 p->config_storage[i] = s;
21309 -               
21310 +
21311                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value,  cv)) {
21312                         return HANDLER_ERROR;
21313                 }
21314 -               
21315 +
21316                 if (s->path_pieces_raw->used != 0) {
21317                         mod_evhost_parse_pattern(s);
21318                 }
21319         }
21320 -       
21321 +
21322         return HANDLER_GO_ON;
21323  }
21324  
21325 @@ -158,7 +160,7 @@
21326   * - %0 - full hostname (authority w/o port)
21327   * - %1 - tld
21328   * - %2 - domain.tld
21329 - * - %3 - 
21330 + * - %3 -
21331   */
21332  
21333  static int mod_evhost_parse_host(connection *con,array *host) {
21334 @@ -168,7 +170,7 @@
21335         int first = 1;
21336         data_string *ds;
21337         int i;
21338 -       
21339 +
21340         /* first, find the domain + tld */
21341         for(;ptr > con->uri.authority->ptr;ptr--) {
21342                 if(*ptr == '.') {
21343 @@ -179,18 +181,18 @@
21344                         first = 1;
21345                 }
21346         }
21347 -       
21348 +
21349         ds = data_string_init();
21350         buffer_copy_string(ds->key,"%0");
21351 -       
21352 +
21353         /* if we stopped at a dot, skip the dot */
21354         if (*ptr == '.') ptr++;
21355         buffer_copy_string_len(ds->value, ptr, colon-ptr);
21356 -       
21357 +
21358         array_insert_unique(host,(data_unset *)ds);
21359 -       
21360 +
21361         /* if the : is not the start of the authority, go on parsing the hostname */
21362 -       
21363 +
21364         if (colon != con->uri.authority->ptr) {
21365                 for(ptr = colon - 1, i = 1; ptr > con->uri.authority->ptr; ptr--) {
21366                         if(*ptr == '.') {
21367 @@ -200,59 +202,55 @@
21368                                         buffer_copy_string(ds->key,"%");
21369                                         buffer_append_long(ds->key, i++);
21370                                         buffer_copy_string_len(ds->value,ptr+1,colon-ptr-1);
21371 -                                       
21372 +
21373                                         array_insert_unique(host,(data_unset *)ds);
21374                                 }
21375                                 colon = ptr;
21376                         }
21377                 }
21378 -               
21379 +
21380                 /* if the . is not the first charactor of the hostname */
21381                 if (colon != ptr) {
21382                         ds = data_string_init();
21383                         buffer_copy_string(ds->key,"%");
21384                         buffer_append_long(ds->key, i++);
21385                         buffer_copy_string_len(ds->value,ptr,colon-ptr);
21386 -                       
21387 +
21388                         array_insert_unique(host,(data_unset *)ds);
21389                 }
21390         }
21391 -       
21392 +
21393         return 0;
21394  }
21395  
21396 -#define PATCH(x) \
21397 -       p->conf.x = s->x;
21398  static int mod_evhost_patch_connection(server *srv, connection *con, plugin_data *p) {
21399         size_t i, j;
21400         plugin_config *s = p->config_storage[0];
21401 -       
21402 -       PATCH(path_pieces);
21403 -       PATCH(len);
21404 -       
21405 +
21406 +       PATCH_OPTION(path_pieces);
21407 +       PATCH_OPTION(len);
21408 +
21409         /* skip the first, the global context */
21410         for (i = 1; i < srv->config_context->used; i++) {
21411                 data_config *dc = (data_config *)srv->config_context->data[i];
21412                 s = p->config_storage[i];
21413 -               
21414 +
21415                 /* condition didn't match */
21416                 if (!config_check_cond(srv, con, dc)) continue;
21417 -               
21418 +
21419                 /* merge config */
21420                 for (j = 0; j < dc->value->used; j++) {
21421                         data_unset *du = dc->value->data[j];
21422 -                       
21423 +
21424                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("evhost.path-pattern"))) {
21425 -                               PATCH(path_pieces);
21426 -                               PATCH(len);
21427 +                               PATCH_OPTION(path_pieces);
21428 +                               PATCH_OPTION(len);
21429                         }
21430                 }
21431         }
21432 -       
21433 +
21434         return 0;
21435  }
21436 -#undef PATCH
21437 -
21438  
21439  static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d) {
21440         plugin_data *p = p_d;
21441 @@ -261,29 +259,29 @@
21442         register char *ptr;
21443         int not_good = 0;
21444         stat_cache_entry *sce = NULL;
21445 -       
21446 +
21447         /* not authority set */
21448         if (con->uri.authority->used == 0) return HANDLER_GO_ON;
21449 -       
21450 +
21451         mod_evhost_patch_connection(srv, con, p);
21452 -       
21453 +
21454         /* missing even default(global) conf */
21455         if (0 == p->conf.len) {
21456                 return HANDLER_GO_ON;
21457         }
21458  
21459         parsed_host = array_init();
21460 -       
21461 +
21462         mod_evhost_parse_host(con, parsed_host);
21463 -       
21464 +
21465         /* build document-root */
21466         buffer_reset(p->tmp_buf);
21467 -       
21468 +
21469         for (i = 0; i < p->conf.len; i++) {
21470                 ptr = p->conf.path_pieces[i]->ptr;
21471                 if (*ptr == '%') {
21472                         data_string *ds;
21473 -                       
21474 +
21475                         if (*(ptr+1) == '%') {
21476                                 /* %% */
21477                                 BUFFER_APPEND_STRING_CONST(p->tmp_buf,"%");
21478 @@ -298,11 +296,11 @@
21479                         buffer_append_string_buffer(p->tmp_buf,p->conf.path_pieces[i]);
21480                 }
21481         }
21482 -       
21483 -       BUFFER_APPEND_SLASH(p->tmp_buf);
21484 -       
21485 +
21486 +       PATHNAME_APPEND_SLASH(p->tmp_buf);
21487 +
21488         array_free(parsed_host);
21489 -       
21490 +
21491         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
21492                 log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
21493                 not_good = 1;
21494 @@ -310,11 +308,11 @@
21495                 log_error_write(srv, __FILE__, __LINE__, "sb", "not a directory:", p->tmp_buf);
21496                 not_good = 1;
21497         }
21498 -       
21499 +
21500         if (!not_good) {
21501                 buffer_copy_string_buffer(con->physical.doc_root, p->tmp_buf);
21502         }
21503 -       
21504 +
21505         return HANDLER_GO_ON;
21506  }
21507  
21508 @@ -325,9 +323,9 @@
21509         p->set_defaults            = mod_evhost_set_defaults;
21510         p->handle_docroot          = mod_evhost_uri_handler;
21511         p->cleanup                 = mod_evhost_free;
21512 -       
21513 +
21514         p->data                    = NULL;
21515 -       
21516 +
21517         return 0;
21518  }
21519  
21520 --- ../lighttpd-1.4.11/src/mod_expire.c 2005-11-03 09:52:13.000000000 +0200
21521 +++ lighttpd-1.4.12/src/mod_expire.c    2006-07-16 00:26:04.000000000 +0300
21522 @@ -12,8 +12,8 @@
21523  #include "stat_cache.h"
21524  
21525  /**
21526 - * this is a expire module for a lighttpd 
21527 - * 
21528 + * this is a expire module for a lighttpd
21529 + *
21530   * set 'Expires:' HTTP Headers on demand
21531   */
21532  
21533 @@ -27,51 +27,51 @@
21534  
21535  typedef struct {
21536         PLUGIN_DATA;
21537 -       
21538 +
21539         buffer *expire_tstmp;
21540 -       
21541 +
21542         plugin_config **config_storage;
21543 -       
21544 -       plugin_config conf; 
21545 +
21546 +       plugin_config conf;
21547  } plugin_data;
21548  
21549  /* init the plugin data */
21550  INIT_FUNC(mod_expire_init) {
21551         plugin_data *p;
21552 -       
21553 +
21554         p = calloc(1, sizeof(*p));
21555 -       
21556 +
21557         p->expire_tstmp = buffer_init();
21558 -       
21559 +
21560         buffer_prepare_copy(p->expire_tstmp, 255);
21561 -       
21562 +
21563         return p;
21564  }
21565  
21566  /* detroy the plugin data */
21567  FREE_FUNC(mod_expire_free) {
21568         plugin_data *p = p_d;
21569 -       
21570 +
21571         UNUSED(srv);
21572  
21573         if (!p) return HANDLER_GO_ON;
21574 -       
21575 +
21576         buffer_free(p->expire_tstmp);
21577 -       
21578 +
21579         if (p->config_storage) {
21580                 size_t i;
21581                 for (i = 0; i < srv->config_context->used; i++) {
21582                         plugin_config *s = p->config_storage[i];
21583 -                       
21584 +
21585                         array_free(s->expire_url);
21586 -                       
21587 +
21588                         free(s);
21589                 }
21590                 free(p->config_storage);
21591         }
21592 -       
21593 +
21594         free(p);
21595 -       
21596 +
21597         return HANDLER_GO_ON;
21598  }
21599  
21600 @@ -79,25 +79,25 @@
21601         char *ts;
21602         int type = -1;
21603         int retts = 0;
21604 -               
21605 +
21606         UNUSED(p);
21607  
21608 -       /* 
21609 +       /*
21610          * parse
21611 -        * 
21612 +        *
21613          * '(access|modification) [plus] {<num> <type>}*'
21614 -        * 
21615 +        *
21616          * e.g. 'access 1 years'
21617          */
21618 -       
21619 +
21620         if (expire->used == 0) {
21621 -               log_error_write(srv, __FILE__, __LINE__, "s", 
21622 +               log_error_write(srv, __FILE__, __LINE__, "s",
21623                                 "empty:");
21624                 return -1;
21625         }
21626 -       
21627 +
21628         ts = expire->ptr;
21629 -       
21630 +
21631         if (0 == strncmp(ts, "access ", 7)) {
21632                 type  = 0;
21633                 ts   += 7;
21634 @@ -110,39 +110,39 @@
21635                                 "invalid <base>:", ts);
21636                 return -1;
21637         }
21638 -       
21639 +
21640         if (0 == strncmp(ts, "plus ", 5)) {
21641                 /* skip the optional plus */
21642                 ts   += 5;
21643         }
21644 -       
21645 +
21646         /* the rest is just <number> (years|months|days|hours|minutes|seconds) */
21647         while (1) {
21648                 char *space, *err;
21649                 int num;
21650 -               
21651 +
21652                 if (NULL == (space = strchr(ts, ' '))) {
21653 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
21654 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
21655                                         "missing space after <num>:", ts);
21656                         return -1;
21657                 }
21658 -               
21659 +
21660                 num = strtol(ts, &err, 10);
21661                 if (*err != ' ') {
21662 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
21663 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
21664                                         "missing <type> after <num>:", ts);
21665                         return -1;
21666                 }
21667 -               
21668 +
21669                 ts = space + 1;
21670 -               
21671 +
21672                 if (NULL != (space = strchr(ts, ' '))) {
21673                         int slen;
21674                         /* */
21675 -                       
21676 +
21677                         slen = space - ts;
21678 -                       
21679 -                       if (slen == 5 && 
21680 +
21681 +                       if (slen == 5 &&
21682                             0 == strncmp(ts, "years", slen)) {
21683                                 num *= 60 * 60 * 24 * 30 * 12;
21684                         } else if (slen == 6 &&
21685 @@ -161,13 +161,13 @@
21686                                    0 == strncmp(ts, "seconds", slen)) {
21687                                 num *= 1;
21688                         } else {
21689 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
21690 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
21691                                                 "unknown type:", ts);
21692                                 return -1;
21693                         }
21694 -                       
21695 +
21696                         retts += num;
21697 -                       
21698 +
21699                         ts = space + 1;
21700                 } else {
21701                         if (0 == strcmp(ts, "years")) {
21702 @@ -183,19 +183,19 @@
21703                         } else if (0 == strcmp(ts, "seconds")) {
21704                                 num *= 1;
21705                         } else {
21706 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
21707 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
21708                                                 "unknown type:", ts);
21709                                 return -1;
21710                         }
21711 -                       
21712 +
21713                         retts += num;
21714 -                       
21715 +
21716                         break;
21717                 }
21718         }
21719 -       
21720 +
21721         if (offset != NULL) *offset = retts;
21722 -       
21723 +
21724         return type;
21725  }
21726  
21727 @@ -205,102 +205,99 @@
21728  SETDEFAULTS_FUNC(mod_expire_set_defaults) {
21729         plugin_data *p = p_d;
21730         size_t i = 0, k;
21731 -       
21732 -       config_values_t cv[] = { 
21733 +
21734 +       config_values_t cv[] = {
21735                 { "expire.url",                 NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
21736                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
21737         };
21738 -       
21739 +
21740         if (!p) return HANDLER_ERROR;
21741 -       
21742 +
21743         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
21744 -       
21745 +
21746         for (i = 0; i < srv->config_context->used; i++) {
21747                 plugin_config *s;
21748 -               
21749 +
21750                 s = calloc(1, sizeof(plugin_config));
21751                 s->expire_url    = array_init();
21752 -               
21753 +
21754                 cv[0].destination = s->expire_url;
21755 -               
21756 +
21757                 p->config_storage[i] = s;
21758 -       
21759 +
21760                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
21761                         return HANDLER_ERROR;
21762                 }
21763 -       
21764 +
21765                 for (k = 0; k < s->expire_url->used; k++) {
21766                         data_string *ds = (data_string *)s->expire_url->data[k];
21767 -                       
21768 +
21769                         /* parse lines */
21770                         if (-1 == mod_expire_get_offset(srv, p, ds->value, NULL)) {
21771 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
21772 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
21773                                                 "parsing expire.url failed:", ds->value);
21774                                 return HANDLER_ERROR;
21775                         }
21776                 }
21777         }
21778 -       
21779 -       
21780 +
21781 +
21782         return HANDLER_GO_ON;
21783  }
21784  
21785 -#define PATCH(x) \
21786 -       p->conf.x = s->x;
21787  static int mod_expire_patch_connection(server *srv, connection *con, plugin_data *p) {
21788         size_t i, j;
21789         plugin_config *s = p->config_storage[0];
21790 -       
21791 -       PATCH(expire_url);
21792 -       
21793 +
21794 +       PATCH_OPTION(expire_url);
21795 +
21796         /* skip the first, the global context */
21797         for (i = 1; i < srv->config_context->used; i++) {
21798                 data_config *dc = (data_config *)srv->config_context->data[i];
21799                 s = p->config_storage[i];
21800 -               
21801 +
21802                 /* condition didn't match */
21803                 if (!config_check_cond(srv, con, dc)) continue;
21804 -               
21805 +
21806                 /* merge config */
21807                 for (j = 0; j < dc->value->used; j++) {
21808                         data_unset *du = dc->value->data[j];
21809 -                       
21810 +
21811                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("expire.url"))) {
21812 -                               PATCH(expire_url);
21813 +                               PATCH_OPTION(expire_url);
21814                         }
21815                 }
21816         }
21817 -       
21818 +
21819         return 0;
21820  }
21821 -#undef PATCH
21822  
21823  URIHANDLER_FUNC(mod_expire_path_handler) {
21824         plugin_data *p = p_d;
21825         int s_len;
21826         size_t k;
21827 -       
21828 +
21829         if (con->uri.path->used == 0) return HANDLER_GO_ON;
21830 -       
21831 +
21832         mod_expire_patch_connection(srv, con, p);
21833 -       
21834 +
21835         s_len = con->uri.path->used - 1;
21836 -       
21837 +
21838         for (k = 0; k < p->conf.expire_url->used; k++) {
21839                 data_string *ds = (data_string *)p->conf.expire_url->data[k];
21840                 int ct_len = ds->key->used - 1;
21841 -               
21842 +
21843                 if (ct_len > s_len) continue;
21844                 if (ds->key->used == 0) continue;
21845 -               
21846 +
21847                 if (0 == strncmp(con->uri.path->ptr, ds->key->ptr, ct_len)) {
21848                         int ts;
21849                         time_t t;
21850                         size_t len;
21851                         stat_cache_entry *sce = NULL;
21852 -               
21853 +
21854                         stat_cache_get_entry(srv, con, con->physical.path, &sce);
21855 -                       
21856 +
21857                         switch(mod_expire_get_offset(srv, p, ds->value, &ts)) {
21858                         case 0:
21859                                 /* access */
21860 @@ -308,38 +305,38 @@
21861                                 break;
21862                         case 1:
21863                                 /* modification */
21864 -                               
21865 +
21866                                 t = (ts + sce->st.st_mtime);
21867                                 break;
21868                         default:
21869                                 /* -1 is handled at parse-time */
21870                                 break;
21871                         }
21872 -                       
21873 -                       
21874 -                       if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1, 
21875 +
21876 +
21877 +                       if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1,
21878                                            "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(t))))) {
21879                                 /* could not set expire header, out of mem */
21880 -                               
21881 +
21882                                 return HANDLER_GO_ON;
21883 -                               
21884 +
21885                         }
21886 -                           
21887 +
21888                         p->expire_tstmp->used = len + 1;
21889 -               
21890 -                       /* HTTP/1.0 */  
21891 +
21892 +                       /* HTTP/1.0 */
21893                         response_header_overwrite(srv, con, CONST_STR_LEN("Expires"), CONST_BUF_LEN(p->expire_tstmp));
21894  
21895 -                       /* HTTP/1.1 */  
21896 +                       /* HTTP/1.1 */
21897                         buffer_copy_string(p->expire_tstmp, "max-age=");
21898                         buffer_append_long(p->expire_tstmp, ts);
21899 -                       
21900 +
21901                         response_header_overwrite(srv, con, CONST_STR_LEN("Cache-Control"), CONST_BUF_LEN(p->expire_tstmp));
21902 -                       
21903 +
21904                         return HANDLER_GO_ON;
21905                 }
21906         }
21907 -       
21908 +
21909         /* not found */
21910         return HANDLER_GO_ON;
21911  }
21912 @@ -349,13 +346,13 @@
21913  int mod_expire_plugin_init(plugin *p) {
21914         p->version     = LIGHTTPD_VERSION_ID;
21915         p->name        = buffer_init_string("expire");
21916 -       
21917 +
21918         p->init        = mod_expire_init;
21919         p->handle_subrequest_start = mod_expire_path_handler;
21920         p->set_defaults  = mod_expire_set_defaults;
21921         p->cleanup     = mod_expire_free;
21922 -       
21923 +
21924         p->data        = NULL;
21925 -       
21926 +
21927         return 0;
21928  }
21929 --- ../lighttpd-1.4.11/src/mod_fastcgi.c        2006-03-09 13:18:39.000000000 +0200
21930 +++ lighttpd-1.4.12/src/mod_fastcgi.c   2006-07-18 13:03:40.000000000 +0300
21931 @@ -1,5 +1,4 @@
21932  #include <sys/types.h>
21933 -#include <unistd.h>
21934  #include <errno.h>
21935  #include <fcntl.h>
21936  #include <string.h>
21937 @@ -24,7 +23,7 @@
21938  #include "inet_ntop_cache.h"
21939  #include "stat_cache.h"
21940  
21941 -#include <fastcgi.h>
21942 +#include "fastcgi.h"
21943  #include <stdio.h>
21944  
21945  #ifdef HAVE_SYS_FILIO_H
21946 @@ -32,7 +31,11 @@
21947  #endif
21948  
21949  #include "sys-socket.h"
21950 +#include "sys-files.h"
21951 +#include "sys-strings.h"
21952 +#include "sys-process.h"
21953  
21954 +#include "http_resp.h"
21955  
21956  #ifndef UNIX_PATH_MAX
21957  # define UNIX_PATH_MAX 108
21958 @@ -45,14 +48,13 @@
21959  #include <sys/wait.h>
21960  #endif
21961  
21962 -
21963  /*
21964 - * 
21965 + *
21966   * TODO:
21967 - * 
21968 + *
21969   * - add timeout for a connect to a non-fastcgi process
21970   *   (use state_timestamp + state)
21971 - * 
21972 + *
21973   */
21974  
21975  typedef struct fcgi_proc {
21976 @@ -61,7 +63,7 @@
21977         unsigned port;  /* config.port + pno */
21978  
21979         buffer *connection_name; /* either tcp:<host>:<port> or unix:<socket> for debuggin purposes */
21980 -       
21981 +
21982         pid_t pid;   /* PID of the spawned process (0 if not spawned locally) */
21983  
21984  
21985 @@ -70,20 +72,20 @@
21986         time_t last_used; /* see idle_timeout */
21987         size_t requests;  /* see max_requests */
21988         struct fcgi_proc *prev, *next; /* see first */
21989 -       
21990 +
21991         time_t disabled_until; /* this proc is disabled until, use something else until than */
21992 -       
21993 +
21994         int is_local;
21995  
21996 -       enum { 
21997 +       enum {
21998                 PROC_STATE_UNSET,    /* init-phase */
21999                 PROC_STATE_RUNNING,  /* alive */
22000 -               PROC_STATE_OVERLOADED, /* listen-queue is full, 
22001 +               PROC_STATE_OVERLOADED, /* listen-queue is full,
22002                                           don't send something to this proc for the next 2 seconds */
22003                 PROC_STATE_DIED_WAIT_FOR_PID, /* */
22004                 PROC_STATE_DIED,     /* marked as dead, should be restarted */
22005                 PROC_STATE_KILLED    /* was killed as we don't have the load anymore */
22006 -       } state; 
22007 +       } state;
22008  } fcgi_proc;
22009  
22010  typedef struct {
22011 @@ -94,20 +96,20 @@
22012          * sorted by lowest load
22013          *
22014          * whenever a job is done move it up in the list
22015 -        * until it is sorted, move it down as soon as the 
22016 +        * until it is sorted, move it down as soon as the
22017          * job is started
22018          */
22019 -       fcgi_proc *first; 
22020 -       fcgi_proc *unused_procs; 
22021 +       fcgi_proc *first;
22022 +       fcgi_proc *unused_procs;
22023  
22024 -       /* 
22025 +       /*
22026          * spawn at least min_procs, at max_procs.
22027          *
22028 -        * as soon as the load of the first entry 
22029 +        * as soon as the load of the first entry
22030          * is max_load_per_proc we spawn a new one
22031 -        * and add it to the first entry and give it 
22032 +        * and add it to the first entry and give it
22033          * the load
22034 -        * 
22035 +        *
22036          */
22037  
22038         unsigned short min_procs;
22039 @@ -119,44 +121,44 @@
22040  
22041         /*
22042          * kick the process from the list if it was not
22043 -        * used for idle_timeout until min_procs is 
22044 +        * used for idle_timeout until min_procs is
22045          * reached. this helps to get the processlist
22046          * small again we had a small peak load.
22047          *
22048          */
22049 -       
22050 +
22051         unsigned short idle_timeout;
22052 -       
22053 +
22054         /*
22055          * time after a disabled remote connection is tried to be re-enabled
22056 -        * 
22057 -        * 
22058 +        *
22059 +        *
22060          */
22061 -       
22062 +
22063         unsigned short disable_time;
22064  
22065         /*
22066          * same fastcgi processes get a little bit larger
22067 -        * than wanted. max_requests_per_proc kills a 
22068 +        * than wanted. max_requests_per_proc kills a
22069          * process after a number of handled requests.
22070          *
22071          */
22072         size_t max_requests_per_proc;
22073 -       
22074 +
22075  
22076         /* config */
22077  
22078 -       /* 
22079 -        * host:port 
22080 +       /*
22081 +        * host:port
22082          *
22083 -        * if host is one of the local IP adresses the 
22084 +        * if host is one of the local IP adresses the
22085          * whole connection is local
22086          *
22087          * if tcp/ip should be used host AND port have
22088 -        * to be specified 
22089 -        * 
22090 -        */ 
22091 -       buffer *host; 
22092 +        * to be specified
22093 +        *
22094 +        */
22095 +       buffer *host;
22096         unsigned short port;
22097  
22098         /*
22099 @@ -169,7 +171,7 @@
22100          */
22101         buffer *unixsocket;
22102  
22103 -       /* if socket is local we can start the fastcgi 
22104 +       /* if socket is local we can start the fastcgi
22105          * process ourself
22106          *
22107          * bin-path is the path to the binary
22108 @@ -177,19 +179,19 @@
22109          * check min_procs and max_procs for the number
22110          * of process to start-up
22111          */
22112 -       buffer *bin_path; 
22113 -       
22114 -       /* bin-path is set bin-environment is taken to 
22115 +       buffer *bin_path;
22116 +
22117 +       /* bin-path is set bin-environment is taken to
22118          * create the environement before starting the
22119          * FastCGI process
22120 -        * 
22121 +        *
22122          */
22123         array *bin_env;
22124 -       
22125 +
22126         array *bin_env_copy;
22127 -       
22128 +
22129         /*
22130 -        * docroot-translation between URL->phys and the 
22131 +        * docroot-translation between URL->phys and the
22132          * remote host
22133          *
22134          * reasons:
22135 @@ -208,7 +210,7 @@
22136         unsigned short mode;
22137  
22138         /*
22139 -        * check_local tell you if the phys file is stat()ed 
22140 +        * check_local tell you if the phys file is stat()ed
22141          * or not. FastCGI doesn't care if the service is
22142          * remote. If the web-server side doesn't contain
22143          * the fastcgi-files we should not stat() for them
22144 @@ -218,11 +220,11 @@
22145  
22146         /*
22147          * append PATH_INFO to SCRIPT_FILENAME
22148 -        * 
22149 +        *
22150          * php needs this if cgi.fix_pathinfo is provied
22151 -        * 
22152 +        *
22153          */
22154 -       
22155 +
22156         unsigned short break_scriptfilename_for_php;
22157  
22158         /*
22159 @@ -231,12 +233,12 @@
22160          *
22161          */
22162         unsigned short allow_xsendfile;
22163 -               
22164 +
22165         ssize_t load; /* replace by host->load */
22166  
22167         size_t max_id; /* corresponds most of the time to
22168         num_procs.
22169 -       
22170 +
22171         only if a process is killed max_id waits for the process itself
22172         to die and decrements its afterwards */
22173  
22174 @@ -245,17 +247,17 @@
22175  
22176  /*
22177   * one extension can have multiple hosts assigned
22178 - * one host can spawn additional processes on the same 
22179 + * one host can spawn additional processes on the same
22180   *   socket (if we control it)
22181   *
22182   * ext -> host -> procs
22183   *    1:n     1:n
22184   *
22185 - * if the fastcgi process is remote that whole goes down 
22186 + * if the fastcgi process is remote that whole goes down
22187   * to
22188   *
22189   * ext -> host -> procs
22190 - *    1:n     1:1 
22191 + *    1:n     1:1
22192   *
22193   * in case of PHP and FCGI_CHILDREN we have again a procs
22194   * but we don't control it directly.
22195 @@ -268,7 +270,7 @@
22196         int note_is_sent;
22197  
22198         fcgi_extension_host **hosts;
22199 -       
22200 +
22201         size_t used;
22202         size_t size;
22203  } fcgi_extension;
22204 @@ -282,10 +284,10 @@
22205  
22206  
22207  typedef struct {
22208 -       fcgi_exts *exts; 
22209 +       fcgi_exts *exts;
22210  
22211         array *ext_mapping;
22212 -       
22213 +
22214         int debug;
22215  } plugin_config;
22216  
22217 @@ -297,7 +299,7 @@
22218  
22219  typedef struct {
22220         char **ptr;
22221 -       
22222 +
22223         size_t size;
22224         size_t used;
22225  } char_array;
22226 @@ -306,55 +308,54 @@
22227  typedef struct {
22228         PLUGIN_DATA;
22229         buffer_uint fcgi_request_id;
22230 -       
22231 +
22232         buffer *fcgi_env;
22233 -       
22234 +
22235         buffer *path;
22236 -       buffer *parse_response;
22237  
22238         buffer *statuskey;
22239 -       
22240 +
22241 +       http_resp *resp;
22242 +
22243         plugin_config **config_storage;
22244 -       
22245 +
22246         plugin_config conf; /* this is only used as long as no handler_ctx is setup */
22247  } plugin_data;
22248  
22249  /* connection specific data */
22250 -typedef enum { 
22251 +typedef enum {
22252         FCGI_STATE_UNSET,
22253 -       FCGI_STATE_INIT, 
22254 -       FCGI_STATE_CONNECT_DELAYED, 
22255 -       FCGI_STATE_PREPARE_WRITE, 
22256 -       FCGI_STATE_WRITE, 
22257 -       FCGI_STATE_READ 
22258 +       FCGI_STATE_INIT,
22259 +       FCGI_STATE_CONNECT_DELAYED,
22260 +       FCGI_STATE_PREPARE_WRITE,
22261 +       FCGI_STATE_WRITE,
22262 +       FCGI_STATE_READ
22263  } fcgi_connection_state_t;
22264  
22265  typedef struct {
22266         fcgi_proc *proc;
22267         fcgi_extension_host *host;
22268         fcgi_extension *ext;
22269 -       
22270 +
22271         fcgi_connection_state_t state;
22272         time_t   state_timestamp;
22273 -       
22274 +
22275         int      reconnects; /* number of reconnect attempts */
22276 -       
22277 -       chunkqueue *rb; /* read queue */
22278 +
22279 +       chunkqueue *rb; /* the raw fcgi read-queue */
22280 +       chunkqueue *http_rb; /* the decoded read-queue for http-parsing */
22281         chunkqueue *wb; /* write queue */
22282 -       
22283 -       buffer   *response_header;
22284 -       
22285 +
22286         size_t    request_id;
22287 -       int       fd;        /* fd to the fastcgi process */
22288 -       int       fde_ndx;   /* index into the fd-event buffer */
22289 +       iosocket *sock;
22290  
22291         pid_t     pid;
22292         int       got_proc;
22293  
22294         int       send_content_body;
22295 -       
22296 +
22297         plugin_config conf;
22298 -       
22299 +
22300         connection *remote_conn;  /* dumb pointer */
22301         plugin_data *plugin_data; /* dumb pointer */
22302  } handler_ctx;
22303 @@ -380,7 +381,7 @@
22304         return di;
22305  }
22306  
22307 -/* dummies of the statistic framework functions 
22308 +/* dummies of the statistic framework functions
22309   * they will be moved to a statistics.c later */
22310  int status_counter_inc(server *srv, const char *s, size_t len) {
22311         data_integer *di = status_counter_get_counter(srv, s, len);
22312 @@ -429,7 +430,7 @@
22313         CLEAN(".connected");
22314         CLEAN(".load");
22315  
22316 -#undef CLEAN   
22317 +#undef CLEAN
22318  
22319  #define CLEAN(x) \
22320         fastcgi_status_copy_procname(b, host, NULL); \
22321 @@ -438,33 +439,30 @@
22322  
22323         CLEAN(".load");
22324  
22325 -#undef CLEAN   
22326 +#undef CLEAN
22327  
22328         return 0;
22329  }
22330  
22331  static handler_ctx * handler_ctx_init() {
22332         handler_ctx * hctx;
22333 -       
22334 +
22335         hctx = calloc(1, sizeof(*hctx));
22336         assert(hctx);
22337 -       
22338 -       hctx->fde_ndx = -1;
22339 -       
22340 -       hctx->response_header = buffer_init();
22341 -       
22342 +
22343         hctx->request_id = 0;
22344         hctx->state = FCGI_STATE_INIT;
22345         hctx->proc = NULL;
22346 -       
22347 -       hctx->fd = -1;
22348 -       
22349 +
22350 +       hctx->sock = iosocket_init();
22351 +
22352         hctx->reconnects = 0;
22353         hctx->send_content_body = 1;
22354  
22355         hctx->rb = chunkqueue_init();
22356 +       hctx->http_rb = chunkqueue_init();
22357         hctx->wb = chunkqueue_init();
22358 -       
22359 +
22360         return hctx;
22361  }
22362  
22363 @@ -473,12 +471,13 @@
22364                 hctx->host->load--;
22365                 hctx->host = NULL;
22366         }
22367 -       
22368 -       buffer_free(hctx->response_header);
22369  
22370         chunkqueue_free(hctx->rb);
22371 +       chunkqueue_free(hctx->http_rb);
22372         chunkqueue_free(hctx->wb);
22373  
22374 +       iosocket_free(hctx->sock);
22375 +
22376         free(hctx);
22377  }
22378  
22379 @@ -488,21 +487,21 @@
22380         f = calloc(1, sizeof(*f));
22381         f->unixsocket = buffer_init();
22382         f->connection_name = buffer_init();
22383 -       
22384 +
22385         f->prev = NULL;
22386         f->next = NULL;
22387 -       
22388 +
22389         return f;
22390  }
22391  
22392  void fastcgi_process_free(fcgi_proc *f) {
22393         if (!f) return;
22394 -       
22395 +
22396         fastcgi_process_free(f->next);
22397 -       
22398 +
22399         buffer_free(f->unixsocket);
22400         buffer_free(f->connection_name);
22401 -       
22402 +
22403         free(f);
22404  }
22405  
22406 @@ -519,13 +518,13 @@
22407         f->bin_env = array_init();
22408         f->bin_env_copy = array_init();
22409         f->strip_request_uri = buffer_init();
22410 -       
22411 +
22412         return f;
22413  }
22414  
22415  void fastcgi_host_free(fcgi_extension_host *h) {
22416         if (!h) return;
22417 -       
22418 +
22419         buffer_free(h->id);
22420         buffer_free(h->host);
22421         buffer_free(h->unixsocket);
22422 @@ -534,49 +533,49 @@
22423         buffer_free(h->strip_request_uri);
22424         array_free(h->bin_env);
22425         array_free(h->bin_env_copy);
22426 -       
22427 +
22428         fastcgi_process_free(h->first);
22429         fastcgi_process_free(h->unused_procs);
22430 -       
22431 +
22432         free(h);
22433 -       
22434 +
22435  }
22436  
22437  fcgi_exts *fastcgi_extensions_init() {
22438         fcgi_exts *f;
22439  
22440         f = calloc(1, sizeof(*f));
22441 -       
22442 +
22443         return f;
22444  }
22445  
22446  void fastcgi_extensions_free(fcgi_exts *f) {
22447         size_t i;
22448 -       
22449 +
22450         if (!f) return;
22451 -       
22452 +
22453         for (i = 0; i < f->used; i++) {
22454                 fcgi_extension *fe;
22455                 size_t j;
22456 -               
22457 +
22458                 fe = f->exts[i];
22459 -               
22460 +
22461                 for (j = 0; j < fe->used; j++) {
22462                         fcgi_extension_host *h;
22463 -                       
22464 +
22465                         h = fe->hosts[j];
22466 -                       
22467 +
22468                         fastcgi_host_free(h);
22469                 }
22470 -               
22471 +
22472                 buffer_free(fe->key);
22473                 free(fe->hosts);
22474 -               
22475 +
22476                 free(fe);
22477         }
22478 -       
22479 +
22480         free(f->exts);
22481 -       
22482 +
22483         free(f);
22484  }
22485  
22486 @@ -625,24 +624,25 @@
22487                 assert(fe->hosts);
22488         }
22489  
22490 -       fe->hosts[fe->used++] = fh; 
22491 +       fe->hosts[fe->used++] = fh;
22492  
22493         return 0;
22494 -       
22495 +
22496  }
22497  
22498  INIT_FUNC(mod_fastcgi_init) {
22499         plugin_data *p;
22500 -       
22501 +
22502         p = calloc(1, sizeof(*p));
22503 -       
22504 +
22505         p->fcgi_env = buffer_init();
22506 -       
22507 +
22508         p->path = buffer_init();
22509 -       p->parse_response = buffer_init();
22510 +
22511 +       p->resp = http_response_init();
22512  
22513         p->statuskey = buffer_init();
22514 -       
22515 +
22516         return p;
22517  }
22518  
22519 @@ -650,81 +650,82 @@
22520  FREE_FUNC(mod_fastcgi_free) {
22521         plugin_data *p = p_d;
22522         buffer_uint *r = &(p->fcgi_request_id);
22523 -       
22524 +
22525         UNUSED(srv);
22526  
22527         if (r->ptr) free(r->ptr);
22528 -       
22529 +
22530         buffer_free(p->fcgi_env);
22531         buffer_free(p->path);
22532 -       buffer_free(p->parse_response);
22533         buffer_free(p->statuskey);
22534 -       
22535 +
22536 +       http_response_free(p->resp);
22537 +
22538         if (p->config_storage) {
22539                 size_t i, j, n;
22540                 for (i = 0; i < srv->config_context->used; i++) {
22541                         plugin_config *s = p->config_storage[i];
22542                         fcgi_exts *exts;
22543 -                       
22544 +
22545                         if (!s) continue;
22546 -                       
22547 +
22548                         exts = s->exts;
22549  
22550                         for (j = 0; j < exts->used; j++) {
22551                                 fcgi_extension *ex;
22552 -                               
22553 +
22554                                 ex = exts->exts[j];
22555 -                               
22556 +
22557                                 for (n = 0; n < ex->used; n++) {
22558                                         fcgi_proc *proc;
22559                                         fcgi_extension_host *host;
22560 -                                       
22561 +
22562                                         host = ex->hosts[n];
22563 -                                       
22564 +
22565                                         for (proc = host->first; proc; proc = proc->next) {
22566                                                 if (proc->pid != 0) kill(proc->pid, SIGTERM);
22567 -                                               
22568 -                                               if (proc->is_local && 
22569 +
22570 +                                               if (proc->is_local &&
22571                                                     !buffer_is_empty(proc->unixsocket)) {
22572                                                         unlink(proc->unixsocket->ptr);
22573                                                 }
22574                                         }
22575 -                                       
22576 +
22577                                         for (proc = host->unused_procs; proc; proc = proc->next) {
22578                                                 if (proc->pid != 0) kill(proc->pid, SIGTERM);
22579 -                                               
22580 -                                               if (proc->is_local && 
22581 +
22582 +                                               if (proc->is_local &&
22583                                                     !buffer_is_empty(proc->unixsocket)) {
22584                                                         unlink(proc->unixsocket->ptr);
22585                                                 }
22586                                         }
22587                                 }
22588                         }
22589 -                       
22590 +
22591                         fastcgi_extensions_free(s->exts);
22592                         array_free(s->ext_mapping);
22593 -                       
22594 +
22595                         free(s);
22596                 }
22597                 free(p->config_storage);
22598         }
22599 -       
22600 +
22601         free(p);
22602 -       
22603 +
22604         return HANDLER_GO_ON;
22605  }
22606  
22607  static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
22608         char *dst;
22609 -       
22610 +
22611         if (!key || !val) return -1;
22612 -       
22613 +
22614         dst = malloc(key_len + val_len + 3);
22615         memcpy(dst, key, key_len);
22616         dst[key_len] = '=';
22617         /* add the \0 from the value */
22618         memcpy(dst + key_len + 1, val, val_len + 1);
22619 -       
22620 +
22621         if (env->size == 0) {
22622                 env->size = 16;
22623                 env->ptr = malloc(env->size * sizeof(*env->ptr));
22624 @@ -732,9 +733,9 @@
22625                 env->size += 16;
22626                 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
22627         }
22628 -       
22629 +
22630         env->ptr[env->used++] = dst;
22631 -       
22632 +
22633         return 0;
22634  }
22635  
22636 @@ -753,15 +754,15 @@
22637                         if (env->size == 0) {
22638                                 env->size = 16;
22639                                 env->ptr = malloc(env->size * sizeof(*env->ptr));
22640 -                       } else if (env->size == env->used) { 
22641 +                       } else if (env->size == env->used) {
22642                                 env->size += 16;
22643                                 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
22644                         }
22645 -                       
22646 +
22647                         b->ptr[i] = '\0';
22648  
22649                         env->ptr[env->used++] = start;
22650 -                       
22651 +
22652                         start = b->ptr + i + 1;
22653                         break;
22654                 default:
22655 @@ -794,7 +795,7 @@
22656         return 0;
22657  }
22658  
22659 -static int fcgi_spawn_connection(server *srv, 
22660 +static int fcgi_spawn_connection(server *srv,
22661                                  plugin_data *p,
22662                                  fcgi_extension_host *host,
22663                                  fcgi_proc *proc) {
22664 @@ -806,31 +807,27 @@
22665  #endif
22666         struct sockaddr_in fcgi_addr_in;
22667         struct sockaddr *fcgi_addr;
22668 -       
22669 +
22670         socklen_t servlen;
22671 -       
22672 +
22673  #ifndef HAVE_FORK
22674         return -1;
22675  #endif
22676 -       
22677 +
22678         if (p->conf.debug) {
22679                 log_error_write(srv, __FILE__, __LINE__, "sdb",
22680                                 "new proc, socket:", proc->port, proc->unixsocket);
22681         }
22682 -               
22683 +
22684         if (!buffer_is_empty(proc->unixsocket)) {
22685                 memset(&fcgi_addr, 0, sizeof(fcgi_addr));
22686 -               
22687 +
22688  #ifdef HAVE_SYS_UN_H
22689                 fcgi_addr_un.sun_family = AF_UNIX;
22690                 strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
22691 -               
22692 -#ifdef SUN_LEN
22693 +
22694                 servlen = SUN_LEN(&fcgi_addr_un);
22695 -#else
22696 -               /* stevens says: */
22697 -               servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
22698 -#endif
22699 +
22700                 socket_type = AF_UNIX;
22701                 fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
22702  
22703 @@ -844,108 +841,108 @@
22704  #endif
22705         } else {
22706                 fcgi_addr_in.sin_family = AF_INET;
22707 -               
22708 +
22709                 if (buffer_is_empty(host->host)) {
22710                         fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
22711                 } else {
22712                         struct hostent *he;
22713 -                       
22714 +
22715                         /* set a usefull default */
22716                         fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
22717 -                       
22718 -                       
22719 +
22720 +
22721                         if (NULL == (he = gethostbyname(host->host->ptr))) {
22722 -                               log_error_write(srv, __FILE__, __LINE__, 
22723 -                                               "sdb", "gethostbyname failed: ", 
22724 +                               log_error_write(srv, __FILE__, __LINE__,
22725 +                                               "sdb", "gethostbyname failed: ",
22726                                                 h_errno, host->host);
22727                                 return -1;
22728                         }
22729 -                       
22730 +
22731                         if (he->h_addrtype != AF_INET) {
22732                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
22733                                 return -1;
22734                         }
22735 -                       
22736 +
22737                         if (he->h_length != sizeof(struct in_addr)) {
22738                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
22739                                 return -1;
22740                         }
22741 -                       
22742 +
22743                         memcpy(&(fcgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
22744 -                       
22745 +
22746                 }
22747                 fcgi_addr_in.sin_port = htons(proc->port);
22748                 servlen = sizeof(fcgi_addr_in);
22749 -               
22750 +
22751                 socket_type = AF_INET;
22752                 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
22753 -               
22754 +
22755                 buffer_copy_string(proc->connection_name, "tcp:");
22756                 buffer_append_string_buffer(proc->connection_name, host->host);
22757                 buffer_append_string(proc->connection_name, ":");
22758                 buffer_append_long(proc->connection_name, proc->port);
22759         }
22760 -       
22761 +
22762         if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
22763 -               log_error_write(srv, __FILE__, __LINE__, "ss", 
22764 +               log_error_write(srv, __FILE__, __LINE__, "ss",
22765                                 "failed:", strerror(errno));
22766                 return -1;
22767         }
22768 -       
22769 +
22770         if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
22771                 /* server is not up, spawn in  */
22772                 pid_t child;
22773                 int val;
22774 -               
22775 -               if (errno != ENOENT && 
22776 +
22777 +               if (errno != ENOENT &&
22778                     !buffer_is_empty(proc->unixsocket)) {
22779                         unlink(proc->unixsocket->ptr);
22780                 }
22781 -               
22782 +
22783                 close(fcgi_fd);
22784 -               
22785 +
22786                 /* reopen socket */
22787                 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
22788 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
22789 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
22790                                 "socket failed:", strerror(errno));
22791                         return -1;
22792                 }
22793 -               
22794 +
22795                 val = 1;
22796                 if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
22797 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
22798 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
22799                                         "socketsockopt failed:", strerror(errno));
22800                         return -1;
22801                 }
22802 -               
22803 +
22804                 /* create socket */
22805                 if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
22806 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
22807 -                               "bind failed for:", 
22808 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
22809 +                               "bind failed for:",
22810                                 proc->connection_name,
22811                                 strerror(errno));
22812                         return -1;
22813                 }
22814 -               
22815 +
22816                 if (-1 == listen(fcgi_fd, 1024)) {
22817 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
22818 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
22819                                 "listen failed:", strerror(errno));
22820                         return -1;
22821                 }
22822 -               
22823 -#ifdef HAVE_FORK       
22824 +
22825 +#ifndef _WIN32
22826                 switch ((child = fork())) {
22827                 case 0: {
22828                         size_t i = 0;
22829                         char *c;
22830                         char_array env;
22831                         char_array arg;
22832 -                       
22833 +
22834                         /* create environment */
22835                         env.ptr = NULL;
22836                         env.size = 0;
22837                         env.used = 0;
22838 -                       
22839 +
22840                         arg.ptr = NULL;
22841                         arg.size = 0;
22842                         arg.used = 0;
22843 @@ -955,18 +952,18 @@
22844                                 dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
22845                                 close(fcgi_fd);
22846                         }
22847 -                       
22848 +
22849                         /* we don't need the client socket */
22850                         for (i = 3; i < 256; i++) {
22851                                 close(i);
22852                         }
22853 -                       
22854 +
22855                         /* build clean environment */
22856                         if (host->bin_env_copy->used) {
22857                                 for (i = 0; i < host->bin_env_copy->used; i++) {
22858                                         data_string *ds = (data_string *)host->bin_env_copy->data[i];
22859                                         char *ge;
22860 -                                       
22861 +
22862                                         if (NULL != (ge = getenv(ds->value->ptr))) {
22863                                                 env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge));
22864                                         }
22865 @@ -974,39 +971,39 @@
22866                         } else {
22867                                 for (i = 0; environ[i]; i++) {
22868                                         char *eq;
22869 -                                       
22870 +
22871                                         if (NULL != (eq = strchr(environ[i], '='))) {
22872                                                 env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));
22873                                         }
22874                                 }
22875                         }
22876 -                       
22877 +
22878                         /* create environment */
22879                         for (i = 0; i < host->bin_env->used; i++) {
22880                                 data_string *ds = (data_string *)host->bin_env->data[i];
22881 -                               
22882 +
22883                                 env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
22884                         }
22885 -                       
22886 +
22887                         for (i = 0; i < env.used; i++) {
22888                                 /* search for PHP_FCGI_CHILDREN */
22889                                 if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break;
22890                         }
22891 -                       
22892 +
22893                         /* not found, add a default */
22894                         if (i == env.used) {
22895                                 env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1"));
22896                         }
22897 -                       
22898 +
22899                         env.ptr[env.used] = NULL;
22900  
22901                         parse_binpath(&arg, host->bin_path);
22902 -                       
22903 +
22904                         /* chdir into the base of the bin-path,
22905                          * search for the last / */
22906                         if (NULL != (c = strrchr(arg.ptr[0], '/'))) {
22907                                 *c = '\0';
22908 -                       
22909 +
22910                                 /* change to the physical directory */
22911                                 if (-1 == chdir(arg.ptr[0])) {
22912                                         *c = '/';
22913 @@ -1018,12 +1015,12 @@
22914  
22915                         /* exec the cgi */
22916                         execve(arg.ptr[0], arg.ptr, env.ptr);
22917 -                       
22918 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
22919 +
22920 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
22921                                         "execve failed for:", host->bin_path, strerror(errno));
22922 -                       
22923 +
22924                         exit(errno);
22925 -                       
22926 +
22927                         break;
22928                 }
22929                 case -1:
22930 @@ -1031,17 +1028,17 @@
22931                         break;
22932                 default:
22933                         /* father */
22934 -                       
22935 +
22936                         /* wait */
22937                         select(0, NULL, NULL, NULL, &tv);
22938 -                       
22939 +
22940                         switch (waitpid(child, &status, WNOHANG)) {
22941                         case 0:
22942                                 /* child still running after timeout, good */
22943                                 break;
22944                         case -1:
22945                                 /* no PID found ? should never happen */
22946 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
22947 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
22948                                                 "pid not found:", strerror(errno));
22949                                 return -1;
22950                         default:
22951 @@ -1049,10 +1046,10 @@
22952                                                 "the fastcgi-backend", host->bin_path, "failed to start:");
22953                                 /* the child should not terminate at all */
22954                                 if (WIFEXITED(status)) {
22955 -                                       log_error_write(srv, __FILE__, __LINE__, "sdb", 
22956 -                                                       "child exited with status", 
22957 +                                       log_error_write(srv, __FILE__, __LINE__, "sdb",
22958 +                                                       "child exited with status",
22959                                                         WEXITSTATUS(status), host->bin_path);
22960 -                                       log_error_write(srv, __FILE__, __LINE__, "s", 
22961 +                                       log_error_write(srv, __FILE__, __LINE__, "s",
22962                                                         "if you try do run PHP as FastCGI backend make sure you use the FastCGI enabled version.\n"
22963                                                         "You can find out if it is the right one by executing 'php -v' and it should display '(cgi-fcgi)' "
22964                                                         "in the output, NOT (cgi) NOR (cli)\n"
22965 @@ -1060,8 +1057,8 @@
22966                                         log_error_write(srv, __FILE__, __LINE__, "s",
22967                                                         "If this is PHP on Gentoo add fastcgi to the USE flags");
22968                                 } else if (WIFSIGNALED(status)) {
22969 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
22970 -                                                       "terminated by signal:", 
22971 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
22972 +                                                       "terminated by signal:",
22973                                                         WTERMSIG(status));
22974  
22975                                         if (WTERMSIG(status) == 11) {
22976 @@ -1071,8 +1068,8 @@
22977                                                                 "If this is PHP try to remove the byte-code caches for now and try again.");
22978                                         }
22979                                 } else {
22980 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
22981 -                                                       "child died somehow:", 
22982 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
22983 +                                                       "child died somehow:",
22984                                                         status);
22985                                 }
22986                                 return -1;
22987 @@ -1082,26 +1079,26 @@
22988                         proc->pid = child;
22989                         proc->last_used = srv->cur_ts;
22990                         proc->is_local = 1;
22991 -                                               
22992 +
22993                         break;
22994                 }
22995  #endif
22996         } else {
22997                 proc->is_local = 0;
22998                 proc->pid = 0;
22999 -               
23000 +
23001                 if (p->conf.debug) {
23002                         log_error_write(srv, __FILE__, __LINE__, "sb",
23003                                         "(debug) socket is already used, won't spawn:",
23004                                         proc->connection_name);
23005                 }
23006         }
23007 -       
23008 +
23009         proc->state = PROC_STATE_RUNNING;
23010         host->active_procs++;
23011 -       
23012 +
23013         close(fcgi_fd);
23014 -       
23015 +
23016         return 0;
23017  }
23018  
23019 @@ -1111,93 +1108,93 @@
23020         data_unset *du;
23021         size_t i = 0;
23022         buffer *fcgi_mode = buffer_init();
23023 -       
23024 -       config_values_t cv[] = { 
23025 +
23026 +       config_values_t cv[] = {
23027                 { "fastcgi.server",              NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
23028                 { "fastcgi.debug",               NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
23029                 { "fastcgi.map-extensions",      NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
23030                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
23031         };
23032 -       
23033 +
23034         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
23035 -       
23036 +
23037         for (i = 0; i < srv->config_context->used; i++) {
23038                 plugin_config *s;
23039                 array *ca;
23040 -               
23041 +
23042                 s = malloc(sizeof(plugin_config));
23043                 s->exts          = fastcgi_extensions_init();
23044                 s->debug         = 0;
23045                 s->ext_mapping   = array_init();
23046 -               
23047 +
23048                 cv[0].destination = s->exts;
23049                 cv[1].destination = &(s->debug);
23050                 cv[2].destination = s->ext_mapping;
23051 -               
23052 +
23053                 p->config_storage[i] = s;
23054                 ca = ((data_config *)srv->config_context->data[i])->value;
23055 -       
23056 +
23057                 if (0 != config_insert_values_global(srv, ca, cv)) {
23058                         return HANDLER_ERROR;
23059                 }
23060 -               
23061 -               /* 
23062 +
23063 +               /*
23064                  * <key> = ( ... )
23065                  */
23066 -               
23067 +
23068                 if (NULL != (du = array_get_element(ca, "fastcgi.server"))) {
23069                         size_t j;
23070                         data_array *da = (data_array *)du;
23071 -                       
23072 +
23073                         if (du->type != TYPE_ARRAY) {
23074 -                               log_error_write(srv, __FILE__, __LINE__, "sss", 
23075 +                               log_error_write(srv, __FILE__, __LINE__, "sss",
23076                                                 "unexpected type for key: ", "fastcgi.server", "array of strings");
23077 -                               
23078 +
23079                                 return HANDLER_ERROR;
23080                         }
23081 -                       
23082 -                       
23083 -                       /* 
23084 -                        * fastcgi.server = ( "<ext>" => ( ... ), 
23085 +
23086 +
23087 +                       /*
23088 +                        * fastcgi.server = ( "<ext>" => ( ... ),
23089                          *                    "<ext>" => ( ... ) )
23090                          */
23091 -                       
23092 +
23093                         for (j = 0; j < da->value->used; j++) {
23094                                 size_t n;
23095                                 data_array *da_ext = (data_array *)da->value->data[j];
23096 -                               
23097 +
23098                                 if (da->value->data[j]->type != TYPE_ARRAY) {
23099 -                                       log_error_write(srv, __FILE__, __LINE__, "sssbs", 
23100 -                                                       "unexpected type for key: ", "fastcgi.server", 
23101 +                                       log_error_write(srv, __FILE__, __LINE__, "sssbs",
23102 +                                                       "unexpected type for key: ", "fastcgi.server",
23103                                                         "[", da->value->data[j]->key, "](string)");
23104 -                                       
23105 +
23106                                         return HANDLER_ERROR;
23107                                 }
23108 -                               
23109 -                               /* 
23110 -                                * da_ext->key == name of the extension 
23111 +
23112 +                               /*
23113 +                                * da_ext->key == name of the extension
23114                                  */
23115 -                               
23116 -                               /* 
23117 -                                * fastcgi.server = ( "<ext>" => 
23118 -                                *                     ( "<host>" => ( ... ), 
23119 +
23120 +                               /*
23121 +                                * fastcgi.server = ( "<ext>" =>
23122 +                                *                     ( "<host>" => ( ... ),
23123                                  *                       "<host>" => ( ... )
23124 -                                *                     ), 
23125 +                                *                     ),
23126                                  *                    "<ext>" => ... )
23127                                  */
23128 -                                       
23129 +
23130                                 for (n = 0; n < da_ext->value->used; n++) {
23131                                         data_array *da_host = (data_array *)da_ext->value->data[n];
23132 -                                       
23133 +
23134                                         fcgi_extension_host *host;
23135 -                                       
23136 -                                       config_values_t fcv[] = { 
23137 +
23138 +                                       config_values_t fcv[] = {
23139                                                 { "host",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
23140                                                 { "docroot",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
23141                                                 { "mode",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
23142                                                 { "socket",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
23143                                                 { "bin-path",          NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 4 */
23144 -                                               
23145 +
23146                                                 { "check-local",       NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 5 */
23147                                                 { "port",              NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 6 */
23148                                                 { "min-procs-not-working",         NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 7 this is broken for now */
23149 @@ -1205,28 +1202,28 @@
23150                                                 { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 9 */
23151                                                 { "idle-timeout",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 10 */
23152                                                 { "disable-time",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 11 */
23153 -                                               
23154 +
23155                                                 { "bin-environment",   NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },        /* 12 */
23156                                                 { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },     /* 13 */
23157 -                                               
23158 +
23159                                                 { "broken-scriptfilename", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },  /* 14 */
23160                                                 { "allow-x-send-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 15 */
23161                                                 { "strip-request-uri",  NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 16 */
23162 -                                               
23163 +
23164                                                 { NULL,                NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
23165                                         };
23166 -                                       
23167 +
23168                                         if (da_host->type != TYPE_ARRAY) {
23169 -                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS", 
23170 -                                                               "unexpected type for key:", 
23171 -                                                               "fastcgi.server", 
23172 +                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS",
23173 +                                                               "unexpected type for key:",
23174 +                                                               "fastcgi.server",
23175                                                                 "[", da_host->key, "](string)");
23176 -                                               
23177 +
23178                                                 return HANDLER_ERROR;
23179                                         }
23180 -                                       
23181 +
23182                                         host = fastcgi_host_init();
23183 -                                       
23184 +
23185                                         buffer_copy_string_buffer(host->id, da_host->key);
23186  
23187                                         host->check_local  = 1;
23188 @@ -1238,13 +1235,13 @@
23189                                         host->disable_time = 60;
23190                                         host->break_scriptfilename_for_php = 0;
23191                                         host->allow_xsendfile = 0; /* handle X-LIGHTTPD-send-file */
23192 -                                       
23193 +
23194                                         fcv[0].destination = host->host;
23195                                         fcv[1].destination = host->docroot;
23196                                         fcv[2].destination = fcgi_mode;
23197                                         fcv[3].destination = host->unixsocket;
23198                                         fcv[4].destination = host->bin_path;
23199 -                                       
23200 +
23201                                         fcv[5].destination = &(host->check_local);
23202                                         fcv[6].destination = &(host->port);
23203                                         fcv[7].destination = &(host->min_procs);
23204 @@ -1252,35 +1249,35 @@
23205                                         fcv[9].destination = &(host->max_load_per_proc);
23206                                         fcv[10].destination = &(host->idle_timeout);
23207                                         fcv[11].destination = &(host->disable_time);
23208 -                                       
23209 +
23210                                         fcv[12].destination = host->bin_env;
23211                                         fcv[13].destination = host->bin_env_copy;
23212                                         fcv[14].destination = &(host->break_scriptfilename_for_php);
23213                                         fcv[15].destination = &(host->allow_xsendfile);
23214                                         fcv[16].destination = host->strip_request_uri;
23215 -                                       
23216 +
23217                                         if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
23218                                                 return HANDLER_ERROR;
23219                                         }
23220 -                                                       
23221 -                                       if ((!buffer_is_empty(host->host) || host->port) && 
23222 +
23223 +                                       if ((!buffer_is_empty(host->host) || host->port) &&
23224                                             !buffer_is_empty(host->unixsocket)) {
23225 -                                               log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", 
23226 +                                               log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23227                                                                 "either host/port or socket have to be set in:",
23228 -                                                               da->key, "= (", 
23229 +                                                               da->key, "= (",
23230                                                                 da_ext->key, " => (",
23231                                                                 da_host->key, " ( ...");
23232  
23233                                                 return HANDLER_ERROR;
23234                                         }
23235 -                                       
23236 +
23237                                         if (!buffer_is_empty(host->unixsocket)) {
23238                                                 /* unix domain socket */
23239 -                                               
23240 +
23241                                                 if (host->unixsocket->used > UNIX_PATH_MAX - 2) {
23242 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", 
23243 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23244                                                                         "unixsocket is too long in:",
23245 -                                                                       da->key, "= (", 
23246 +                                                                       da->key, "= (",
23247                                                                         da_ext->key, " => (",
23248                                                                         da_host->key, " ( ...");
23249  
23250 @@ -1288,37 +1285,37 @@
23251                                                 }
23252                                         } else {
23253                                                 /* tcp/ip */
23254 -                                               
23255 -                                               if (buffer_is_empty(host->host) && 
23256 +
23257 +                                               if (buffer_is_empty(host->host) &&
23258                                                     buffer_is_empty(host->bin_path)) {
23259 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", 
23260 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23261                                                                         "host or binpath have to be set in:",
23262 -                                                                       da->key, "= (", 
23263 +                                                                       da->key, "= (",
23264                                                                         da_ext->key, " => (",
23265                                                                         da_host->key, " ( ...");
23266 -                                                       
23267 +
23268                                                         return HANDLER_ERROR;
23269                                                 } else if (host->port == 0) {
23270 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", 
23271 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23272                                                                         "port has to be set in:",
23273 -                                                                       da->key, "= (", 
23274 +                                                                       da->key, "= (",
23275                                                                         da_ext->key, " => (",
23276                                                                         da_host->key, " ( ...");
23277  
23278                                                         return HANDLER_ERROR;
23279                                                 }
23280                                         }
23281 -                                               
23282 -                                       if (!buffer_is_empty(host->bin_path)) { 
23283 +
23284 +                                       if (!buffer_is_empty(host->bin_path)) {
23285                                                 /* a local socket + self spawning */
23286                                                 size_t pno;
23287  
23288                                                 /* HACK:  just to make sure the adaptive spawing is disabled */
23289                                                 host->min_procs = host->max_procs;
23290 -                                               
23291 +
23292                                                 if (host->min_procs > host->max_procs) host->max_procs = host->min_procs;
23293                                                 if (host->max_load_per_proc < 1) host->max_load_per_proc = 0;
23294 -                                               
23295 +
23296                                                 if (s->debug) {
23297                                                         log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
23298                                                                         "--- fastcgi spawning local",
23299 @@ -1328,7 +1325,7 @@
23300                                                                         "\n\tmin-procs:", host->min_procs,
23301                                                                         "\n\tmax-procs:", host->max_procs);
23302                                                 }
23303 -                                               
23304 +
23305                                                 for (pno = 0; pno < host->min_procs; pno++) {
23306                                                         fcgi_proc *proc;
23307  
23308 @@ -1343,7 +1340,7 @@
23309                                                                 buffer_append_string(proc->unixsocket, "-");
23310                                                                 buffer_append_long(proc->unixsocket, pno);
23311                                                         }
23312 -                                                       
23313 +
23314                                                         if (s->debug) {
23315                                                                 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
23316                                                                                 "--- fastcgi spawning",
23317 @@ -1351,7 +1348,7 @@
23318                                                                                 "\n\tsocket", host->unixsocket,
23319                                                                                 "\n\tcurrent:", pno, "/", host->min_procs);
23320                                                         }
23321 -                                                       
23322 +
23323                                                         if (fcgi_spawn_connection(srv, p, host, proc)) {
23324                                                                 log_error_write(srv, __FILE__, __LINE__, "s",
23325                                                                                 "[ERROR]: spawning fcgi failed.");
23326 @@ -1359,35 +1356,35 @@
23327                                                         }
23328  
23329                                                         fastcgi_status_init(srv, p->statuskey, host, proc);
23330 -                                                       
23331 +
23332                                                         proc->next = host->first;
23333                                                         if (host->first)        host->first->prev = proc;
23334 -                                                       
23335 +
23336                                                         host->first = proc;
23337                                                 }
23338                                         } else {
23339                                                 fcgi_proc *proc;
23340 -                                               
23341 +
23342                                                 proc = fastcgi_process_init();
23343                                                 proc->id = host->num_procs++;
23344                                                 host->max_id++;
23345                                                 host->active_procs++;
23346                                                 proc->state = PROC_STATE_RUNNING;
23347 -                                               
23348 +
23349                                                 if (buffer_is_empty(host->unixsocket)) {
23350                                                         proc->port = host->port;
23351                                                 } else {
23352                                                         buffer_copy_string_buffer(proc->unixsocket, host->unixsocket);
23353                                                 }
23354 -                                               
23355 +
23356                                                 fastcgi_status_init(srv, p->statuskey, host, proc);
23357  
23358                                                 host->first = proc;
23359 -                                               
23360 +
23361                                                 host->min_procs = 1;
23362                                                 host->max_procs = 1;
23363                                         }
23364 -                                       
23365 +
23366                                         if (!buffer_is_empty(fcgi_mode)) {
23367                                                 if (strcmp(fcgi_mode->ptr, "responder") == 0) {
23368                                                         host->mode = FCGI_RESPONDER;
23369 @@ -1411,16 +1408,16 @@
23370                         }
23371                 }
23372         }
23373 -       
23374 +
23375         buffer_free(fcgi_mode);
23376 -       
23377 +
23378         return HANDLER_GO_ON;
23379  }
23380  
23381  static int fcgi_set_state(server *srv, handler_ctx *hctx, fcgi_connection_state_t state) {
23382         hctx->state = state;
23383         hctx->state_timestamp = srv->cur_ts;
23384 -       
23385 +
23386         return 0;
23387  }
23388  
23389 @@ -1429,13 +1426,13 @@
23390         size_t m = 0;
23391         size_t i;
23392         buffer_uint *r = &(p->fcgi_request_id);
23393 -       
23394 +
23395         UNUSED(srv);
23396  
23397         for (i = 0; i < r->used; i++) {
23398                 if (r->ptr[i] > m) m = r->ptr[i];
23399         }
23400 -       
23401 +
23402         if (r->size == 0) {
23403                 r->size = 16;
23404                 r->ptr = malloc(sizeof(*r->ptr) * r->size);
23405 @@ -1443,54 +1440,55 @@
23406                 r->size += 16;
23407                 r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
23408         }
23409 -       
23410 +
23411         r->ptr[r->used++] = ++m;
23412 -       
23413 +
23414         return m;
23415  }
23416  
23417  static int fcgi_requestid_del(server *srv, plugin_data *p, size_t request_id) {
23418         size_t i;
23419         buffer_uint *r = &(p->fcgi_request_id);
23420 -       
23421 +
23422         UNUSED(srv);
23423  
23424         for (i = 0; i < r->used; i++) {
23425                 if (r->ptr[i] == request_id) break;
23426         }
23427 -       
23428 +
23429         if (i != r->used) {
23430                 /* found */
23431 -               
23432 +
23433                 if (i != r->used - 1) {
23434                         r->ptr[i] = r->ptr[r->used - 1];
23435                 }
23436                 r->used--;
23437         }
23438 -       
23439 +
23440         return 0;
23441  }
23442  void fcgi_connection_close(server *srv, handler_ctx *hctx) {
23443         plugin_data *p;
23444         connection  *con;
23445 -       
23446 +
23447         if (NULL == hctx) return;
23448 -       
23449 +
23450         p    = hctx->plugin_data;
23451         con  = hctx->remote_conn;
23452 -       
23453 +
23454         if (con->mode != p->id) {
23455 -               WP();
23456                 return;
23457         }
23458 -       
23459 -       if (hctx->fd != -1) {
23460 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
23461 -               fdevent_unregister(srv->ev, hctx->fd);
23462 -               close(hctx->fd);
23463 -               srv->cur_fds--;
23464 +
23465 +       if (hctx->sock->fd != -1) {
23466 +               fdevent_event_del(srv->ev, hctx->sock);
23467 +               fdevent_unregister(srv->ev, hctx->sock);
23468 +               closesocket(hctx->sock->fd);
23469 +               hctx->sock->fd = -1;
23470 +
23471 +               srv->cur_fds--;
23472         }
23473 -       
23474 +
23475         if (hctx->request_id != 0) {
23476                 fcgi_requestid_del(srv, p, hctx->request_id);
23477         }
23478 @@ -1499,7 +1497,7 @@
23479                 if (hctx->got_proc) {
23480                         /* after the connect the process gets a load */
23481                         hctx->proc->load--;
23482 -                       
23483 +
23484                         status_counter_dec(srv, CONST_STR_LEN("fastcgi.active-requests"));
23485  
23486                         fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
23487 @@ -1509,101 +1507,101 @@
23488  
23489                         if (p->conf.debug) {
23490                                 log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
23491 -                                               "released proc:", 
23492 -                                               "pid:", hctx->proc->pid, 
23493 -                                               "socket:", hctx->proc->connection_name, 
23494 +                                               "released proc:",
23495 +                                               "pid:", hctx->proc->pid,
23496 +                                               "socket:", hctx->proc->connection_name,
23497                                                 "load:", hctx->proc->load);
23498                         }
23499                 }
23500         }
23501  
23502 -       
23503 +
23504         handler_ctx_free(hctx);
23505 -       con->plugin_ctx[p->id] = NULL;  
23506 +       con->plugin_ctx[p->id] = NULL;
23507  }
23508  
23509  static int fcgi_reconnect(server *srv, handler_ctx *hctx) {
23510         plugin_data *p    = hctx->plugin_data;
23511 -       
23512 -       /* child died 
23513 -        * 
23514 -        * 1. 
23515 -        * 
23516 +
23517 +       /* child died
23518 +        *
23519 +        * 1.
23520 +        *
23521          * connect was ok, connection was accepted
23522          * but the php accept loop checks after the accept if it should die or not.
23523 -        * 
23524 -        * if yes we can only detect it at a write() 
23525 -        * 
23526 +        *
23527 +        * if yes we can only detect it at a write()
23528 +        *
23529          * next step is resetting this attemp and setup a connection again
23530 -        * 
23531 +        *
23532          * if we have more then 5 reconnects for the same request, die
23533 -        * 
23534 -        * 2. 
23535 -        * 
23536 +        *
23537 +        * 2.
23538 +        *
23539          * we have a connection but the child died by some other reason
23540 -        * 
23541 +        *
23542          */
23543  
23544 -       if (hctx->fd != -1) {
23545 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
23546 -               fdevent_unregister(srv->ev, hctx->fd);
23547 -               close(hctx->fd);
23548 +       if (hctx->sock->fd != -1) {
23549 +               fdevent_event_del(srv->ev, hctx->sock);
23550 +               fdevent_unregister(srv->ev, hctx->sock);
23551 +               close(hctx->sock->fd);
23552                 srv->cur_fds--;
23553 -               hctx->fd = -1;
23554 +               hctx->sock->fd = -1;
23555         }
23556 -       
23557 +
23558         fcgi_requestid_del(srv, p, hctx->request_id);
23559 -       
23560 +
23561         fcgi_set_state(srv, hctx, FCGI_STATE_INIT);
23562 -       
23563 +
23564         hctx->request_id = 0;
23565         hctx->reconnects++;
23566 -       
23567 +
23568         if (p->conf.debug > 2) {
23569                 if (hctx->proc) {
23570                         log_error_write(srv, __FILE__, __LINE__, "sdb",
23571 -                                       "release proc for reconnect:", 
23572 +                                       "release proc for reconnect:",
23573                                         hctx->proc->pid, hctx->proc->connection_name);
23574                 } else {
23575                         log_error_write(srv, __FILE__, __LINE__, "sb",
23576 -                                       "release proc for reconnect:", 
23577 +                                       "release proc for reconnect:",
23578                                         hctx->host->unixsocket);
23579                 }
23580         }
23581  
23582 -       if (hctx->proc && hctx->got_proc) {     
23583 +       if (hctx->proc && hctx->got_proc) {
23584                 hctx->proc->load--;
23585         }
23586  
23587         /* perhaps another host gives us more luck */
23588         hctx->host->load--;
23589         hctx->host = NULL;
23590 -       
23591 +
23592         return 0;
23593  }
23594  
23595  
23596  static handler_t fcgi_connection_reset(server *srv, connection *con, void *p_d) {
23597         plugin_data *p = p_d;
23598 -       
23599 +
23600         fcgi_connection_close(srv, con->plugin_ctx[p->id]);
23601 -       
23602 +
23603         return HANDLER_GO_ON;
23604  }
23605  
23606  
23607  static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
23608         size_t len;
23609 -       
23610 +
23611         if (!key || !val) return -1;
23612 -       
23613 +
23614         len = key_len + val_len;
23615 -       
23616 +
23617         len += key_len > 127 ? 4 : 1;
23618         len += val_len > 127 ? 4 : 1;
23619 -       
23620 +
23621         buffer_prepare_append(env, len);
23622 -       
23623 +
23624         if (key_len > 127) {
23625                 env->ptr[env->used++] = ((key_len >> 24) & 0xff) | 0x80;
23626                 env->ptr[env->used++] = (key_len >> 16) & 0xff;
23627 @@ -1612,7 +1610,7 @@
23628         } else {
23629                 env->ptr[env->used++] = (key_len >> 0) & 0xff;
23630         }
23631 -       
23632 +
23633         if (val_len > 127) {
23634                 env->ptr[env->used++] = ((val_len >> 24) & 0xff) | 0x80;
23635                 env->ptr[env->used++] = (val_len >> 16) & 0xff;
23636 @@ -1621,12 +1619,12 @@
23637         } else {
23638                 env->ptr[env->used++] = (val_len >> 0) & 0xff;
23639         }
23640 -       
23641 +
23642         memcpy(env->ptr + env->used, key, key_len);
23643         env->used += key_len;
23644         memcpy(env->ptr + env->used, val, val_len);
23645         env->used += val_len;
23646 -       
23647 +
23648         return 0;
23649  }
23650  
23651 @@ -1639,11 +1637,11 @@
23652         header->contentLengthB1 = (contentLength >> 8) & 0xff;
23653         header->paddingLength = paddingLength;
23654         header->reserved = 0;
23655 -       
23656 +
23657         return 0;
23658  }
23659  /**
23660 - * 
23661 + *
23662   * returns
23663   *   -1 error
23664   *    0 connected
23665 @@ -1665,26 +1663,23 @@
23666         struct sockaddr_un fcgi_addr_un;
23667  #endif
23668         socklen_t servlen;
23669 -       
23670 +
23671         fcgi_extension_host *host = hctx->host;
23672         fcgi_proc *proc   = hctx->proc;
23673 -       int fcgi_fd       = hctx->fd;
23674 -       
23675 +       int fcgi_fd       = hctx->sock->fd;
23676 +
23677         memset(&fcgi_addr, 0, sizeof(fcgi_addr));
23678 -       
23679 +
23680         if (!buffer_is_empty(proc->unixsocket)) {
23681  #ifdef HAVE_SYS_UN_H
23682                 /* use the unix domain socket */
23683                 fcgi_addr_un.sun_family = AF_UNIX;
23684                 strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
23685 -#ifdef SUN_LEN
23686 +
23687                 servlen = SUN_LEN(&fcgi_addr_un);
23688 -#else
23689 -               /* stevens says: */
23690 -               servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
23691 -#endif
23692 +
23693                 fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
23694 -       
23695 +
23696                 if (buffer_is_empty(proc->connection_name)) {
23697                         /* on remote spawing we have to set the connection-name now */
23698                         buffer_copy_string(proc->connection_name, "unix:");
23699 @@ -1695,16 +1690,18 @@
23700  #endif
23701         } else {
23702                 fcgi_addr_in.sin_family = AF_INET;
23703 +
23704                 if (0 == inet_aton(host->host->ptr, &(fcgi_addr_in.sin_addr))) {
23705 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
23706 -                                       "converting IP-adress failed for", host->host, 
23707 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
23708 +                                       "converting IP-adress failed for", host->host,
23709                                         "\nBe sure to specify an IP address here");
23710 -                       
23711 +
23712                         return -1;
23713                 }
23714 +
23715                 fcgi_addr_in.sin_port = htons(proc->port);
23716                 servlen = sizeof(fcgi_addr_in);
23717 -               
23718 +
23719                 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
23720  
23721                 if (buffer_is_empty(proc->connection_name)) {
23722 @@ -1715,20 +1712,20 @@
23723                         buffer_append_long(proc->connection_name, proc->port);
23724                 }
23725         }
23726 -       
23727 +
23728         if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
23729 -               if (errno == EINPROGRESS || 
23730 +               if (errno == EINPROGRESS ||
23731                     errno == EALREADY ||
23732                     errno == EINTR) {
23733                         if (hctx->conf.debug > 2) {
23734 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
23735 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
23736                                         "connect delayed, will continue later:", proc->connection_name);
23737                         }
23738 -                       
23739 +
23740                         return CONNECTION_DELAYED;
23741                 } else if (errno == EAGAIN) {
23742                         if (hctx->conf.debug) {
23743 -                               log_error_write(srv, __FILE__, __LINE__, "sbsd", 
23744 +                               log_error_write(srv, __FILE__, __LINE__, "sbsd",
23745                                         "This means that the you have more incoming requests than your fastcgi-backend can handle in parallel. "
23746                                         "Perhaps it helps to spawn more fastcgi backend or php-children, if not decrease server.max-connections."
23747                                         "The load for this fastcgi backend", proc->connection_name, "is", proc->load);
23748 @@ -1736,8 +1733,8 @@
23749  
23750                         return CONNECTION_OVERLOADED;
23751                 } else {
23752 -                       log_error_write(srv, __FILE__, __LINE__, "sssb", 
23753 -                                       "connect failed:", 
23754 +                       log_error_write(srv, __FILE__, __LINE__, "sssb",
23755 +                                       "connect failed:",
23756                                         strerror(errno), "on",
23757                                         proc->connection_name);
23758  
23759 @@ -1747,7 +1744,7 @@
23760  
23761         hctx->reconnects = 0;
23762         if (hctx->conf.debug > 1) {
23763 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
23764 +               log_error_write(srv, __FILE__, __LINE__, "sd",
23765                                 "connect succeeded: ", fcgi_fd);
23766         }
23767  
23768 @@ -1756,21 +1753,21 @@
23769  
23770  static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
23771         size_t i;
23772 -       
23773 +
23774         for (i = 0; i < con->request.headers->used; i++) {
23775                 data_string *ds;
23776 -               
23777 +
23778                 ds = (data_string *)con->request.headers->data[i];
23779 -               
23780 +
23781                 if (ds->value->used && ds->key->used) {
23782                         size_t j;
23783                         buffer_reset(srv->tmp_buf);
23784 -                       
23785 +
23786                         if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
23787                                 BUFFER_COPY_STRING_CONST(srv->tmp_buf, "HTTP_");
23788                                 srv->tmp_buf->used--;
23789                         }
23790 -                       
23791 +
23792                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
23793                         for (j = 0; j < ds->key->used - 1; j++) {
23794                                 char c = '_';
23795 @@ -1784,20 +1781,20 @@
23796                                 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
23797                         }
23798                         srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
23799 -                       
23800 +
23801                         fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
23802                 }
23803         }
23804 -       
23805 +
23806         for (i = 0; i < con->environment->used; i++) {
23807                 data_string *ds;
23808 -               
23809 +
23810                 ds = (data_string *)con->environment->data[i];
23811 -               
23812 +
23813                 if (ds->value->used && ds->key->used) {
23814                         size_t j;
23815                         buffer_reset(srv->tmp_buf);
23816 -                       
23817 +
23818                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
23819                         for (j = 0; j < ds->key->used - 1; j++) {
23820                                 char c = '_';
23821 @@ -1811,11 +1808,11 @@
23822                                 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
23823                         }
23824                         srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
23825 -                       
23826 +
23827                         fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
23828                 }
23829         }
23830 -       
23831 +
23832         return 0;
23833  }
23834  
23835 @@ -1824,24 +1821,24 @@
23836         FCGI_BeginRequestRecord beginRecord;
23837         FCGI_Header header;
23838         buffer *b;
23839 -       
23840 +
23841         char buf[32];
23842         const char *s;
23843  #ifdef HAVE_IPV6
23844         char b2[INET6_ADDRSTRLEN + 1];
23845  #endif
23846 -       
23847 +
23848         plugin_data *p    = hctx->plugin_data;
23849         fcgi_extension_host *host= hctx->host;
23850  
23851         connection *con   = hctx->remote_conn;
23852         server_socket *srv_sock = con->srv_socket;
23853 -       
23854 +
23855         sock_addr our_addr;
23856         socklen_t our_addr_len;
23857 -       
23858 +
23859         /* send FCGI_BEGIN_REQUEST */
23860 -       
23861 +
23862         fcgi_header(&(beginRecord.header), FCGI_BEGIN_REQUEST, request_id, sizeof(beginRecord.body), 0);
23863         beginRecord.body.roleB0 = host->mode;
23864         beginRecord.body.roleB1 = 0;
23865 @@ -1849,21 +1846,21 @@
23866         memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved));
23867  
23868         b = chunkqueue_get_append_buffer(hctx->wb);
23869 -       
23870 +
23871         buffer_copy_memory(b, (const char *)&beginRecord, sizeof(beginRecord));
23872 -       
23873 +
23874         /* send FCGI_PARAMS */
23875         buffer_prepare_copy(p->fcgi_env, 1024);
23876  
23877  
23878         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
23879 -       
23880 +
23881         if (con->server_name->used) {
23882                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
23883         } else {
23884  #ifdef HAVE_IPV6
23885 -               s = inet_ntop(srv_sock->addr.plain.sa_family, 
23886 -                             srv_sock->addr.plain.sa_family == AF_INET6 ? 
23887 +               s = inet_ntop(srv_sock->addr.plain.sa_family,
23888 +                             srv_sock->addr.plain.sa_family == AF_INET6 ?
23889                               (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
23890                               (const void *) &(srv_sock->addr.ipv4.sin_addr),
23891                               b2, sizeof(b2)-1);
23892 @@ -1872,50 +1869,50 @@
23893  #endif
23894                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
23895         }
23896 -       
23897 +
23898         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
23899 -       
23900 -       ltostr(buf, 
23901 +
23902 +       ltostr(buf,
23903  #ifdef HAVE_IPV6
23904                ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
23905  #else
23906                ntohs(srv_sock->addr.ipv4.sin_port)
23907  #endif
23908                );
23909 -       
23910 +
23911         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
23912 -       
23913 +
23914         /* get the server-side of the connection to the client */
23915         our_addr_len = sizeof(our_addr);
23916 -       
23917 -       if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
23918 +
23919 +       if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
23920                 s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
23921         } else {
23922                 s = inet_ntop_cache_get_ip(srv, &(our_addr));
23923         }
23924         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
23925 -       
23926 -       ltostr(buf, 
23927 +
23928 +       ltostr(buf,
23929  #ifdef HAVE_IPV6
23930                ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
23931  #else
23932                ntohs(con->dst_addr.ipv4.sin_port)
23933  #endif
23934                );
23935 -       
23936 +
23937         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
23938 -       
23939 +
23940         s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
23941         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
23942 -       
23943 +
23944         if (!buffer_is_empty(con->authed_user)) {
23945                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_USER"),
23946                              CONST_BUF_LEN(con->authed_user));
23947         }
23948 -       
23949 +
23950         if (con->request.content_length > 0 && host->mode != FCGI_AUTHORIZER) {
23951                 /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
23952 -               
23953 +
23954                 /* request.content_length < SSIZE_MAX, see request.c */
23955                 ltostr(buf, con->request.content_length);
23956                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
23957 @@ -1930,12 +1927,12 @@
23958                  */
23959  
23960                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
23961 -               
23962 +
23963                 if (!buffer_is_empty(con->request.pathinfo)) {
23964                         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
23965 -                       
23966 +
23967                         /* PATH_TRANSLATED is only defined if PATH_INFO is set */
23968 -                       
23969 +
23970                         if (!buffer_is_empty(host->docroot)) {
23971                                 buffer_copy_string_buffer(p->path, host->docroot);
23972                         } else {
23973 @@ -1957,27 +1954,27 @@
23974          */
23975  
23976         if (!buffer_is_empty(host->docroot)) {
23977 -               /* 
23978 -                * rewrite SCRIPT_FILENAME 
23979 -                * 
23980 +               /*
23981 +                * rewrite SCRIPT_FILENAME
23982 +                *
23983                  */
23984 -               
23985 +
23986                 buffer_copy_string_buffer(p->path, host->docroot);
23987                 buffer_append_string_buffer(p->path, con->uri.path);
23988 -               
23989 +
23990                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
23991                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot));
23992         } else {
23993                 buffer_copy_string_buffer(p->path, con->physical.path);
23994 -               
23995 -               /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself 
23996 -                * 
23997 +
23998 +               /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself
23999 +                *
24000                  * see src/sapi/cgi_main.c, init_request_info()
24001                  */
24002                 if (host->break_scriptfilename_for_php) {
24003                         buffer_append_string_buffer(p->path, con->request.pathinfo);
24004                 }
24005 -               
24006 +
24007                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
24008                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
24009         }
24010 @@ -1987,7 +1984,7 @@
24011                 /**
24012                  * /app1/index/list
24013                  *
24014 -                * stripping /app1 or /app1/ should lead to 
24015 +                * stripping /app1 or /app1/ should lead to
24016                  *
24017                  * /index/list
24018                  *
24019 @@ -2001,7 +1998,7 @@
24020                     0 == strncmp(con->request.orig_uri->ptr, host->strip_request_uri->ptr, host->strip_request_uri->used - 1)) {
24021                         /* the left is the same */
24022  
24023 -                       fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), 
24024 +                       fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"),
24025                                         con->request.orig_uri->ptr + (host->strip_request_uri->used - 2),
24026                                         con->request.orig_uri->used - (host->strip_request_uri->used - 2));
24027                 } else {
24028 @@ -2018,26 +2015,26 @@
24029         } else {
24030                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
24031         }
24032 -       
24033 +
24034         s = get_http_method_name(con->request.http_method);
24035         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
24036         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
24037         s = get_http_version_name(con->request.http_version);
24038         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
24039 -       
24040 +
24041  #ifdef USE_OPENSSL
24042         if (srv_sock->is_ssl) {
24043                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
24044         }
24045  #endif
24046 -       
24047 -       
24048 +
24049 +
24050         fcgi_env_add_request_headers(srv, con, p);
24051 -       
24052 +
24053         fcgi_header(&(header), FCGI_PARAMS, request_id, p->fcgi_env->used, 0);
24054         buffer_append_memory(b, (const char *)&header, sizeof(header));
24055         buffer_append_memory(b, (const char *)p->fcgi_env->ptr, p->fcgi_env->used);
24056 -       
24057 +
24058         fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0);
24059         buffer_append_memory(b, (const char *)&header, sizeof(header));
24060  
24061 @@ -2057,7 +2054,7 @@
24062  
24063                         /* we announce toWrite octects
24064                          * now take all the request_content chunk that we need to fill this request
24065 -                        * */   
24066 +                        * */
24067  
24068                         b = chunkqueue_get_append_buffer(hctx->wb);
24069                         fcgi_header(&(header), FCGI_STDIN, request_id, weWant, 0);
24070 @@ -2080,16 +2077,16 @@
24071                                         if (weHave > weWant - written) weHave = weWant - written;
24072  
24073                                         if (p->conf.debug > 10) {
24074 -                                               fprintf(stderr, "%s.%d: sending %lld bytes from (%lld / %lld) %s\n", 
24075 -                                                               __FILE__, __LINE__, 
24076 -                                                               weHave, 
24077 -                                                               req_c->offset, 
24078 -                                                               req_c->file.length, 
24079 +                                               fprintf(stderr, "%s.%d: sending %lld bytes from (%lld / %lld) %s\n",
24080 +                                                               __FILE__, __LINE__,
24081 +                                                               weHave,
24082 +                                                               req_c->offset,
24083 +                                                               req_c->file.length,
24084                                                                 req_c->file.name->ptr);
24085                                         }
24086  
24087                                         assert(weHave != 0);
24088 -                                       
24089 +
24090                                         chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave);
24091  
24092                                         req_c->offset += weHave;
24093 @@ -2104,7 +2101,7 @@
24094                                          * - we reference the tempfile from the request-content-queue several times
24095                                          *   if the req_c is larger than FCGI_MAX_LENGTH
24096                                          * - we can't simply cleanup the request-content-queue as soon as possible
24097 -                                        *   as it would remove the tempfiles 
24098 +                                        *   as it would remove the tempfiles
24099                                          * - the idea is to 'steal' the tempfiles and attach the is_temp flag to the last
24100                                          *   referencing chunk of the fastcgi-write-queue
24101                                          *
24102 @@ -2141,7 +2138,7 @@
24103                                         req_c->offset += weHave;
24104                                         req_cq->bytes_out += weHave;
24105                                         written += weHave;
24106 -                                       
24107 +
24108                                         hctx->wb->bytes_in += weHave;
24109  
24110                                         if (req_c->offset == req_c->mem->used - 1) {
24111 @@ -2155,12 +2152,12 @@
24112                                         break;
24113                                 }
24114                         }
24115 -                       
24116 +
24117                         b->used++; /* add virtual \0 */
24118                         offset += weWant;
24119                 }
24120         }
24121 -       
24122 +
24123         b = chunkqueue_get_append_buffer(hctx->wb);
24124         /* terminate STDIN */
24125         fcgi_header(&(header), FCGI_STDIN, request_id, 0, 0);
24126 @@ -2175,118 +2172,19 @@
24127                 if ((i+1) % 16 == 0) {
24128                         size_t j;
24129                         for (j = i-15; j <= i; j++) {
24130 -                               fprintf(stderr, "%c", 
24131 +                               fprintf(stderr, "%c",
24132                                         isprint((unsigned char)hctx->write_buffer->ptr[j]) ? hctx->write_buffer->ptr[j] : '.');
24133                         }
24134                         fprintf(stderr, "\n");
24135                 }
24136         }
24137  #endif
24138 -       
24139 -       return 0;
24140 -}
24141 -
24142 -static int fcgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
24143 -       char *s, *ns;
24144 -       
24145 -       handler_ctx *hctx = con->plugin_ctx[p->id];
24146 -       fcgi_extension_host *host= hctx->host;
24147 -       
24148 -       UNUSED(srv);
24149  
24150 -       buffer_copy_string_buffer(p->parse_response, in);
24151 -       
24152 -       /* search for \n */
24153 -       for (s = p->parse_response->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1) {
24154 -               char *key, *value;
24155 -               int key_len;
24156 -               data_string *ds;
24157 -               
24158 -               /* a good day. Someone has read the specs and is sending a \r\n to us */
24159 -               
24160 -               if (ns > p->parse_response->ptr &&
24161 -                   *(ns-1) == '\r') {
24162 -                       *(ns-1) = '\0';
24163 -               }
24164 -               
24165 -               ns[0] = '\0';
24166 -               
24167 -               key = s;
24168 -               if (NULL == (value = strchr(s, ':'))) {
24169 -                       /* we expect: "<key>: <value>\n" */
24170 -                       continue;
24171 -               }
24172 -               
24173 -               key_len = value - key;
24174 -               
24175 -               value++;
24176 -               /* strip WS */
24177 -               while (*value == ' ' || *value == '\t') value++;
24178 -               
24179 -               if (host->mode != FCGI_AUTHORIZER ||
24180 -                   !(con->http_status == 0 ||
24181 -                     con->http_status == 200)) {
24182 -                       /* authorizers shouldn't affect the response headers sent back to the client */
24183 -                       
24184 -                       /* don't forward Status: */
24185 -                       if (0 != strncasecmp(key, "Status", key_len)) {
24186 -                               if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
24187 -                                       ds = data_response_init();
24188 -                               }
24189 -                               buffer_copy_string_len(ds->key, key, key_len);
24190 -                               buffer_copy_string(ds->value, value);
24191 -                               
24192 -                               array_insert_unique(con->response.headers, (data_unset *)ds);
24193 -                       }
24194 -               }
24195 -               
24196 -               switch(key_len) {
24197 -               case 4:
24198 -                       if (0 == strncasecmp(key, "Date", key_len)) {
24199 -                               con->parsed_response |= HTTP_DATE;
24200 -                       }
24201 -                       break;
24202 -               case 6:
24203 -                       if (0 == strncasecmp(key, "Status", key_len)) {
24204 -                               con->http_status = strtol(value, NULL, 10);
24205 -                               con->parsed_response |= HTTP_STATUS;
24206 -                       }
24207 -                       break;
24208 -               case 8:
24209 -                       if (0 == strncasecmp(key, "Location", key_len)) {
24210 -                               con->parsed_response |= HTTP_LOCATION;
24211 -                       }
24212 -                       break;
24213 -               case 10:
24214 -                       if (0 == strncasecmp(key, "Connection", key_len)) {
24215 -                               con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
24216 -                               con->parsed_response |= HTTP_CONNECTION;
24217 -                       }
24218 -                       break;
24219 -               case 14:
24220 -                       if (0 == strncasecmp(key, "Content-Length", key_len)) {
24221 -                               con->response.content_length = strtol(value, NULL, 10);
24222 -                               con->parsed_response |= HTTP_CONTENT_LENGTH;
24223 -                               
24224 -                               if (con->response.content_length < 0) con->response.content_length = 0;
24225 -                       }
24226 -                       break;
24227 -               default:
24228 -                       break;
24229 -               }
24230 -       }
24231 -       
24232 -       /* CGI/1.1 rev 03 - 7.2.1.2 */
24233 -       if ((con->parsed_response & HTTP_LOCATION) &&
24234 -           !(con->parsed_response & HTTP_STATUS)) {
24235 -               con->http_status = 302;
24236 -       }
24237 -       
24238         return 0;
24239  }
24240  
24241  typedef struct {
24242 -       buffer  *b; 
24243 +       buffer  *b;
24244         size_t   len;
24245         int      type;
24246         int      padding;
24247 @@ -2327,9 +2225,9 @@
24248                 return -1;
24249         }
24250  
24251 -       /* we have at least a header, now check how much me have to fetch */ 
24252 +       /* we have at least a header, now check how much me have to fetch */
24253         header = (FCGI_Header *)(packet->b->ptr);
24254 -                       
24255 +
24256         packet->len = (header->contentLengthB0 | (header->contentLengthB1 << 8)) + header->paddingLength;
24257         packet->request_id = (header->requestIdB0 | (header->requestIdB1 << 8));
24258         packet->type = header->type;
24259 @@ -2348,7 +2246,7 @@
24260                         size_t weHave = c->mem->used - c->offset - offset - 1;
24261  
24262                         if (weHave > weWant) weHave = weWant;
24263 -                                               
24264 +
24265                         buffer_append_string_len(packet->b, c->mem->ptr + c->offset + offset, weHave);
24266  
24267                         /* we only skipped the first 8 bytes as they are the fcgi header */
24268 @@ -2380,65 +2278,42 @@
24269         }
24270  
24271         chunkqueue_remove_finished_chunks(hctx->rb);
24272 -       
24273 +
24274         return 0;
24275  }
24276  
24277  static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
24278         int fin = 0;
24279 -       int toread;
24280 -       ssize_t r;
24281 -       
24282 +
24283         plugin_data *p    = hctx->plugin_data;
24284         connection *con   = hctx->remote_conn;
24285 -       int fcgi_fd       = hctx->fd;
24286         fcgi_extension_host *host= hctx->host;
24287         fcgi_proc *proc   = hctx->proc;
24288 -       
24289 -       /* 
24290 -        * check how much we have to read 
24291 -        */
24292 -       if (ioctl(hctx->fd, FIONREAD, &toread)) {
24293 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
24294 -                               "unexpected end-of-file (perhaps the fastcgi process died):",
24295 -                               fcgi_fd);
24296 -               return -1;
24297 -       }
24298 -       
24299 -       /* init read-buffer */
24300 -       
24301 -       if (toread > 0) {
24302 -               buffer *b;
24303 -
24304 -               b = chunkqueue_get_append_buffer(hctx->rb);
24305 -               buffer_prepare_copy(b, toread + 1);
24306 -
24307 -               /* append to read-buffer */
24308 -               if (-1 == (r = read(hctx->fd, b->ptr, toread))) {
24309 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
24310 -                                       "unexpected end-of-file (perhaps the fastcgi process died):",
24311 -                                       fcgi_fd, strerror(errno));
24312 -                       return -1;
24313 -               }
24314 -               
24315 -               /* this should be catched by the b > 0 above */
24316 -               assert(r);
24317 +       handler_t ret;
24318  
24319 -               b->used = r + 1; /* one extra for the fake \0 */
24320 -               b->ptr[b->used - 1] = '\0';
24321 -       } else {
24322 -               log_error_write(srv, __FILE__, __LINE__, "ssdsb", 
24323 -                               "unexpected end-of-file (perhaps the fastcgi process died):",
24324 -                               "pid:", proc->pid,
24325 -                               "socket:", proc->connection_name);
24326 -               
24327 +       /* in case we read nothing, check the return code
24328 +        * if we got something, be happy :)
24329 +        *
24330 +        * Ok, to be honest:
24331 +        * - it is fine to receive a EAGAIN on a second read() call
24332 +        * - it might be fine they we get a con-close on a second read() call */
24333 +       switch(srv->network_backend_read(srv, con, hctx->sock, hctx->rb)) {
24334 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
24335 +               /* a EAGAIN after we read exactly the chunk-size */
24336 +
24337 +               ERROR("%s", "oops, got a EAGAIN even if we just got call for the event, wired");
24338 +               return -1;
24339 +       case NETWORK_STATUS_SUCCESS:
24340 +               break;
24341 +       default:
24342 +               ERROR("reading from fastcgi socket failed (fd=%d)", hctx->sock->fd);
24343                 return -1;
24344         }
24345  
24346         /*
24347          * parse the fastcgi packets and forward the content to the write-queue
24348          *
24349 -        */     
24350 +        */
24351         while (fin == 0) {
24352                 fastcgi_response_packet packet;
24353  
24354 @@ -2454,92 +2329,136 @@
24355  
24356                         /* is the header already finished */
24357                         if (0 == con->file_started) {
24358 -                               char *c;
24359 -                               size_t blen;
24360 -                               data_string *ds;
24361 -                                       
24362 -                               /* search for header terminator 
24363 -                                * 
24364 -                                * if we start with \r\n check if last packet terminated with \r\n
24365 -                                * if we start with \n check if last packet terminated with \n
24366 -                                * search for \r\n\r\n
24367 -                                * search for \n\n
24368 -                                */
24369 -
24370 -                               if (hctx->response_header->used == 0) {
24371 -                                       buffer_copy_string_buffer(hctx->response_header, packet.b);
24372 -                               } else {
24373 -                                       buffer_append_string_buffer(hctx->response_header, packet.b);
24374 -                               }
24375 -
24376 -                               if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\r\n\r\n")))) {
24377 -                                       blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 4;
24378 -                                       hctx->response_header->used = (c - hctx->response_header->ptr) + 3;
24379 -                                       c += 4; /* point the the start of the response */
24380 -                               } else if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\n\n")))) {
24381 -                                       blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 2;
24382 -                                       hctx->response_header->used = c - hctx->response_header->ptr + 2;
24383 -                                       c += 2; /* point the the start of the response */
24384 -                               } else {
24385 -                                       /* no luck, no header found */
24386 +                               int have_content_length = 0;
24387 +                               int need_more = 0;
24388 +                               size_t i;
24389 +
24390 +                               /* append the current packet to the chunk queue */
24391 +                               chunkqueue_append_buffer(hctx->http_rb, packet.b);
24392 +                               http_response_reset(p->resp);
24393 +
24394 +                               switch(http_response_parse_cq(hctx->http_rb, p->resp)) {
24395 +                               case PARSE_ERROR:
24396 +                                       /* parsing the response header failed */
24397 +
24398 +                                       con->http_status = 502; /* Bad Gateway */
24399 +
24400 +                                       return 1;
24401 +                               case PARSE_NEED_MORE:
24402 +                                       need_more = 1;
24403 +                                       break; /* leave the loop */
24404 +                               case PARSE_SUCCESS:
24405                                         break;
24406 +                               default:
24407 +                                       /* should not happen */
24408 +                                       SEGFAULT();
24409                                 }
24410  
24411 -                               /* parse the response header */
24412 -                               fcgi_response_parse(srv, con, p, hctx->response_header);
24413 +                               if (need_more) break;
24414  
24415 -                               con->file_started = 1;
24416 +                               chunkqueue_remove_finished_chunks(hctx->http_rb);
24417 +
24418 +                               con->http_status = p->resp->status;
24419 +                               hctx->send_content_body = 1;
24420  
24421 -                               if (host->mode == FCGI_AUTHORIZER &&
24422 -                                   (con->http_status == 0 ||
24423 -                                    con->http_status == 200)) {
24424 -                                       /* a authorizer with approved the static request, ignore the content here */
24425 -                                       hctx->send_content_body = 0;
24426 -                               }
24427 -
24428 -                               if (host->allow_xsendfile &&
24429 -                                   NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-LIGHTTPD-send-file"))) {
24430 -                                       stat_cache_entry *sce;
24431 -
24432 -                                       if (HANDLER_ERROR != stat_cache_get_entry(srv, con, ds->value, &sce)) {
24433 -                                               /* found */
24434 -
24435 -                                               http_chunk_append_file(srv, con, ds->value, 0, sce->st.st_size);
24436 -                                               hctx->send_content_body = 0; /* ignore the content */
24437 -                                               joblist_append(srv, con);
24438 +                               /* handle the header fields */
24439 +                               if (host->mode == FCGI_AUTHORIZER) {
24440 +                                       /* auth mode is a bit different */
24441 +
24442 +                                       if (con->http_status == 0 ||
24443 +                                           con->http_status == 200) {
24444 +                                               /* a authorizer with approved the static request, ignore the content here */
24445 +                                               hctx->send_content_body = 0;
24446                                         }
24447                                 }
24448  
24449 +                               /* copy the http-headers */
24450 +                               for (i = 0; i < p->resp->headers->used; i++) {
24451 +                                       const char *ign[] = { "Status", NULL };
24452 +                                       size_t j;
24453 +                                       data_string *ds;
24454 +
24455 +                                       data_string *header = (data_string *)p->resp->headers->data[i];
24456 +
24457 +                                       /* ignore all headers in AUTHORIZER mode */
24458 +                                       if (host->mode == FCGI_AUTHORIZER) continue;
24459 +
24460 +                                       /* some headers are ignored by default */
24461 +                                       for (j = 0; ign[j]; j++) {
24462 +                                               if (0 == strcasecmp(ign[j], header->key->ptr)) break;
24463 +                                       }
24464 +                                       if (ign[j]) continue;
24465 +
24466 +                                       if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
24467 +                                               /* CGI/1.1 rev 03 - 7.2.1.2 */
24468 +                                               con->http_status = 302;
24469 +                                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
24470 +                                               have_content_length = 1;
24471 +                                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-Sendfile")) || 
24472 +                                                  0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-LIGHTTPD-send-file"))) {
24473 +                                               
24474 +                                               stat_cache_entry *sce;
24475                                                 
24476 -                               if (hctx->send_content_body && blen > 1) {                                              
24477 -                                       /* enable chunked-transfer-encoding */
24478 +                                               if (host->allow_xsendfile &&
24479 +                                                   HANDLER_ERROR != stat_cache_get_entry(srv, con, header->value, &sce)) {
24480 +                                                       http_chunk_append_file(srv, con, header->value, 0, sce->st.st_size);
24481 +                                                       hctx->send_content_body = 0; /* ignore the content */
24482 +                                       
24483 +                                                       joblist_append(srv, con);
24484 +                                               }
24485 +
24486 +                                               continue; /* ignore header */
24487 +                                       }
24488 +                                       
24489 +                                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
24490 +                                               ds = data_response_init();
24491 +                                       }
24492 +                                       buffer_copy_string_buffer(ds->key, header->key);
24493 +                                       buffer_copy_string_buffer(ds->value, header->value);
24494 +
24495 +                                       array_insert_unique(con->response.headers, (data_unset *)ds);
24496 +                               }
24497 +
24498 +                               /* header is complete ... go on with the body */
24499 +
24500 +                               con->file_started = 1;
24501 +
24502 +                               if (hctx->send_content_body) {
24503 +                                       chunk *c = hctx->http_rb->first;
24504 +
24505 +                                       /* if we don't have a content-length enable chunked encoding 
24506 +                                        * if possible
24507 +                                        * 
24508 +                                        * TODO: move this to a later stage in the filter-queue
24509 +                                        *  */
24510                                         if (con->request.http_version == HTTP_VERSION_1_1 &&
24511 -                                           !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
24512 +                                           !have_content_length) {
24513                                                 con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
24514                                         }
24515  
24516 -                                       http_chunk_append_mem(srv, con, c, blen);
24517 +                                       /* copy the rest of the data */
24518 +                                       for (c = hctx->http_rb->first; c; c = c->next) {
24519 +                                               if (c->mem->used > 1) {
24520 +                                                       http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
24521 +                                                       c->offset = c->mem->used - 1;
24522 +                                               }
24523 +                                       }
24524 +                                       chunkqueue_remove_finished_chunks(hctx->http_rb);
24525                                         joblist_append(srv, con);
24526                                 }
24527                         } else if (hctx->send_content_body && packet.b->used > 1) {
24528 -                               if (con->request.http_version == HTTP_VERSION_1_1 &&
24529 -                                   !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
24530 -                                       /* enable chunked-transfer-encoding */
24531 -                                       con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
24532 -                               }
24533 -
24534                                 http_chunk_append_mem(srv, con, packet.b->ptr, packet.b->used);
24535                                 joblist_append(srv, con);
24536                         }
24537                         break;
24538                 case FCGI_STDERR:
24539 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
24540 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
24541                                         "FastCGI-stderr:", packet.b);
24542 -                       
24543 +
24544                         break;
24545                 case FCGI_END_REQUEST:
24546                         con->file_finished = 1;
24547 -                       
24548 +
24549                         if (host->mode != FCGI_AUTHORIZER ||
24550                             !(con->http_status == 0 ||
24551                               con->http_status == 200)) {
24552 @@ -2547,39 +2466,39 @@
24553                                 http_chunk_append_mem(srv, con, NULL, 0);
24554                                 joblist_append(srv, con);
24555                         }
24556 -                       
24557 +
24558                         fin = 1;
24559                         break;
24560                 default:
24561 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
24562 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
24563                                         "FastCGI: header.type not handled: ", packet.type);
24564                         break;
24565                 }
24566                 buffer_free(packet.b);
24567         }
24568 -       
24569 +
24570         return fin;
24571  }
24572  
24573  static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_host *host) {
24574         fcgi_proc *proc;
24575 -       
24576 +
24577         for (proc = host->first; proc; proc = proc->next) {
24578                 int status;
24579  
24580                 if (p->conf.debug > 2) {
24581 -                       log_error_write(srv, __FILE__, __LINE__,  "sbdddd", 
24582 -                                       "proc:", 
24583 +                       log_error_write(srv, __FILE__, __LINE__,  "sbdddd",
24584 +                                       "proc:",
24585                                         proc->connection_name,
24586                                         proc->state,
24587                                         proc->is_local,
24588                                         proc->load,
24589                                         proc->pid);
24590                 }
24591 -               
24592 -               /* 
24593 +
24594 +               /*
24595                  * if the remote side is overloaded, we check back after <n> seconds
24596 -                * 
24597 +                *
24598                  */
24599                 switch (proc->state) {
24600                 case PROC_STATE_KILLED:
24601 @@ -2592,13 +2511,13 @@
24602                         break;
24603                 case PROC_STATE_OVERLOADED:
24604                         if (srv->cur_ts <= proc->disabled_until) break;
24605 -                       
24606 +
24607                         proc->state = PROC_STATE_RUNNING;
24608                         host->active_procs++;
24609 -                       
24610 -                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", 
24611 -                                       "fcgi-server re-enabled:", 
24612 -                                       host->host, host->port, 
24613 +
24614 +                       log_error_write(srv, __FILE__, __LINE__,  "sbdb",
24615 +                                       "fcgi-server re-enabled:",
24616 +                                       host->host, host->port,
24617                                         host->unixsocket);
24618                         break;
24619                 case PROC_STATE_DIED_WAIT_FOR_PID:
24620 @@ -2606,7 +2525,7 @@
24621                         if (!proc->is_local) break;
24622  
24623                         /* the child should not terminate at all */
24624 -                       
24625 +#ifndef _WIN32
24626                         switch(waitpid(proc->pid, &status, WNOHANG)) {
24627                         case 0:
24628                                 /* child is still alive */
24629 @@ -2616,45 +2535,45 @@
24630                         default:
24631                                 if (WIFEXITED(status)) {
24632  #if 0
24633 -                                       log_error_write(srv, __FILE__, __LINE__, "sdsd", 
24634 +                                       log_error_write(srv, __FILE__, __LINE__, "sdsd",
24635                                                         "child exited, pid:", proc->pid,
24636                                                         "status:", WEXITSTATUS(status));
24637  #endif
24638                                 } else if (WIFSIGNALED(status)) {
24639 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
24640 -                                                       "child signaled:", 
24641 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
24642 +                                                       "child signaled:",
24643                                                         WTERMSIG(status));
24644                                 } else {
24645 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
24646 -                                                       "child died somehow:", 
24647 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
24648 +                                                       "child died somehow:",
24649                                                         status);
24650                                 }
24651 -                               
24652 +
24653                                 proc->state = PROC_STATE_DIED;
24654                                 break;
24655                         }
24656 -
24657 +#endif
24658                         /* fall through if we have a dead proc now */
24659                         if (proc->state != PROC_STATE_DIED) break;
24660  
24661                 case PROC_STATE_DIED:
24662 -                       /* local proc get restarted by us, 
24663 +                       /* local proc get restarted by us,
24664                          * remote ones hopefully by the admin */
24665 -                       
24666 +
24667                         if (proc->is_local) {
24668                                 /* we still have connections bound to this proc,
24669                                  * let them terminate first */
24670                                 if (proc->load != 0) break;
24671 -                       
24672 +
24673                                 /* restart the child */
24674 -                               
24675 +
24676                                 if (p->conf.debug) {
24677                                         log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
24678                                                         "--- fastcgi spawning",
24679                                                         "\n\tsocket", proc->connection_name,
24680                                                         "\n\tcurrent:", 1, "/", host->min_procs);
24681                                 }
24682 -                               
24683 +
24684                                 if (fcgi_spawn_connection(srv, p, host, proc)) {
24685                                         log_error_write(srv, __FILE__, __LINE__, "s",
24686                                                         "ERROR: spawning fcgi failed.");
24687 @@ -2662,18 +2581,18 @@
24688                                 }
24689                         } else {
24690                                 if (srv->cur_ts <= proc->disabled_until) break;
24691 -                       
24692 +
24693                                 proc->state = PROC_STATE_RUNNING;
24694                                 host->active_procs++;
24695 -                       
24696 -                               log_error_write(srv, __FILE__, __LINE__,  "sb", 
24697 -                                               "fcgi-server re-enabled:", 
24698 +
24699 +                               log_error_write(srv, __FILE__, __LINE__,  "sb",
24700 +                                               "fcgi-server re-enabled:",
24701                                                 proc->connection_name);
24702                         }
24703                         break;
24704                 }
24705         }
24706 -       
24707 +
24708         return 0;
24709  }
24710  
24711 @@ -2682,19 +2601,19 @@
24712         fcgi_extension_host *host= hctx->host;
24713         connection *con   = hctx->remote_conn;
24714         fcgi_proc  *proc;
24715 -       
24716 +
24717         int ret;
24718  
24719 -       /* sanity check */      
24720 +       /* sanity check */
24721         if (!host ||
24722             ((!host->host->used || !host->port) && !host->unixsocket->used)) {
24723 -               log_error_write(srv, __FILE__, __LINE__, "sxddd", 
24724 +               log_error_write(srv, __FILE__, __LINE__, "sxddd",
24725                                 "write-req: error",
24726                                 host,
24727                                 host->host->used,
24728                                 host->port,
24729                                 host->unixsocket->used);
24730 -                       
24731 +
24732                 hctx->proc->disabled_until = srv->cur_ts + 10;
24733                 hctx->proc->state = PROC_STATE_DIED;
24734  
24735 @@ -2705,12 +2624,12 @@
24736         if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
24737                 int socket_error;
24738                 socklen_t socket_error_len = sizeof(socket_error);
24739 -                       
24740 +
24741                 /* try to finish the connect() */
24742 -               if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
24743 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
24744 +               if (0 != getsockopt(hctx->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
24745 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
24746                                         "getsockopt failed:", strerror(errno));
24747 -                       
24748 +
24749                         hctx->proc->disabled_until = srv->cur_ts + 10;
24750                         hctx->proc->state = PROC_STATE_DIED;
24751  
24752 @@ -2719,12 +2638,12 @@
24753                 if (socket_error != 0) {
24754                         if (!hctx->proc->is_local || p->conf.debug) {
24755                                 /* local procs get restarted */
24756 -                               
24757 +
24758                                 log_error_write(srv, __FILE__, __LINE__, "sssb",
24759 -                                               "establishing connection failed:", strerror(socket_error), 
24760 +                                               "establishing connection failed:", strerror(socket_error),
24761                                                 "socket:", hctx->proc->connection_name);
24762                         }
24763 -       
24764 +
24765                         hctx->proc->disabled_until = srv->cur_ts + 5;
24766  
24767                         if (hctx->proc->is_local) {
24768 @@ -2732,17 +2651,17 @@
24769                         } else {
24770                                 hctx->proc->state = PROC_STATE_DIED;
24771                         }
24772 -       
24773 +
24774                         hctx->proc->state = PROC_STATE_DIED;
24775 -               
24776 +
24777                         fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
24778                         buffer_append_string(p->statuskey, ".died");
24779  
24780                         status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
24781 -               
24782 +
24783                         return HANDLER_ERROR;
24784                 }
24785 -               /* go on with preparing the request */ 
24786 +               /* go on with preparing the request */
24787                 hctx->state = FCGI_STATE_PREPARE_WRITE;
24788         }
24789  
24790 @@ -2755,14 +2674,14 @@
24791                 /* do we have a running process for this host (max-procs) ? */
24792                 hctx->proc = NULL;
24793  
24794 -               for (proc = hctx->host->first; 
24795 -                    proc && proc->state != PROC_STATE_RUNNING; 
24796 +               for (proc = hctx->host->first;
24797 +                    proc && proc->state != PROC_STATE_RUNNING;
24798                      proc = proc->next);
24799 -                       
24800 +
24801                 /* all childs are dead */
24802                 if (proc == NULL) {
24803 -                       hctx->fde_ndx = -1;
24804 -               
24805 +                       hctx->sock->fde_ndx = -1;
24806 +
24807                         return HANDLER_ERROR;
24808                 }
24809  
24810 @@ -2775,50 +2694,50 @@
24811                 }
24812  
24813                 ret = host->unixsocket->used ? AF_UNIX : AF_INET;
24814 -               
24815 -               if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
24816 +
24817 +               if (-1 == (hctx->sock->fd = socket(ret, SOCK_STREAM, 0))) {
24818                         if (errno == EMFILE ||
24819                             errno == EINTR) {
24820 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
24821 -                                               "wait for fd at connection:", con->fd);
24822 -                               
24823 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
24824 +                                               "wait for fd at connection:", con->sock->fd);
24825 +
24826                                 return HANDLER_WAIT_FOR_FD;
24827                         }
24828 -                       
24829 -                       log_error_write(srv, __FILE__, __LINE__, "ssdd", 
24830 +
24831 +                       log_error_write(srv, __FILE__, __LINE__, "ssdd",
24832                                         "socket failed:", strerror(errno), srv->cur_fds, srv->max_fds);
24833                         return HANDLER_ERROR;
24834                 }
24835 -               hctx->fde_ndx = -1;
24836 -               
24837 +               hctx->sock->fde_ndx = -1;
24838 +
24839                 srv->cur_fds++;
24840 -               
24841 -               fdevent_register(srv->ev, hctx->fd, fcgi_handle_fdevent, hctx);
24842 -               
24843 -               if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
24844 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
24845 +
24846 +               fdevent_register(srv->ev, hctx->sock, fcgi_handle_fdevent, hctx);
24847 +
24848 +               if (-1 == fdevent_fcntl_set(srv->ev, hctx->sock)) {
24849 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
24850                                         "fcntl failed:", strerror(errno));
24851 -                       
24852 +
24853                         return HANDLER_ERROR;
24854                 }
24855 -                       
24856 +
24857                 if (hctx->proc->is_local) {
24858                         hctx->pid = hctx->proc->pid;
24859                 }
24860 -                       
24861 +
24862                 switch (fcgi_establish_connection(srv, hctx)) {
24863                 case CONNECTION_DELAYED:
24864                         /* connection is in progress, wait for an event and call getsockopt() below */
24865 -                       
24866 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
24867 -                       
24868 +
24869 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
24870 +
24871                         fcgi_set_state(srv, hctx, FCGI_STATE_CONNECT_DELAYED);
24872                         return HANDLER_WAIT_FOR_EVENT;
24873                 case CONNECTION_OVERLOADED:
24874                         /* cool down the backend, it is overloaded
24875                          * -> EAGAIN */
24876  
24877 -                       log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
24878 +                       log_error_write(srv, __FILE__, __LINE__, "ssdsd",
24879                                 "backend is overloaded, we disable it for a 2 seconds and send the request to another backend instead:",
24880                                 "reconnects:", hctx->reconnects,
24881                                 "load:", host->load);
24882 @@ -2831,7 +2750,7 @@
24883                         buffer_append_string(p->statuskey, ".overloaded");
24884  
24885                         status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
24886 -                       
24887 +
24888                         return HANDLER_ERROR;
24889                 case CONNECTION_DEAD:
24890                         /* we got a hard error from the backend like
24891 @@ -2840,19 +2759,19 @@
24892                          *
24893                          * for check if the host is back in 5 seconds
24894                          *  */
24895 -                       
24896 +
24897                         hctx->proc->disabled_until = srv->cur_ts + 5;
24898                         if (hctx->proc->is_local) {
24899                                 hctx->proc->state = PROC_STATE_DIED_WAIT_FOR_PID;
24900                         } else {
24901                                 hctx->proc->state = PROC_STATE_DIED;
24902                         }
24903 -       
24904 -                       log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
24905 +
24906 +                       log_error_write(srv, __FILE__, __LINE__, "ssdsd",
24907                                 "backend died, we disable it for a 5 seconds and send the request to another backend instead:",
24908                                 "reconnects:", hctx->reconnects,
24909                                 "load:", host->load);
24910 -       
24911 +
24912                         fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
24913                         buffer_append_string(p->statuskey, ".died");
24914  
24915 @@ -2863,19 +2782,19 @@
24916                         /* everything is ok, go on */
24917  
24918                         fcgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
24919 -                       
24920 +
24921                         break;
24922                 case CONNECTION_UNSET:
24923                         break;
24924                 }
24925 -               
24926 +
24927         case FCGI_STATE_PREPARE_WRITE:
24928                 /* ok, we have the connection */
24929 -               
24930 +
24931                 hctx->proc->load++;
24932                 hctx->proc->last_used = srv->cur_ts;
24933                 hctx->got_proc = 1;
24934 -       
24935 +
24936                 status_counter_inc(srv, CONST_STR_LEN("fastcgi.requests"));
24937                 status_counter_inc(srv, CONST_STR_LEN("fastcgi.active-requests"));
24938  
24939 @@ -2898,9 +2817,9 @@
24940  
24941                 if (p->conf.debug) {
24942                         log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
24943 -                                       "got proc:", 
24944 -                                       "pid:", hctx->proc->pid, 
24945 -                                       "socket:", hctx->proc->connection_name, 
24946 +                                       "got proc:",
24947 +                                       "pid:", hctx->proc->pid,
24948 +                                       "socket:", hctx->proc->connection_name,
24949                                         "load:", hctx->proc->load);
24950                 }
24951  
24952 @@ -2908,74 +2827,75 @@
24953                 if (hctx->request_id == 0) {
24954                         hctx->request_id = fcgi_requestid_new(srv, p);
24955                 } else {
24956 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
24957 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
24958                                         "fcgi-request is already in use:", hctx->request_id);
24959                 }
24960 -               
24961 +
24962                 /* fall through */
24963                 fcgi_create_env(srv, hctx, hctx->request_id);
24964 -               
24965 +
24966                 fcgi_set_state(srv, hctx, FCGI_STATE_WRITE);
24967 -               
24968 +
24969                 /* fall through */
24970         case FCGI_STATE_WRITE:
24971 -               ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); 
24972 +               ret = srv->network_backend_write(srv, con, hctx->sock, hctx->wb);
24973  
24974                 chunkqueue_remove_finished_chunks(hctx->wb);
24975 -               
24976 +
24977                 if (ret < 0) {
24978                         switch(errno) {
24979                         case ENOTCONN:
24980 -                               /* the connection got dropped after accept() 
24981 -                                * 
24982 -                                * this is most of the time a PHP which dies 
24983 +                               /* the connection got dropped after accept()
24984 +                                *
24985 +                                * this is most of the time a PHP which dies
24986                                  * after PHP_FCGI_MAX_REQUESTS
24987 -                                * 
24988 -                                */ 
24989 +                                *
24990 +                                */
24991                                 if (hctx->wb->bytes_out == 0 &&
24992                                     hctx->reconnects < 5) {
24993 -                                       usleep(10000); /* take away the load of the webserver 
24994 -                                                       * to let the php a chance to restart 
24995 +#ifndef _WIN32
24996 +                                       usleep(10000); /* take away the load of the webserver
24997 +                                                       * to let the php a chance to restart
24998                                                         */
24999 -                                       
25000 +#endif
25001                                         fcgi_reconnect(srv, hctx);
25002 -                               
25003 +
25004                                         return HANDLER_WAIT_FOR_FD;
25005                                 }
25006 -                               
25007 +
25008                                 /* not reconnected ... why
25009 -                                * 
25010 +                                *
25011                                  * far@#lighttpd report this for FreeBSD
25012 -                                * 
25013 +                                *
25014                                  */
25015 -                               
25016 -                               log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
25017 +
25018 +                               log_error_write(srv, __FILE__, __LINE__, "ssosd",
25019                                                 "[REPORT ME] connection was dropped after accept(). reconnect() denied:",
25020                                                 "write-offset:", hctx->wb->bytes_out,
25021                                                 "reconnect attempts:", hctx->reconnects);
25022 -                               
25023 +
25024                                 return HANDLER_ERROR;
25025                         case EAGAIN:
25026                         case EINTR:
25027 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
25028 -                               
25029 +                               fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
25030 +
25031                                 return HANDLER_WAIT_FOR_EVENT;
25032                         default:
25033 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", 
25034 +                               log_error_write(srv, __FILE__, __LINE__, "ssd",
25035                                                 "write failed:", strerror(errno), errno);
25036 -                               
25037 +
25038                                 return HANDLER_ERROR;
25039                         }
25040                 }
25041  
25042                 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
25043                         /* we don't need the out event anymore */
25044 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
25045 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
25046 +                       fdevent_event_del(srv->ev, hctx->sock);
25047 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
25048                         fcgi_set_state(srv, hctx, FCGI_STATE_READ);
25049                 } else {
25050 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
25051 -                               
25052 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
25053 +
25054                         return HANDLER_WAIT_FOR_EVENT;
25055                 }
25056  
25057 @@ -2987,7 +2907,7 @@
25058                 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
25059                 return HANDLER_ERROR;
25060         }
25061 -       
25062 +
25063         return HANDLER_WAIT_FOR_EVENT;
25064  }
25065  
25066 @@ -2996,18 +2916,18 @@
25067   * */
25068  SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
25069         plugin_data *p = p_d;
25070 -       
25071 +
25072         handler_ctx *hctx = con->plugin_ctx[p->id];
25073         fcgi_proc *proc;
25074         fcgi_extension_host *host;
25075 -       
25076 +
25077         if (NULL == hctx) return HANDLER_GO_ON;
25078 -       
25079 +
25080         /* not my job */
25081         if (con->mode != p->id) return HANDLER_GO_ON;
25082  
25083         /* we don't have a host yet, choose one
25084 -        * -> this happens in the first round 
25085 +        * -> this happens in the first round
25086          *    and when the host died and we have to select a new one */
25087         if (hctx->host == NULL) {
25088                 size_t k;
25089 @@ -3016,23 +2936,23 @@
25090                 /* get best server */
25091                 for (k = 0, ndx = -1; k < hctx->ext->used; k++) {
25092                         host = hctx->ext->hosts[k];
25093 -               
25094 +
25095                         /* we should have at least one proc that can do something */
25096                         if (host->active_procs == 0) continue;
25097  
25098                         if (used == -1 || host->load < used) {
25099                                 used = host->load;
25100 -                       
25101 +
25102                                 ndx = k;
25103                         }
25104                 }
25105 -       
25106 +
25107                 /* found a server */
25108                 if (ndx == -1) {
25109                         /* all hosts are down */
25110  
25111                         fcgi_connection_close(srv, hctx);
25112 -                       
25113 +
25114                         con->http_status = 500;
25115                         con->mode = DIRECT;
25116  
25117 @@ -3040,16 +2960,16 @@
25118                 }
25119  
25120                 host = hctx->ext->hosts[ndx];
25121 -               
25122 -               /* 
25123 -                * if check-local is disabled, use the uri.path handler 
25124 -                * 
25125 +
25126 +               /*
25127 +                * if check-local is disabled, use the uri.path handler
25128 +                *
25129                  */
25130 -               
25131 +
25132                 /* init handler-context */
25133                 hctx->host = host;
25134  
25135 -               /* we put a connection on this host, move the other new connections to other hosts 
25136 +               /* we put a connection on this host, move the other new connections to other hosts
25137                  *
25138                  * as soon as hctx->host is unassigned, decrease the load again */
25139                 hctx->host->load++;
25140 @@ -3063,7 +2983,7 @@
25141         case HANDLER_ERROR:
25142                 proc = hctx->proc;
25143                 host = hctx->host;
25144 -               
25145 +
25146                 if (hctx->state == FCGI_STATE_INIT ||
25147                     hctx->state == FCGI_STATE_CONNECT_DELAYED) {
25148                         if (proc) host->active_procs--;
25149 @@ -3078,7 +2998,7 @@
25150                                 return HANDLER_WAIT_FOR_FD;
25151                         } else {
25152                                 fcgi_connection_close(srv, hctx);
25153 -                       
25154 +
25155                                 buffer_reset(con->physical.path);
25156                                 con->mode = DIRECT;
25157                                 con->http_status = 500;
25158 @@ -3088,12 +3008,12 @@
25159                         }
25160                 } else {
25161                         fcgi_connection_close(srv, hctx);
25162 -                       
25163 +
25164                         buffer_reset(con->physical.path);
25165                         con->mode = DIRECT;
25166                         con->http_status = 503;
25167                         joblist_append(srv, con); /* really ? */
25168 -                       
25169 +
25170                         return HANDLER_FINISHED;
25171                 }
25172         case HANDLER_WAIT_FOR_EVENT:
25173 @@ -3115,7 +3035,7 @@
25174         handler_ctx *hctx = ctx;
25175         connection  *con  = hctx->remote_conn;
25176         plugin_data *p    = hctx->plugin_data;
25177 -       
25178 +
25179         fcgi_proc *proc   = hctx->proc;
25180         fcgi_extension_host *host= hctx->host;
25181  
25182 @@ -3125,8 +3045,8 @@
25183                 case 0:
25184                         break;
25185                 case 1:
25186 -                       
25187 -                       if (host->mode == FCGI_AUTHORIZER && 
25188 +
25189 +                       if (host->mode == FCGI_AUTHORIZER &&
25190                             (con->http_status == 200 ||
25191                              con->http_status == 0)) {
25192                                 /*
25193 @@ -3136,26 +3056,26 @@
25194                                  */
25195  
25196                                 buffer_copy_string_buffer(con->physical.doc_root, host->docroot);
25197 -                               
25198 +
25199                                 buffer_copy_string_buffer(con->physical.path, host->docroot);
25200                                 buffer_append_string_buffer(con->physical.path, con->uri.path);
25201                                 fcgi_connection_close(srv, hctx);
25202 -                               
25203 +
25204                                 con->mode = DIRECT;
25205                                 con->file_started = 1; /* fcgi_extension won't touch the request afterwards */
25206                         } else {
25207                                 /* we are done */
25208                                 fcgi_connection_close(srv, hctx);
25209                         }
25210 -                       
25211 +
25212                         joblist_append(srv, con);
25213                         return HANDLER_FINISHED;
25214                 case -1:
25215                         if (proc->pid && proc->state != PROC_STATE_DIED) {
25216                                 int status;
25217 -                               
25218 +
25219                                 /* only fetch the zombie if it is not already done */
25220 -                               
25221 +#ifndef _WIN32
25222                                 switch(waitpid(proc->pid, &status, WNOHANG)) {
25223                                 case 0:
25224                                         /* child is still alive */
25225 @@ -3165,60 +3085,61 @@
25226                                 default:
25227                                         /* the child should not terminate at all */
25228                                         if (WIFEXITED(status)) {
25229 -                                               log_error_write(srv, __FILE__, __LINE__, "sdsd", 
25230 +                                               log_error_write(srv, __FILE__, __LINE__, "sdsd",
25231                                                                 "child exited, pid:", proc->pid,
25232                                                                 "status:", WEXITSTATUS(status));
25233                                         } else if (WIFSIGNALED(status)) {
25234 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
25235 -                                                               "child signaled:", 
25236 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
25237 +                                                               "child signaled:",
25238                                                                 WTERMSIG(status));
25239                                         } else {
25240 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
25241 -                                                               "child died somehow:", 
25242 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
25243 +                                                               "child died somehow:",
25244                                                                 status);
25245                                         }
25246 -                                       
25247 +
25248                                         if (p->conf.debug) {
25249                                                 log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
25250                                                                 "--- fastcgi spawning",
25251                                                                 "\n\tsocket", proc->connection_name,
25252                                                                 "\n\tcurrent:", 1, "/", host->min_procs);
25253                                         }
25254 -                                       
25255 +
25256                                         if (fcgi_spawn_connection(srv, p, host, proc)) {
25257                                                 /* respawning failed, retry later */
25258                                                 proc->state = PROC_STATE_DIED;
25259  
25260 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
25261 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
25262                                                                 "respawning failed, will retry later");
25263                                         }
25264 -                                       
25265 +
25266                                         break;
25267                                 }
25268 +#endif
25269                         }
25270  
25271                         if (con->file_started == 0) {
25272                                 /* nothing has been send out yet, try to use another child */
25273 -                               
25274 +
25275                                 if (hctx->wb->bytes_out == 0 &&
25276                                     hctx->reconnects < 5) {
25277                                         fcgi_reconnect(srv, hctx);
25278 -                                       
25279 -                                       log_error_write(srv, __FILE__, __LINE__, "ssbsbs", 
25280 +
25281 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
25282                                                 "response not received, request not sent",
25283 -                                               "on socket:", proc->connection_name, 
25284 +                                               "on socket:", proc->connection_name,
25285                                                 "for", con->uri.path, ", reconnecting");
25286 -                                       
25287 +
25288                                         return HANDLER_WAIT_FOR_FD;
25289                                 }
25290 -                       
25291 -                               log_error_write(srv, __FILE__, __LINE__, "sosbsbs", 
25292 +
25293 +                               log_error_write(srv, __FILE__, __LINE__, "sosbsbs",
25294                                                 "response not received, request sent:", hctx->wb->bytes_out,
25295 -                                               "on socket:", proc->connection_name, 
25296 +                                               "on socket:", proc->connection_name,
25297                                                 "for", con->uri.path, ", closing connection");
25298 -                               
25299 +
25300                                 fcgi_connection_close(srv, hctx);
25301 -                               
25302 +
25303                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
25304                                 buffer_reset(con->physical.path);
25305                                 con->http_status = 500;
25306 @@ -3226,76 +3147,76 @@
25307                         } else {
25308                                 /* response might have been already started, kill the connection */
25309                                 fcgi_connection_close(srv, hctx);
25310 -                               
25311 -                               log_error_write(srv, __FILE__, __LINE__, "ssbsbs", 
25312 +
25313 +                               log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
25314                                                 "response already sent out, but backend returned error",
25315 -                                               "on socket:", proc->connection_name, 
25316 +                                               "on socket:", proc->connection_name,
25317                                                 "for", con->uri.path, ", terminating connection");
25318 -                               
25319 +
25320                                 connection_set_state(srv, con, CON_STATE_ERROR);
25321                         }
25322  
25323                         /* */
25324 -                       
25325 -                       
25326 +
25327 +
25328                         joblist_append(srv, con);
25329                         return HANDLER_FINISHED;
25330                 }
25331         }
25332 -       
25333 +
25334         if (revents & FDEVENT_OUT) {
25335                 if (hctx->state == FCGI_STATE_CONNECT_DELAYED ||
25336                     hctx->state == FCGI_STATE_WRITE) {
25337                         /* we are allowed to send something out
25338 -                        * 
25339 +                        *
25340                          * 1. in a unfinished connect() call
25341                          * 2. in a unfinished write() call (long POST request)
25342                          */
25343                         return mod_fastcgi_handle_subrequest(srv, con, p);
25344                 } else {
25345 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
25346 -                                       "got a FDEVENT_OUT and didn't know why:", 
25347 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
25348 +                                       "got a FDEVENT_OUT and didn't know why:",
25349                                         hctx->state);
25350                 }
25351         }
25352 -       
25353 +
25354         /* perhaps this issue is already handled */
25355         if (revents & FDEVENT_HUP) {
25356                 if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
25357                         /* getoptsock will catch this one (right ?)
25358 -                        * 
25359 -                        * if we are in connect we might get a EINPROGRESS 
25360 -                        * in the first call and a FDEVENT_HUP in the 
25361 +                        *
25362 +                        * if we are in connect we might get a EINPROGRESS
25363 +                        * in the first call and a FDEVENT_HUP in the
25364                          * second round
25365 -                        * 
25366 +                        *
25367                          * FIXME: as it is a bit ugly.
25368 -                        * 
25369 +                        *
25370                          */
25371                         return mod_fastcgi_handle_subrequest(srv, con, p);
25372                 } else if (hctx->state == FCGI_STATE_READ &&
25373                            hctx->proc->port == 0) {
25374                         /* FIXME:
25375 -                        * 
25376 +                        *
25377                          * ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket
25378                          * even if the FCGI_FIN packet is not received yet
25379                          */
25380                 } else {
25381 -                       log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd", 
25382 -                                       "error: unexpected close of fastcgi connection for", 
25383 +                       log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
25384 +                                       "error: unexpected close of fastcgi connection for",
25385                                         con->uri.path,
25386 -                                       "(no fastcgi process on host:", 
25387 +                                       "(no fastcgi process on host:",
25388                                         host->host,
25389 -                                       ", port: ", 
25390 +                                       ", port: ",
25391                                         host->port,
25392                                         " ?)",
25393                                         hctx->state);
25394 -                       
25395 +
25396                         connection_set_state(srv, con, CON_STATE_ERROR);
25397                         fcgi_connection_close(srv, hctx);
25398                         joblist_append(srv, con);
25399                 }
25400         } else if (revents & FDEVENT_ERR) {
25401 -               log_error_write(srv, __FILE__, __LINE__, "s", 
25402 +               log_error_write(srv, __FILE__, __LINE__, "s",
25403                                 "fcgi: got a FDEVENT_ERR. Don't know why.");
25404                 /* kill all connections to the fastcgi process */
25405  
25406 @@ -3304,45 +3225,42 @@
25407                 fcgi_connection_close(srv, hctx);
25408                 joblist_append(srv, con);
25409         }
25410 -       
25411 +
25412         return HANDLER_FINISHED;
25413  }
25414 -#define PATCH(x) \
25415 -       p->conf.x = s->x;
25416 +
25417  static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) {
25418         size_t i, j;
25419         plugin_config *s = p->config_storage[0];
25420 -       
25421 -       PATCH(exts);
25422 -       PATCH(debug);
25423 -       PATCH(ext_mapping);
25424 -       
25425 +
25426 +       PATCH_OPTION(exts);
25427 +       PATCH_OPTION(debug);
25428 +       PATCH_OPTION(ext_mapping);
25429 +
25430         /* skip the first, the global context */
25431         for (i = 1; i < srv->config_context->used; i++) {
25432                 data_config *dc = (data_config *)srv->config_context->data[i];
25433                 s = p->config_storage[i];
25434 -               
25435 +
25436                 /* condition didn't match */
25437                 if (!config_check_cond(srv, con, dc)) continue;
25438 -               
25439 +
25440                 /* merge config */
25441                 for (j = 0; j < dc->value->used; j++) {
25442                         data_unset *du = dc->value->data[j];
25443 -                       
25444 +
25445                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.server"))) {
25446 -                               PATCH(exts);
25447 +                               PATCH_OPTION(exts);
25448                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.debug"))) {
25449 -                               PATCH(debug);
25450 +                               PATCH_OPTION(debug);
25451                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.map-extensions"))) {
25452 -                               PATCH(ext_mapping);
25453 +                               PATCH_OPTION(ext_mapping);
25454                         }
25455                 }
25456         }
25457 -       
25458 +
25459         return 0;
25460  }
25461 -#undef PATCH
25462 -
25463  
25464  static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
25465         plugin_data *p = p_d;
25466 @@ -3351,16 +3269,16 @@
25467         buffer *fn;
25468         fcgi_extension *extension = NULL;
25469         fcgi_extension_host *host = NULL;
25470 -       
25471 +
25472         /* Possibly, we processed already this request */
25473         if (con->file_started == 1) return HANDLER_GO_ON;
25474  
25475         fn = uri_path_handler ? con->uri.path : con->physical.path;
25476  
25477         if (buffer_is_empty(fn)) return HANDLER_GO_ON;
25478 -       
25479 +
25480         s_len = fn->used - 1;
25481 -       
25482 +
25483         fcgi_patch_connection(srv, con, p);
25484  
25485         /* fastcgi.map-extensions maps extensions to existing fastcgi.server entries
25486 @@ -3368,24 +3286,24 @@
25487          * fastcgi.map-extensions = ( ".php3" => ".php" )
25488          *
25489          * fastcgi.server = ( ".php" => ... )
25490 -        * 
25491 +        *
25492          * */
25493  
25494         /* check if extension-mapping matches */
25495         for (k = 0; k < p->conf.ext_mapping->used; k++) {
25496                 data_string *ds = (data_string *)p->conf.ext_mapping->data[k];
25497                 size_t ct_len; /* length of the config entry */
25498 -               
25499 +
25500                 if (ds->key->used == 0) continue;
25501 -               
25502 +
25503                 ct_len = ds->key->used - 1;
25504 -               
25505 +
25506                 if (s_len < ct_len) continue;
25507 -               
25508 +
25509                 /* found a mapping */
25510                 if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
25511                         /* check if we know the extension */
25512 -                       
25513 +
25514                         /* we can reuse k here */
25515                         for (k = 0; k < p->conf.exts->used; k++) {
25516                                 extension = p->conf.exts->exts[k];
25517 @@ -3407,15 +3325,15 @@
25518                 /* check if extension matches */
25519                 for (k = 0; k < p->conf.exts->used; k++) {
25520                         size_t ct_len; /* length of the config entry */
25521 -               
25522 +
25523                         extension = p->conf.exts->exts[k];
25524 -               
25525 +
25526                         if (extension->key->used == 0) continue;
25527 -               
25528 +
25529                         ct_len = extension->key->used - 1;
25530 -               
25531 +
25532                         if (s_len < ct_len) continue;
25533 -               
25534 +
25535                         /* check extension in the form "/fcgi_pattern" */
25536                         if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
25537                                 break;
25538 @@ -3441,10 +3359,10 @@
25539                         continue;
25540                 }
25541  
25542 -               /* we found one host that is alive */ 
25543 +               /* we found one host that is alive */
25544                 break;
25545         }
25546 -       
25547 +
25548         if (!host) {
25549                 /* sorry, we don't have a server alive for this ext */
25550                 buffer_reset(con->physical.path);
25551 @@ -3459,72 +3377,72 @@
25552                                         "on", extension->key,
25553                                         "are down.");
25554                 }
25555 -               
25556 +
25557                 return HANDLER_FINISHED;
25558         }
25559  
25560         /* a note about no handler is not sent yey */
25561         extension->note_is_sent = 0;
25562  
25563 -       /* 
25564 -        * if check-local is disabled, use the uri.path handler 
25565 -        * 
25566 +       /*
25567 +        * if check-local is disabled, use the uri.path handler
25568 +        *
25569          */
25570 -       
25571 +
25572         /* init handler-context */
25573         if (uri_path_handler) {
25574                 if (host->check_local == 0) {
25575                         handler_ctx *hctx;
25576                         char *pathinfo;
25577 -                       
25578 +
25579                         hctx = handler_ctx_init();
25580 -                       
25581 +
25582                         hctx->remote_conn      = con;
25583                         hctx->plugin_data      = p;
25584                         hctx->proc             = NULL;
25585                         hctx->ext              = extension;
25586 -       
25587 +
25588  
25589                         hctx->conf.exts        = p->conf.exts;
25590                         hctx->conf.debug       = p->conf.debug;
25591 -                               
25592 +
25593                         con->plugin_ctx[p->id] = hctx;
25594 -                               
25595 +
25596                         con->mode = p->id;
25597 -                               
25598 +
25599                         if (con->conf.log_request_handling) {
25600 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
25601 +                               log_error_write(srv, __FILE__, __LINE__, "s",
25602                                 "handling it in mod_fastcgi");
25603                         }
25604 -                               
25605 -                       /* the prefix is the SCRIPT_NAME, 
25606 +
25607 +                       /* the prefix is the SCRIPT_NAME,
25608                          * everthing from start to the next slash
25609                          * this is important for check-local = "disable"
25610 -                        * 
25611 +                        *
25612                          * if prefix = /admin.fcgi
25613 -                        * 
25614 +                        *
25615                          * /admin.fcgi/foo/bar
25616 -                        * 
25617 +                        *
25618                          * SCRIPT_NAME = /admin.fcgi
25619                          * PATH_INFO   = /foo/bar
25620 -                        * 
25621 +                        *
25622                          * if prefix = /fcgi-bin/
25623 -                        * 
25624 +                        *
25625                          * /fcgi-bin/foo/bar
25626 -                        * 
25627 +                        *
25628                          * SCRIPT_NAME = /fcgi-bin/foo
25629                          * PATH_INFO   = /bar
25630 -                        * 
25631 +                        *
25632                          */
25633 -                       
25634 +
25635                         /* the rewrite is only done for /prefix/? matches */
25636                         if (extension->key->ptr[0] == '/' &&
25637                             con->uri.path->used > extension->key->used &&
25638                             NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
25639 -                               /* rewrite uri.path and pathinfo */ 
25640 -                               
25641 +                               /* rewrite uri.path and pathinfo */
25642 +
25643                                 buffer_copy_string(con->request.pathinfo, pathinfo);
25644 -                               
25645 +
25646                                 con->uri.path->used -= con->request.pathinfo->used - 1;
25647                                 con->uri.path->ptr[con->uri.path->used - 1] = '\0';
25648                         }
25649 @@ -3532,19 +3450,19 @@
25650         } else {
25651                 handler_ctx *hctx;
25652                 hctx = handler_ctx_init();
25653 -               
25654 +
25655                 hctx->remote_conn      = con;
25656                 hctx->plugin_data      = p;
25657                 hctx->proc             = NULL;
25658                 hctx->ext              = extension;
25659 -               
25660 +
25661                 hctx->conf.exts        = p->conf.exts;
25662                 hctx->conf.debug       = p->conf.debug;
25663 -               
25664 +
25665                 con->plugin_ctx[p->id] = hctx;
25666 -               
25667 +
25668                 con->mode = p->id;
25669 -               
25670 +
25671                 if (con->conf.log_request_handling) {
25672                         log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
25673                 }
25674 @@ -3566,19 +3484,19 @@
25675  JOBLIST_FUNC(mod_fastcgi_handle_joblist) {
25676         plugin_data *p = p_d;
25677         handler_ctx *hctx = con->plugin_ctx[p->id];
25678 -       
25679 +
25680         if (hctx == NULL) return HANDLER_GO_ON;
25681  
25682 -       if (hctx->fd != -1) {
25683 +       if (hctx->sock->fd != -1) {
25684                 switch (hctx->state) {
25685                 case FCGI_STATE_READ:
25686 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
25687 -                       
25688 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
25689 +
25690                         break;
25691                 case FCGI_STATE_CONNECT_DELAYED:
25692                 case FCGI_STATE_WRITE:
25693 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
25694 -                       
25695 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
25696 +
25697                         break;
25698                 case FCGI_STATE_INIT:
25699                         /* at reconnect */
25700 @@ -3595,7 +3513,7 @@
25701  
25702  static handler_t fcgi_connection_close_callback(server *srv, connection *con, void *p_d) {
25703         plugin_data *p = p_d;
25704 -       
25705 +
25706         fcgi_connection_close(srv, con->plugin_ctx[p->id]);
25707  
25708         return HANDLER_GO_ON;
25709 @@ -3604,16 +3522,39 @@
25710  TRIGGER_FUNC(mod_fastcgi_handle_trigger) {
25711         plugin_data *p = p_d;
25712         size_t i, j, n;
25713 -       
25714 -       
25715 +
25716 +
25717         /* perhaps we should kill a connect attempt after 10-15 seconds
25718 -        * 
25719 +        *
25720          * currently we wait for the TCP timeout which is on Linux 180 seconds
25721 -        * 
25722 -        * 
25723 -        * 
25724 +        *
25725          */
25726  
25727 +       for (i = 0; i < srv->conns->used; i++) {
25728 +               connection *con = srv->conns->ptr[i];
25729 +               handler_ctx *hctx = con->plugin_ctx[p->id];
25730 +
25731 +               /* if a connection is ours and is in handle-req for more than max-request-time
25732 +                * kill the connection */
25733 +
25734 +               if (con->mode != p->id) continue;
25735 +               if (con->state != CON_STATE_HANDLE_REQUEST) continue;
25736 +               if (srv->cur_ts < con->request_start + 60) continue;
25737 +
25738 +               /* the request is waiting for a FCGI_STDOUT since 60 seconds */
25739 +
25740 +               /* kill the connection */
25741 +
25742 +               log_error_write(srv, __FILE__, __LINE__, "s", "fastcgi backend didn't responded after 60 seconds");
25743 +
25744 +               fcgi_connection_close(srv, hctx);
25745 +
25746 +               con->mode = DIRECT;
25747 +               con->http_status = 500;
25748 +
25749 +               joblist_append(srv, con);
25750 +       }
25751 +
25752         /* check all childs if they are still up */
25753  
25754         for (i = 0; i < srv->config_context->used; i++) {
25755 @@ -3628,45 +3569,45 @@
25756                         fcgi_extension *ex;
25757  
25758                         ex = exts->exts[j];
25759 -                       
25760 +
25761                         for (n = 0; n < ex->used; n++) {
25762 -                               
25763 +
25764                                 fcgi_proc *proc;
25765                                 unsigned long sum_load = 0;
25766                                 fcgi_extension_host *host;
25767 -                               
25768 +
25769                                 host = ex->hosts[n];
25770 -                               
25771 +
25772                                 fcgi_restart_dead_procs(srv, p, host);
25773 -                               
25774 +
25775                                 for (proc = host->first; proc; proc = proc->next) {
25776                                         sum_load += proc->load;
25777                                 }
25778 -                               
25779 +
25780                                 if (host->num_procs &&
25781                                     host->num_procs < host->max_procs &&
25782                                     (sum_load / host->num_procs) > host->max_load_per_proc) {
25783                                         /* overload, spawn new child */
25784                                         if (p->conf.debug) {
25785 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
25786 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
25787                                                                 "overload detected, spawning a new child");
25788                                         }
25789 -                                       
25790 +
25791                                         for (proc = host->unused_procs; proc && proc->pid != 0; proc = proc->next);
25792 -                                       
25793 +
25794                                         if (proc) {
25795                                                 if (proc == host->unused_procs) host->unused_procs = proc->next;
25796 -                                               
25797 +
25798                                                 if (proc->next) proc->next->prev = NULL;
25799 -                                               
25800 +
25801                                                 host->max_id++;
25802                                         } else {
25803                                                 proc = fastcgi_process_init();
25804                                                 proc->id = host->max_id++;
25805                                         }
25806 -                                       
25807 +
25808                                         host->num_procs++;
25809 -                                       
25810 +
25811                                         if (buffer_is_empty(host->unixsocket)) {
25812                                                 proc->port = host->port + proc->id;
25813                                         } else {
25814 @@ -3674,13 +3615,13 @@
25815                                                 buffer_append_string(proc->unixsocket, "-");
25816                                                 buffer_append_long(proc->unixsocket, proc->id);
25817                                         }
25818 -                                       
25819 +
25820                                         if (fcgi_spawn_connection(srv, p, host, proc)) {
25821                                                 log_error_write(srv, __FILE__, __LINE__, "s",
25822                                                                 "ERROR: spawning fcgi failed.");
25823                                                 return HANDLER_ERROR;
25824                                         }
25825 -                                       
25826 +
25827                                         proc->prev = NULL;
25828                                         proc->next = host->first;
25829                                         if (host->first) {
25830 @@ -3688,56 +3629,56 @@
25831                                         }
25832                                         host->first = proc;
25833                                 }
25834 -                               
25835 +
25836                                 for (proc = host->first; proc; proc = proc->next) {
25837                                         if (proc->load != 0) break;
25838                                         if (host->num_procs <= host->min_procs) break;
25839                                         if (proc->pid == 0) continue;
25840 -                                       
25841 +
25842                                         if (srv->cur_ts - proc->last_used > host->idle_timeout) {
25843                                                 /* a proc is idling for a long time now,
25844                                                  * terminated it */
25845 -                                               
25846 +
25847                                                 if (p->conf.debug) {
25848 -                                                       log_error_write(srv, __FILE__, __LINE__, "ssbsd", 
25849 -                                                                       "idle-timeout reached, terminating child:", 
25850 -                                                                       "socket:", proc->connection_name, 
25851 +                                                       log_error_write(srv, __FILE__, __LINE__, "ssbsd",
25852 +                                                                       "idle-timeout reached, terminating child:",
25853 +                                                                       "socket:", proc->connection_name,
25854                                                                         "pid", proc->pid);
25855                                                 }
25856 -                                               
25857 -                                               
25858 +
25859 +
25860                                                 if (proc->next) proc->next->prev = proc->prev;
25861                                                 if (proc->prev) proc->prev->next = proc->next;
25862 -                                               
25863 +
25864                                                 if (proc->prev == NULL) host->first = proc->next;
25865 -                                               
25866 +
25867                                                 proc->prev = NULL;
25868                                                 proc->next = host->unused_procs;
25869 -                                               
25870 +
25871                                                 if (host->unused_procs) host->unused_procs->prev = proc;
25872                                                 host->unused_procs = proc;
25873 -                                               
25874 +
25875                                                 kill(proc->pid, SIGTERM);
25876 -                                               
25877 +
25878                                                 proc->state = PROC_STATE_KILLED;
25879 -                                               
25880 -                                               log_error_write(srv, __FILE__, __LINE__, "ssbsd", 
25881 -                                                                       "killed:", 
25882 -                                                                       "socket:", proc->connection_name, 
25883 +
25884 +                                               log_error_write(srv, __FILE__, __LINE__, "ssbsd",
25885 +                                                                       "killed:",
25886 +                                                                       "socket:", proc->connection_name,
25887                                                                         "pid", proc->pid);
25888 -                                               
25889 +
25890                                                 host->num_procs--;
25891 -                                               
25892 +
25893                                                 /* proc is now in unused, let the next second handle the next process */
25894                                                 break;
25895 -                                       }       
25896 +                                       }
25897                                 }
25898 -                               
25899 +
25900                                 for (proc = host->unused_procs; proc; proc = proc->next) {
25901                                         int status;
25902 -                                       
25903 +
25904                                         if (proc->pid == 0) continue;
25905 -                                       
25906 +#ifndef _WIN32
25907                                         switch (waitpid(proc->pid, &status, WNOHANG)) {
25908                                         case 0:
25909                                                 /* child still running after timeout, good */
25910 @@ -3745,10 +3686,10 @@
25911                                         case -1:
25912                                                 if (errno != EINTR) {
25913                                                         /* no PID found ? should never happen */
25914 -                                                       log_error_write(srv, __FILE__, __LINE__, "sddss", 
25915 +                                                       log_error_write(srv, __FILE__, __LINE__, "sddss",
25916                                                                         "pid ", proc->pid, proc->state,
25917                                                                         "not found:", strerror(errno));
25918 -                                                       
25919 +
25920  #if 0
25921                                                         if (errno == ECHILD) {
25922                                                                 /* someone else has cleaned up for us */
25923 @@ -3762,25 +3703,26 @@
25924                                                 /* the child should not terminate at all */
25925                                                 if (WIFEXITED(status)) {
25926                                                         if (proc->state != PROC_STATE_KILLED) {
25927 -                                                               log_error_write(srv, __FILE__, __LINE__, "sdb", 
25928 -                                                                               "child exited:", 
25929 +                                                               log_error_write(srv, __FILE__, __LINE__, "sdb",
25930 +                                                                               "child exited:",
25931                                                                                 WEXITSTATUS(status), proc->connection_name);
25932                                                         }
25933                                                 } else if (WIFSIGNALED(status)) {
25934                                                         if (WTERMSIG(status) != SIGTERM) {
25935 -                                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
25936 -                                                                               "child signaled:", 
25937 +                                                               log_error_write(srv, __FILE__, __LINE__, "sd",
25938 +                                                                               "child signaled:",
25939                                                                                 WTERMSIG(status));
25940                                                         }
25941                                                 } else {
25942 -                                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
25943 -                                                                       "child died somehow:", 
25944 +                                                       log_error_write(srv, __FILE__, __LINE__, "sd",
25945 +                                                                       "child died somehow:",
25946                                                                         status);
25947                                                 }
25948                                                 proc->pid = 0;
25949                                                 proc->state = PROC_STATE_UNSET;
25950                                                 host->max_id--;
25951                                         }
25952 +#endif
25953                                 }
25954                         }
25955                 }
25956 @@ -3804,8 +3746,8 @@
25957         p->handle_subrequest       = mod_fastcgi_handle_subrequest;
25958         p->handle_joblist          = mod_fastcgi_handle_joblist;
25959         p->handle_trigger          = mod_fastcgi_handle_trigger;
25960 -       
25961 +
25962         p->data         = NULL;
25963 -       
25964 +
25965         return 0;
25966  }
25967 --- ../lighttpd-1.4.11/src/mod_flv_streaming.c  2006-03-07 14:06:26.000000000 +0200
25968 +++ lighttpd-1.4.12/src/mod_flv_streaming.c     2006-07-16 00:26:04.000000000 +0300
25969 @@ -23,35 +23,35 @@
25970  
25971  typedef struct {
25972         PLUGIN_DATA;
25973 -       
25974 +
25975         buffer *query_str;
25976         array *get_params;
25977 -       
25978 +
25979         plugin_config **config_storage;
25980 -       
25981 -       plugin_config conf; 
25982 +
25983 +       plugin_config conf;
25984  } plugin_data;
25985  
25986  /* init the plugin data */
25987  INIT_FUNC(mod_flv_streaming_init) {
25988         plugin_data *p;
25989 -       
25990 +
25991         p = calloc(1, sizeof(*p));
25992 -       
25993 +
25994         p->query_str = buffer_init();
25995         p->get_params = array_init();
25996 -       
25997 +
25998         return p;
25999  }
26000  
26001  /* detroy the plugin data */
26002  FREE_FUNC(mod_flv_streaming_free) {
26003         plugin_data *p = p_d;
26004 -       
26005 +
26006         UNUSED(srv);
26007  
26008         if (!p) return HANDLER_GO_ON;
26009 -       
26010 +
26011         if (p->config_storage) {
26012                 size_t i;
26013  
26014 @@ -59,19 +59,19 @@
26015                         plugin_config *s = p->config_storage[i];
26016  
26017                         if (!s) continue;
26018 -                       
26019 +
26020                         array_free(s->extensions);
26021 -                       
26022 +
26023                         free(s);
26024                 }
26025                 free(p->config_storage);
26026         }
26027 -       
26028 +
26029         buffer_free(p->query_str);
26030         array_free(p->get_params);
26031 -       
26032 +
26033         free(p);
26034 -       
26035 +
26036         return HANDLER_GO_ON;
26037  }
26038  
26039 @@ -80,83 +80,80 @@
26040  SETDEFAULTS_FUNC(mod_flv_streaming_set_defaults) {
26041         plugin_data *p = p_d;
26042         size_t i = 0;
26043 -       
26044 -       config_values_t cv[] = { 
26045 +
26046 +       config_values_t cv[] = {
26047                 { "flv-streaming.extensions",   NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
26048                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
26049         };
26050 -       
26051 +
26052         if (!p) return HANDLER_ERROR;
26053 -       
26054 +
26055         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
26056 -       
26057 +
26058         for (i = 0; i < srv->config_context->used; i++) {
26059                 plugin_config *s;
26060 -               
26061 +
26062                 s = calloc(1, sizeof(plugin_config));
26063                 s->extensions     = array_init();
26064 -               
26065 +
26066                 cv[0].destination = s->extensions;
26067 -               
26068 +
26069                 p->config_storage[i] = s;
26070 -       
26071 +
26072                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
26073                         return HANDLER_ERROR;
26074                 }
26075         }
26076 -       
26077 +
26078         return HANDLER_GO_ON;
26079  }
26080  
26081 -#define PATCH(x) \
26082 -       p->conf.x = s->x;
26083  static int mod_flv_streaming_patch_connection(server *srv, connection *con, plugin_data *p) {
26084         size_t i, j;
26085         plugin_config *s = p->config_storage[0];
26086 -       
26087 -       PATCH(extensions);
26088 -       
26089 +
26090 +       PATCH_OPTION(extensions);
26091 +
26092         /* skip the first, the global context */
26093         for (i = 1; i < srv->config_context->used; i++) {
26094                 data_config *dc = (data_config *)srv->config_context->data[i];
26095                 s = p->config_storage[i];
26096 -               
26097 +
26098                 /* condition didn't match */
26099                 if (!config_check_cond(srv, con, dc)) continue;
26100 -               
26101 +
26102                 /* merge config */
26103                 for (j = 0; j < dc->value->used; j++) {
26104                         data_unset *du = dc->value->data[j];
26105 -                       
26106 +
26107                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("flv-streaming.extensions"))) {
26108 -                               PATCH(extensions);
26109 +                               PATCH_OPTION(extensions);
26110                         }
26111                 }
26112         }
26113 -       
26114 +
26115         return 0;
26116  }
26117 -#undef PATCH
26118  
26119 -static int split_get_params(server *srv, connection *con, array *get_params, buffer *qrystr) {
26120 +static int split_get_params(array *get_params, buffer *qrystr) {
26121         size_t is_key = 1;
26122         size_t i;
26123         char *key = NULL, *val = NULL;
26124 -       
26125 +
26126         key = qrystr->ptr;
26127 -       
26128 +
26129         /* we need the \0 */
26130         for (i = 0; i < qrystr->used; i++) {
26131                 switch(qrystr->ptr[i]) {
26132                 case '=':
26133                         if (is_key) {
26134                                 val = qrystr->ptr + i + 1;
26135 -                               
26136 +
26137                                 qrystr->ptr[i] = '\0';
26138 -                               
26139 +
26140                                 is_key = 0;
26141                         }
26142 -                       
26143 +
26144                         break;
26145                 case '&':
26146                 case '\0': /* fin symbol */
26147 @@ -167,7 +164,7 @@
26148                                 /* terminate the value */
26149                                 qrystr->ptr[i] = '\0';
26150  
26151 -                               if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
26152 +                               if (NULL == (ds = (data_string *)array_get_unused_element(get_params, TYPE_STRING))) {
26153                                         ds = data_string_init();
26154                                 }
26155                                 buffer_copy_string_len(ds->key, key, strlen(key));
26156 @@ -175,14 +172,14 @@
26157  
26158                                 array_insert_unique(get_params, (data_unset *)ds);
26159                         }
26160 -                       
26161 +
26162                         key = qrystr->ptr + i + 1;
26163                         val = NULL;
26164                         is_key = 1;
26165                         break;
26166                 }
26167         }
26168 -       
26169 +
26170         return 0;
26171  }
26172  
26173 @@ -190,34 +187,34 @@
26174         plugin_data *p = p_d;
26175         int s_len;
26176         size_t k;
26177 -       
26178 +
26179         UNUSED(srv);
26180  
26181         if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
26182 -       
26183 +
26184         mod_flv_streaming_patch_connection(srv, con, p);
26185  
26186         s_len = con->physical.path->used - 1;
26187 -       
26188 +
26189         for (k = 0; k < p->conf.extensions->used; k++) {
26190                 data_string *ds = (data_string *)p->conf.extensions->data[k];
26191                 int ct_len = ds->value->used - 1;
26192 -               
26193 +
26194                 if (ct_len > s_len) continue;
26195                 if (ds->value->used == 0) continue;
26196 -               
26197 +
26198                 if (0 == strncmp(con->physical.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
26199                         data_string *get_param;
26200                         stat_cache_entry *sce = NULL;
26201                         buffer *b;
26202                         int start;
26203                         char *err = NULL;
26204 -                       /* if there is a start=[0-9]+ in the header use it as start, 
26205 +                       /* if there is a start=[0-9]+ in the header use it as start,
26206                          * otherwise send the full file */
26207  
26208                         array_reset(p->get_params);
26209                         buffer_copy_string_buffer(p->query_str, con->uri.query);
26210 -                       split_get_params(srv, con, p->get_params, p->query_str);
26211 +                       split_get_params(p->get_params, p->query_str);
26212  
26213                         if (NULL == (get_param = (data_string *)array_get_element(p->get_params, "start"))) {
26214                                 return HANDLER_GO_ON;
26215 @@ -256,7 +253,7 @@
26216                         return HANDLER_FINISHED;
26217                 }
26218         }
26219 -       
26220 +
26221         /* not found */
26222         return HANDLER_GO_ON;
26223  }
26224 @@ -266,13 +263,13 @@
26225  int mod_flv_streaming_plugin_init(plugin *p) {
26226         p->version     = LIGHTTPD_VERSION_ID;
26227         p->name        = buffer_init_string("flv_streaming");
26228 -       
26229 +
26230         p->init        = mod_flv_streaming_init;
26231         p->handle_physical = mod_flv_streaming_path_handler;
26232         p->set_defaults  = mod_flv_streaming_set_defaults;
26233         p->cleanup     = mod_flv_streaming_free;
26234 -       
26235 +
26236         p->data        = NULL;
26237 -       
26238 +
26239         return 0;
26240  }
26241 --- ../lighttpd-1.4.11/src/mod_indexfile.c      2005-09-30 01:08:53.000000000 +0300
26242 +++ lighttpd-1.4.12/src/mod_indexfile.c 2006-07-16 00:26:04.000000000 +0300
26243 @@ -12,6 +12,8 @@
26244  
26245  #include "stat_cache.h"
26246  
26247 +#include "sys-strings.h"
26248 +#include "sys-files.h"
26249  /* plugin config for all request/connections */
26250  
26251  typedef struct {
26252 @@ -20,51 +22,51 @@
26253  
26254  typedef struct {
26255         PLUGIN_DATA;
26256 -       
26257 +
26258         buffer *tmp_buf;
26259 -       
26260 +
26261         plugin_config **config_storage;
26262 -       
26263 -       plugin_config conf; 
26264 +
26265 +       plugin_config conf;
26266  } plugin_data;
26267  
26268  /* init the plugin data */
26269  INIT_FUNC(mod_indexfile_init) {
26270         plugin_data *p;
26271 -       
26272 +
26273         p = calloc(1, sizeof(*p));
26274 -       
26275 +
26276         p->tmp_buf = buffer_init();
26277 -       
26278 +
26279         return p;
26280  }
26281  
26282  /* detroy the plugin data */
26283  FREE_FUNC(mod_indexfile_free) {
26284         plugin_data *p = p_d;
26285 -       
26286 +
26287         UNUSED(srv);
26288  
26289         if (!p) return HANDLER_GO_ON;
26290 -       
26291 +
26292         if (p->config_storage) {
26293                 size_t i;
26294                 for (i = 0; i < srv->config_context->used; i++) {
26295                         plugin_config *s = p->config_storage[i];
26296  
26297                         if (!s) continue;
26298 -                       
26299 +
26300                         array_free(s->indexfiles);
26301 -                       
26302 +
26303                         free(s);
26304                 }
26305                 free(p->config_storage);
26306         }
26307 -       
26308 +
26309         buffer_free(p->tmp_buf);
26310 -       
26311 +
26312         free(p);
26313 -       
26314 +
26315         return HANDLER_GO_ON;
26316  }
26317  
26318 @@ -73,131 +75,139 @@
26319  SETDEFAULTS_FUNC(mod_indexfile_set_defaults) {
26320         plugin_data *p = p_d;
26321         size_t i = 0;
26322 -       
26323 -       config_values_t cv[] = { 
26324 +
26325 +       config_values_t cv[] = {
26326                 { "index-file.names",           NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
26327                 { "server.indexfiles",          NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
26328                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
26329         };
26330 -       
26331 +
26332         if (!p) return HANDLER_ERROR;
26333 -       
26334 +
26335         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
26336 -       
26337 +
26338         for (i = 0; i < srv->config_context->used; i++) {
26339                 plugin_config *s;
26340 -               
26341 +
26342                 s = calloc(1, sizeof(plugin_config));
26343                 s->indexfiles    = array_init();
26344 -               
26345 +
26346                 cv[0].destination = s->indexfiles;
26347                 cv[1].destination = s->indexfiles; /* old name for [0] */
26348 -               
26349 +
26350                 p->config_storage[i] = s;
26351 -       
26352 +
26353                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
26354                         return HANDLER_ERROR;
26355                 }
26356         }
26357 -       
26358 +
26359         return HANDLER_GO_ON;
26360  }
26361  
26362 -#define PATCH(x) \
26363 -       p->conf.x = s->x;
26364  static int mod_indexfile_patch_connection(server *srv, connection *con, plugin_data *p) {
26365         size_t i, j;
26366         plugin_config *s = p->config_storage[0];
26367 -       
26368 -       PATCH(indexfiles);
26369 -       
26370 +
26371 +       PATCH_OPTION(indexfiles);
26372 +
26373         /* skip the first, the global context */
26374         for (i = 1; i < srv->config_context->used; i++) {
26375                 data_config *dc = (data_config *)srv->config_context->data[i];
26376                 s = p->config_storage[i];
26377 -               
26378 +
26379                 /* condition didn't match */
26380                 if (!config_check_cond(srv, con, dc)) continue;
26381 -               
26382 +
26383                 /* merge config */
26384                 for (j = 0; j < dc->value->used; j++) {
26385                         data_unset *du = dc->value->data[j];
26386 -                       
26387 +
26388                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.indexfiles"))) {
26389 -                               PATCH(indexfiles);
26390 +                               PATCH_OPTION(indexfiles);
26391                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("index-file.names"))) {
26392 -                               PATCH(indexfiles);
26393 +                               PATCH_OPTION(indexfiles);
26394                         }
26395                 }
26396         }
26397 -       
26398 +
26399         return 0;
26400  }
26401 -#undef PATCH
26402  
26403  URIHANDLER_FUNC(mod_indexfile_subrequest) {
26404         plugin_data *p = p_d;
26405         size_t k;
26406         stat_cache_entry *sce = NULL;
26407 -       
26408 +
26409         if (con->uri.path->used == 0) return HANDLER_GO_ON;
26410         if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
26411 -       
26412 +
26413         mod_indexfile_patch_connection(srv, con, p);
26414 -       
26415 +
26416 +       /* is the physical-path really a dir ? */
26417 +       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
26418 +               return HANDLER_GO_ON;
26419 +       }
26420 +
26421 +       if (!S_ISDIR(sce->st.st_mode)) {
26422 +               return HANDLER_GO_ON;
26423 +       }
26424 +
26425         if (con->conf.log_request_handling) {
26426                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling the request as Indexfile");
26427                 log_error_write(srv, __FILE__, __LINE__,  "sb", "URI          :", con->uri.path);
26428         }
26429 -       
26430 +
26431 +
26432         /* indexfile */
26433         for (k = 0; k < p->conf.indexfiles->used; k++) {
26434                 data_string *ds = (data_string *)p->conf.indexfiles->data[k];
26435 -               
26436 +
26437                 if (ds->value && ds->value->ptr[0] == '/') {
26438 -                       /* if the index-file starts with a prefix as use this file as 
26439 +                       /* if the index-file starts with a prefix as use this file as
26440                          * index-generator */
26441                         buffer_copy_string_buffer(p->tmp_buf, con->physical.doc_root);
26442                 } else {
26443                         buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
26444 +                       PATHNAME_APPEND_SLASH(p->tmp_buf);
26445                 }
26446                 buffer_append_string_buffer(p->tmp_buf, ds->value);
26447 -               
26448 +
26449                 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
26450                         if (errno == EACCES) {
26451                                 con->http_status = 403;
26452                                 buffer_reset(con->physical.path);
26453 -                               
26454 +
26455                                 return HANDLER_FINISHED;
26456                         }
26457 -                       
26458 +
26459                         if (errno != ENOENT &&
26460                             errno != ENOTDIR) {
26461                                 /* we have no idea what happend. let's tell the user so. */
26462 -                               
26463 +
26464                                 con->http_status = 500;
26465 -                               
26466 +
26467                                 log_error_write(srv, __FILE__, __LINE__, "ssbsb",
26468                                                 "file not found ... or so: ", strerror(errno),
26469                                                 con->uri.path,
26470                                                 "->", con->physical.path);
26471 -                               
26472 +
26473                                 buffer_reset(con->physical.path);
26474 -                               
26475 +
26476                                 return HANDLER_FINISHED;
26477                         }
26478                         continue;
26479                 }
26480 -                       
26481 +
26482                 /* rewrite uri.path to the real path (/ -> /index.php) */
26483                 buffer_append_string_buffer(con->uri.path, ds->value);
26484                 buffer_copy_string_buffer(con->physical.path, p->tmp_buf);
26485 -               
26486 +
26487                 /* fce is already set up a few lines above */
26488 -               
26489 +
26490                 return HANDLER_GO_ON;
26491         }
26492 -       
26493 +
26494         /* not found */
26495         return HANDLER_GO_ON;
26496  }
26497 @@ -207,13 +217,13 @@
26498  int mod_indexfile_plugin_init(plugin *p) {
26499         p->version     = LIGHTTPD_VERSION_ID;
26500         p->name        = buffer_init_string("indexfile");
26501 -       
26502 +
26503         p->init        = mod_indexfile_init;
26504         p->handle_subrequest_start = mod_indexfile_subrequest;
26505         p->set_defaults  = mod_indexfile_set_defaults;
26506         p->cleanup     = mod_indexfile_free;
26507 -       
26508 +
26509         p->data        = NULL;
26510 -       
26511 +
26512         return 0;
26513  }
26514 --- ../lighttpd-1.4.11/src/mod_mysql_vhost.c    2006-01-14 20:35:10.000000000 +0200
26515 +++ lighttpd-1.4.12/src/mod_mysql_vhost.c       2006-07-16 00:26:04.000000000 +0300
26516 @@ -1,13 +1,18 @@
26517 -#include <unistd.h>
26518  #include <stdio.h>
26519  #include <errno.h>
26520  #include <fcntl.h>
26521 -#include <strings.h>
26522 +#include <string.h>
26523  
26524  #ifdef HAVE_CONFIG_H
26525  #include "config.h"
26526  #endif
26527  
26528 +#ifdef HAVE_MYSQL_H 
26529 +# ifdef HAVE_LIBMYSQL
26530 +#  define HAVE_MYSQL
26531 +# endif
26532 +#endif
26533 +
26534  #ifdef HAVE_MYSQL
26535  #include <mysql.h>
26536  #endif
26537 @@ -16,61 +21,40 @@
26538  #include "log.h"
26539  
26540  #include "stat_cache.h"
26541 -#ifdef DEBUG_MOD_MYSQL_VHOST
26542 -#define DEBUG
26543 -#endif
26544 +#include "sys-files.h"
26545  
26546 -/*
26547 - * Plugin for lighttpd to use MySQL 
26548 - *   for domain to directory lookups,
26549 - *   i.e virtual hosts (vhosts).
26550 - *   
26551 - * Optionally sets fcgi_offset and fcgi_arg 
26552 - *   in preparation for fcgi.c to handle 
26553 - *   per-user fcgi chroot jails.
26554 - *
26555 - * /ada@riksnet.se 2004-12-06
26556 - */
26557 +#include "mod_sql_vhost_core.h"
26558  
26559  #ifdef HAVE_MYSQL
26560 +
26561 +#define CORE_PLUGIN "mod_sql_vhost_core"
26562 +
26563  typedef struct {
26564         MYSQL   *mysql;
26565 -       
26566 -       buffer  *mydb;
26567 -       buffer  *myuser;
26568 -       buffer  *mypass;
26569 -       buffer  *mysock;
26570 -       
26571 -       buffer  *hostname;
26572 -       unsigned short port;
26573 -       
26574 +
26575         buffer  *mysql_pre;
26576         buffer  *mysql_post;
26577 +
26578 +       mod_sql_vhost_core_plugin_config *core;
26579  } plugin_config;
26580  
26581  /* global plugin data */
26582  typedef struct {
26583         PLUGIN_DATA;
26584 -       
26585 +
26586         buffer  *tmp_buf;
26587 -       
26588 +
26589         plugin_config **config_storage;
26590 -       
26591 -       plugin_config conf; 
26592 +
26593 +       plugin_config conf;
26594  } plugin_data;
26595  
26596 -/* per connection plugin data */
26597 -typedef struct {
26598 -       buffer  *server_name;
26599 -       buffer  *document_root;
26600 -       buffer  *fcgi_arg;
26601 -       unsigned fcgi_offset;
26602 -} plugin_connection_data;
26603 +SQLVHOST_BACKEND_GETVHOST(mod_mysql_vhost_get_vhost); 
26604  
26605  /* init the plugin data */
26606  INIT_FUNC(mod_mysql_vhost_init) {
26607         plugin_data *p;
26608 -       
26609 +
26610         p = calloc(1, sizeof(*p));
26611  
26612         p->tmp_buf = buffer_init();
26613 @@ -83,144 +67,77 @@
26614         plugin_data *p = p_d;
26615  
26616         UNUSED(srv);
26617 -       
26618 -#ifdef DEBUG
26619 -       log_error_write(srv, __FILE__, __LINE__, "ss", 
26620 -               "mod_mysql_vhost_cleanup", p ? "yes" : "NO");
26621 -#endif
26622 +
26623         if (!p) return HANDLER_GO_ON;
26624 -       
26625 +
26626         if (p->config_storage) {
26627                 size_t i;
26628                 for (i = 0; i < srv->config_context->used; i++) {
26629                         plugin_config *s = p->config_storage[i];
26630  
26631                         if (!s) continue;
26632 -                       
26633 +
26634                         mysql_close(s->mysql);
26635 -                       
26636 -                       buffer_free(s->mydb);
26637 -                       buffer_free(s->myuser);
26638 -                       buffer_free(s->mypass);
26639 -                       buffer_free(s->mysock);
26640 +
26641                         buffer_free(s->mysql_pre);
26642                         buffer_free(s->mysql_post);
26643 -                       
26644 +
26645                         free(s);
26646                 }
26647                 free(p->config_storage);
26648         }
26649         buffer_free(p->tmp_buf);
26650 -       
26651 -       free(p);
26652  
26653 -       return HANDLER_GO_ON;
26654 -}
26655 -
26656 -/* handle the plugin per connection data */
26657 -static void* mod_mysql_vhost_connection_data(server *srv, connection *con, void *p_d)
26658 -{
26659 -       plugin_data *p = p_d;
26660 -       plugin_connection_data *c = con->plugin_ctx[p->id];
26661 -
26662 -       UNUSED(srv);
26663 -
26664 -#ifdef DEBUG
26665 -        log_error_write(srv, __FILE__, __LINE__, "ss", 
26666 -               "mod_mysql_connection_data", c ? "old" : "NEW");
26667 -#endif
26668 -
26669 -       if (c) return c;
26670 -       c = calloc(1, sizeof(*c));
26671 -
26672 -       c->server_name = buffer_init();
26673 -       c->document_root = buffer_init();
26674 -       c->fcgi_arg = buffer_init();
26675 -       c->fcgi_offset = 0;
26676 -
26677 -       return con->plugin_ctx[p->id] = c;
26678 -}
26679 -
26680 -/* destroy the plugin per connection data */
26681 -CONNECTION_FUNC(mod_mysql_vhost_handle_connection_close) {
26682 -       plugin_data *p = p_d;
26683 -       plugin_connection_data *c = con->plugin_ctx[p->id];
26684 -
26685 -       UNUSED(srv);
26686 -
26687 -#ifdef DEBUG
26688 -       log_error_write(srv, __FILE__, __LINE__, "ss", 
26689 -               "mod_mysql_vhost_handle_connection_close", c ? "yes" : "NO");
26690 -#endif
26691 -       
26692 -       if (!c) return HANDLER_GO_ON;
26693 -
26694 -       buffer_free(c->server_name);
26695 -       buffer_free(c->document_root);
26696 -       buffer_free(c->fcgi_arg);
26697 -       c->fcgi_offset = 0;
26698 -
26699 -       free(c);
26700 +       free(p);
26701  
26702 -       con->plugin_ctx[p->id] = NULL;
26703         return HANDLER_GO_ON;
26704  }
26705  
26706  /* set configuration values */
26707  SERVER_FUNC(mod_mysql_vhost_set_defaults) {
26708         plugin_data *p = p_d;
26709 +       mod_sql_vhost_core_plugin_data *core_config;
26710  
26711 -       char *qmark;
26712         size_t i = 0;
26713  
26714 -       config_values_t cv[] = {
26715 -               { "mysql-vhost.db",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
26716 -               { "mysql-vhost.user",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
26717 -               { "mysql-vhost.pass",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
26718 -               { "mysql-vhost.sock",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
26719 -               { "mysql-vhost.sql",    NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
26720 -               { "mysql-vhost.hostname", NULL, T_CONFIG_STRING,T_CONFIG_SCOPE_SERVER },
26721 -               { "mysql-vhost.port",   NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_SERVER },
26722 -                { NULL,                        NULL, T_CONFIG_UNSET,   T_CONFIG_SCOPE_UNSET }
26723 -        };
26724 -       
26725 +       /* our very own plugin storage, one entry for each conditional
26726 +        * 
26727 +        * srv->config_context->used is the number of conditionals
26728 +        * */
26729         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
26730 -       
26731 +
26732 +       /* get the config of the core-plugin */
26733 +       core_config = plugin_get_config(srv, CORE_PLUGIN);
26734 +
26735 +
26736 +       /* walk through all conditionals and check for assignments */
26737         for (i = 0; i < srv->config_context->used; i++) {
26738                 plugin_config *s;
26739                 buffer *sel;
26740 -               
26741 -               
26742 +               char *qmark;
26743 +
26744 +               /* get the config from the core plugin for this conditional-context */
26745                 s = calloc(1, sizeof(plugin_config));
26746 -               s->mydb = buffer_init();
26747 -               s->myuser = buffer_init();
26748 -               s->mypass = buffer_init();
26749 -               s->mysock = buffer_init();
26750 -               s->hostname = buffer_init();
26751 -               s->port   = 0;               /* default port for mysql */
26752 -               sel = buffer_init();
26753 -               s->mysql = NULL;
26754 +
26755 +               s->core = core_config->config_storage[i];
26756                 
26757 +               s->mysql = NULL;
26758 +
26759                 s->mysql_pre = buffer_init();
26760                 s->mysql_post = buffer_init();
26761 -               
26762 -               cv[0].destination = s->mydb;
26763 -               cv[1].destination = s->myuser;
26764 -               cv[2].destination = s->mypass;
26765 -               cv[3].destination = s->mysock;
26766 -               cv[4].destination = sel;
26767 -               cv[5].destination = s->hostname;
26768 -               cv[6].destination = &(s->port);
26769 -               
26770 +
26771                 p->config_storage[i] = s;
26772 -               
26773 -               if (config_insert_values_global(srv, 
26774 -                       ((data_config *)srv->config_context->data[i])->value,
26775 -                       cv)) return HANDLER_ERROR;
26776 -               
26777 -               s->mysql_pre = buffer_init();
26778 -               s->mysql_post = buffer_init();
26779 -               
26780 +
26781 +               /* check if we are the plugin for this backend */
26782 +               if (!buffer_is_equal_string(s->core->backend, CONST_STR_LEN("mysql"))) continue;
26783 +
26784 +               /* attach us to the core-plugin */
26785 +               s->core->backend_data = p;
26786 +               s->core->get_vhost = mod_mysql_vhost_get_vhost;
26787 +
26788 +               sel = buffer_init();
26789 +               buffer_copy_string_buffer(sel, s->core->select_vhost);
26790 +
26791                 if (sel->used && (qmark = index(sel->ptr, '?'))) {
26792                         *qmark = '\0';
26793                         buffer_copy_string(s->mysql_pre, sel->ptr);
26794 @@ -228,35 +145,35 @@
26795                 } else {
26796                         buffer_copy_string_buffer(s->mysql_pre, sel);
26797                 }
26798 -               
26799 +
26800                 /* required:
26801                  * - username
26802 -                * - database 
26803 -                * 
26804 +                * - database
26805 +                *
26806                  * optional:
26807                  * - password, default: empty
26808                  * - socket, default: mysql default
26809                  * - hostname, if set overrides socket
26810                  * - port, default: 3306
26811                  */
26812 -               
26813 +
26814                 /* all have to be set */
26815 -               if (!(buffer_is_empty(s->myuser) ||
26816 -                     buffer_is_empty(s->mydb))) {
26817 +               if (!(buffer_is_empty(s->core->user) ||
26818 +                     buffer_is_empty(s->core->db))) {
26819  
26820                         int fd;
26821 -               
26822 +
26823                         if (NULL == (s->mysql = mysql_init(NULL))) {
26824                                 log_error_write(srv, __FILE__, __LINE__, "s", "mysql_init() failed, exiting...");
26825 -                               
26826 +
26827                                 return HANDLER_ERROR;
26828                         }
26829 -#define FOO(x) (s->x->used ? s->x->ptr : NULL)
26830 -                       
26831 -                       if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(myuser), FOO(mypass), 
26832 -                                               FOO(mydb), s->port, FOO(mysock), 0)) {
26833 +#define FOO(x) (s->core->x->used ? s->core->x->ptr : NULL)
26834 +
26835 +                       if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(user), FOO(pass),
26836 +                                               FOO(db), s->core->port, FOO(sock), 0)) {
26837                                 log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(s->mysql));
26838 -                               
26839 +
26840                                 return HANDLER_ERROR;
26841                         }
26842  #undef FOO
26843 @@ -265,61 +182,47 @@
26844                         /* otherwise we cannot be sure that mysql is fd i-1 */
26845                         if (-1 == (fd = open("/dev/null", 0))) {
26846                                 close(fd);
26847 -                               fcntl(fd-1, F_SETFD, FD_CLOEXEC); 
26848 +                               fcntl(fd-1, F_SETFD, FD_CLOEXEC);
26849                         }
26850                 }
26851         }
26852 -       
26853 -       
26854 +
26855 +
26856  
26857          return HANDLER_GO_ON;
26858  }
26859  
26860 -#define PATCH(x) \
26861 -       p->conf.x = s->x;
26862  static int mod_mysql_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
26863 -       size_t i, j;
26864 +       size_t i;
26865         plugin_config *s = p->config_storage[0];
26866 -       
26867 -       PATCH(mysql_pre);
26868 -       PATCH(mysql_post);
26869 -#ifdef HAVE_MYSQL
26870 -       PATCH(mysql);
26871 -#endif
26872 -       
26873 +
26874 +       PATCH_OPTION(mysql_pre);
26875 +       PATCH_OPTION(mysql_post);
26876 +       PATCH_OPTION(mysql);
26877 +
26878         /* skip the first, the global context */
26879         for (i = 1; i < srv->config_context->used; i++) {
26880                 data_config *dc = (data_config *)srv->config_context->data[i];
26881                 s = p->config_storage[i];
26882 -               
26883 +
26884                 /* condition didn't match */
26885                 if (!config_check_cond(srv, con, dc)) continue;
26886 -               
26887 -               /* merge config */
26888 -               for (j = 0; j < dc->value->used; j++) {
26889 -                       data_unset *du = dc->value->data[j];
26890 -                       
26891 -                       if (buffer_is_equal_string(du->key, CONST_STR_LEN("mysql-vhost.sql"))) {
26892 -                               PATCH(mysql_pre);
26893 -                               PATCH(mysql_post);
26894 -                       }
26895 -               }
26896 -               
26897 +
26898                 if (s->mysql) {
26899 -                       PATCH(mysql);
26900 +                       PATCH_OPTION(mysql);
26901 +                       PATCH_OPTION(mysql_pre);
26902 +                       PATCH_OPTION(mysql_post);
26903                 }
26904         }
26905 -       
26906 +
26907         return 0;
26908  }
26909 -#undef PATCH
26910  
26911 -
26912 -/* handle document root request */
26913 -CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
26914 +/**
26915 + * get the vhost info from the database 
26916 + */
26917 +SQLVHOST_BACKEND_GETVHOST(mod_mysql_vhost_get_vhost) {
26918         plugin_data *p = p_d;
26919 -       plugin_connection_data *c;
26920 -       stat_cache_entry *sce;
26921  
26922         unsigned  cols;
26923         MYSQL_ROW row;
26924 @@ -332,13 +235,6 @@
26925  
26926         if (!p->conf.mysql) return HANDLER_GO_ON;
26927  
26928 -       /* sets up connection data if not done yet */
26929 -       c = mod_mysql_vhost_connection_data(srv, con, p_d);
26930 -
26931 -       /* check if cached this connection */
26932 -       if (c->server_name->used && /* con->uri.authority->used && */
26933 -            buffer_is_equal(c->server_name, con->uri.authority)) goto GO_ON;
26934 -
26935         /* build and run SQL query */
26936         buffer_copy_string_buffer(p->tmp_buf, p->conf.mysql_pre);
26937         if (p->conf.mysql_post->used) {
26938 @@ -347,77 +243,43 @@
26939         }
26940         if (mysql_query(p->conf.mysql, p->tmp_buf->ptr)) {
26941                 log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(p->conf.mysql));
26942 -               goto ERR500;
26943 +
26944 +               mysql_free_result(result);
26945 +               return HANDLER_GO_ON;
26946         }
26947         result = mysql_store_result(p->conf.mysql);
26948         cols = mysql_num_fields(result);
26949         row = mysql_fetch_row(result);
26950 +
26951         if (!row || cols < 1) {
26952                 /* no such virtual host */
26953                 mysql_free_result(result);
26954                 return HANDLER_GO_ON;
26955         }
26956  
26957 -       /* sanity check that really is a directory */
26958 -       buffer_copy_string(p->tmp_buf, row[0]);
26959 -       BUFFER_APPEND_SLASH(p->tmp_buf);
26960 -
26961 -       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
26962 -               log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
26963 -               goto ERR500;
26964 -       }
26965 -        if (!S_ISDIR(sce->st.st_mode)) {
26966 -               log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", p->tmp_buf);
26967 -               goto ERR500;
26968 -       }
26969 +       buffer_copy_string(docroot, row[0]);
26970  
26971 -       /* cache the data */
26972 -       buffer_copy_string_buffer(c->server_name, con->uri.authority);
26973 -       buffer_copy_string_buffer(c->document_root, p->tmp_buf);
26974 -
26975 -       /* fcgi_offset and fcgi_arg are optional */
26976 -       if (cols > 1 && row[1]) {
26977 -               c->fcgi_offset = atoi(row[1]);
26978 -               
26979 -               if (cols > 2 && row[2]) {
26980 -                       buffer_copy_string(c->fcgi_arg, row[2]);
26981 -               } else {
26982 -                       c->fcgi_arg->used = 0;
26983 -               }
26984 -       } else {
26985 -               c->fcgi_offset = c->fcgi_arg->used = 0;
26986 -       }
26987         mysql_free_result(result);
26988  
26989 -       /* fix virtual server and docroot */
26990 -GO_ON: buffer_copy_string_buffer(con->server_name, c->server_name);
26991 -       buffer_copy_string_buffer(con->physical.doc_root, c->document_root);
26992 -
26993 -#ifdef DEBUG
26994 -       log_error_write(srv, __FILE__, __LINE__, "sbbdb", 
26995 -               result ? "NOT CACHED" : "cached", 
26996 -               con->server_name, con->physical.doc_root,
26997 -               c->fcgi_offset, c->fcgi_arg);
26998 -#endif
26999 -       return HANDLER_GO_ON;   
27000 -
27001 -ERR500:        if (result) mysql_free_result(result);
27002 -       con->http_status = 500; /* Internal Error */
27003 -       return HANDLER_FINISHED;
27004 +       return HANDLER_GO_ON;
27005  }
27006  
27007  /* this function is called at dlopen() time and inits the callbacks */
27008  int mod_mysql_vhost_plugin_init(plugin *p) {
27009 +       data_string *ds;
27010 +       
27011         p->version     = LIGHTTPD_VERSION_ID;
27012         p->name                         = buffer_init_string("mysql_vhost");
27013  
27014         p->init                         = mod_mysql_vhost_init;
27015         p->cleanup                      = mod_mysql_vhost_cleanup;
27016 -       p->handle_request_done          = mod_mysql_vhost_handle_connection_close;
27017  
27018         p->set_defaults                 = mod_mysql_vhost_set_defaults;
27019 -       p->handle_docroot               = mod_mysql_vhost_handle_docroot;
27020         
27021 +       ds = data_string_init();
27022 +       buffer_copy_string(ds->value, CORE_PLUGIN);
27023 +       array_insert_unique(p->required_plugins, (data_unset *)ds);
27024 +
27025         return 0;
27026  }
27027  #else
27028 --- ../lighttpd-1.4.11/src/mod_proxy.c  2006-01-31 13:01:22.000000000 +0200
27029 +++ lighttpd-1.4.12/src/mod_proxy.c     2006-07-18 13:03:40.000000000 +0300
27030 @@ -1,6 +1,5 @@
27031  #include <sys/types.h>
27032  
27033 -#include <unistd.h>
27034  #include <errno.h>
27035  #include <fcntl.h>
27036  #include <string.h>
27037 @@ -23,6 +22,9 @@
27038  
27039  #include "inet_ntop_cache.h"
27040  #include "crc32.h"
27041 +#include "network.h"
27042 +
27043 +#include "http_resp.h"
27044  
27045  #include <stdio.h>
27046  
27047 @@ -31,6 +33,8 @@
27048  #endif
27049  
27050  #include "sys-socket.h"
27051 +#include "sys-files.h"
27052 +#include "sys-strings.h"
27053  
27054  #define data_proxy data_fastcgi
27055  #define data_proxy_init data_fastcgi_init
27056 @@ -38,22 +42,25 @@
27057  #define PROXY_RETRY_TIMEOUT 60
27058  
27059  /**
27060 - * 
27061 - * the proxy module is based on the fastcgi module 
27062 - * 
27063 + *
27064 + * the proxy module is based on the fastcgi module
27065 + *
27066   * 28.06.2004 Jan Kneschke     The first release
27067   * 01.07.2004 Evgeny Rodichev  Several bugfixes and cleanups
27068   *            - co-ordinate up- and downstream flows correctly (proxy_demux_response
27069   *              and proxy_handle_fdevent)
27070   *            - correctly transfer upstream http_response_status;
27071   *            - some unused structures removed.
27072 - * 
27073 + *
27074   * TODO:      - delay upstream read if write_queue is too large
27075   *              (to prevent memory eating, like in apache). Shoud be
27076   *              configurable).
27077   *            - persistent connection with upstream servers
27078   *            - HTTP/1.1
27079   */
27080 +
27081 +
27082 +
27083  typedef enum {
27084         PROXY_BALANCE_UNSET,
27085         PROXY_BALANCE_FAIR,
27086 @@ -66,26 +73,33 @@
27087         int debug;
27088  
27089         proxy_balance_t balance;
27090 +
27091 +       array *last_used_backends; /* "extension" : last_used_backend */
27092  } plugin_config;
27093  
27094  typedef struct {
27095         PLUGIN_DATA;
27096 -       
27097 +
27098         buffer *parse_response;
27099         buffer *balance_buf;
27100 -       
27101 +
27102 +       http_resp *resp;
27103 +
27104 +       array *ignore_headers;
27105 +
27106         plugin_config **config_storage;
27107 -       
27108 +
27109         plugin_config conf;
27110  } plugin_data;
27111  
27112 -typedef enum { 
27113 -       PROXY_STATE_INIT, 
27114 -       PROXY_STATE_CONNECT, 
27115 -       PROXY_STATE_PREPARE_WRITE, 
27116 -       PROXY_STATE_WRITE, 
27117 -       PROXY_STATE_READ, 
27118 -       PROXY_STATE_ERROR 
27119 +typedef enum {
27120 +       PROXY_STATE_INIT,
27121 +       PROXY_STATE_CONNECT,
27122 +       PROXY_STATE_PREPARE_WRITE,
27123 +       PROXY_STATE_WRITE,
27124 +       PROXY_STATE_RESPONSE_HEADER,
27125 +       PROXY_STATE_RESPONSE_CONTENT,
27126 +       PROXY_STATE_ERROR
27127  } proxy_connection_state_t;
27128  
27129  enum { PROXY_STDOUT, PROXY_END_REQUEST };
27130 @@ -93,19 +107,16 @@
27131  typedef struct {
27132         proxy_connection_state_t state;
27133         time_t state_timestamp;
27134 -       
27135 +
27136         data_proxy *host;
27137 -       
27138 -       buffer *response;
27139 -       buffer *response_header;
27140  
27141         chunkqueue *wb;
27142 -       
27143 -       int fd; /* fd to the proxy process */
27144 -       int fde_ndx; /* index into the fd-event buffer */
27145 +       chunkqueue *rb;
27146 +
27147 +       iosocket *fd; /* fd to the proxy process */
27148  
27149         size_t path_info_offset; /* start of path_info in uri.path */
27150 -       
27151 +
27152         connection *remote_conn;  /* dump pointer */
27153         plugin_data *plugin_data; /* dump pointer */
27154  } handler_ctx;
27155 @@ -116,69 +127,89 @@
27156  
27157  static handler_ctx * handler_ctx_init() {
27158         handler_ctx * hctx;
27159 -       
27160 +
27161  
27162         hctx = calloc(1, sizeof(*hctx));
27163 -       
27164 +
27165         hctx->state = PROXY_STATE_INIT;
27166         hctx->host = NULL;
27167 -       
27168 -       hctx->response = buffer_init();
27169 -       hctx->response_header = buffer_init();
27170  
27171         hctx->wb = chunkqueue_init();
27172 +       hctx->rb = chunkqueue_init();
27173 +
27174 +       hctx->fd = iosocket_init();
27175  
27176 -       hctx->fd = -1;
27177 -       hctx->fde_ndx = -1;
27178 -       
27179         return hctx;
27180  }
27181  
27182  static void handler_ctx_free(handler_ctx *hctx) {
27183 -       buffer_free(hctx->response);
27184 -       buffer_free(hctx->response_header);
27185         chunkqueue_free(hctx->wb);
27186 -       
27187 +       chunkqueue_free(hctx->rb);
27188 +
27189 +       iosocket_free(hctx->fd);
27190 +
27191         free(hctx);
27192  }
27193  
27194  INIT_FUNC(mod_proxy_init) {
27195         plugin_data *p;
27196 -       
27197 +       size_t i;
27198 +
27199 +       char *hop2hop_headers[] = {
27200 +               "Connection",
27201 +               "Keep-Alive",
27202 +               "Host",
27203 +               NULL
27204 +       };
27205 +
27206         p = calloc(1, sizeof(*p));
27207 -       
27208 -       p->parse_response = buffer_init();
27209 +
27210         p->balance_buf = buffer_init();
27211 -       
27212 +       p->ignore_headers = array_init();
27213 +       p->resp = http_response_init();
27214 +
27215 +       for (i = 0; hop2hop_headers[i]; i++) {
27216 +               data_string *ds;
27217 +
27218 +               if (NULL == (ds = (data_string *)array_get_unused_element(p->ignore_headers, TYPE_STRING))) {
27219 +                       ds = data_string_init();
27220 +               }
27221 +
27222 +               buffer_copy_string(ds->key, hop2hop_headers[i]);
27223 +               buffer_copy_string(ds->value, hop2hop_headers[i]);
27224 +               array_insert_unique(p->ignore_headers, (data_unset *)ds);
27225 +       }
27226 +
27227         return p;
27228  }
27229  
27230  
27231  FREE_FUNC(mod_proxy_free) {
27232         plugin_data *p = p_d;
27233 -       
27234 +
27235         UNUSED(srv);
27236  
27237 -       buffer_free(p->parse_response);
27238 -       buffer_free(p->balance_buf);
27239 -       
27240         if (p->config_storage) {
27241                 size_t i;
27242                 for (i = 0; i < srv->config_context->used; i++) {
27243                         plugin_config *s = p->config_storage[i];
27244 -                       
27245 +
27246                         if (s) {
27247 -                       
27248                                 array_free(s->extensions);
27249 -                       
27250 +                               array_free(s->last_used_backends);
27251 +
27252                                 free(s);
27253                         }
27254                 }
27255                 free(p->config_storage);
27256         }
27257 -       
27258 +
27259 +       array_free(p->ignore_headers);
27260 +       buffer_free(p->balance_buf);
27261 +       http_response_free(p->resp);
27262 +
27263         free(p);
27264 -       
27265 +
27266         return HANDLER_GO_ON;
27267  }
27268  
27269 @@ -186,37 +217,38 @@
27270         plugin_data *p = p_d;
27271         data_unset *du;
27272         size_t i = 0;
27273 -       
27274 -       config_values_t cv[] = { 
27275 +
27276 +       config_values_t cv[] = {
27277                 { "proxy.server",              NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
27278                 { "proxy.debug",               NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
27279                 { "proxy.balance",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 2 */
27280                 { NULL,                        NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
27281         };
27282 -       
27283 +
27284         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
27285 -       
27286 +
27287         for (i = 0; i < srv->config_context->used; i++) {
27288                 plugin_config *s;
27289                 array *ca;
27290 -               
27291 +
27292                 s = malloc(sizeof(plugin_config));
27293 -               s->extensions    = array_init();
27294 +               s->extensions         = array_init();
27295 +               s->last_used_backends = array_init();
27296                 s->debug         = 0;
27297 -               
27298 +
27299                 cv[0].destination = s->extensions;
27300                 cv[1].destination = &(s->debug);
27301                 cv[2].destination = p->balance_buf;
27302  
27303                 buffer_reset(p->balance_buf);
27304 -               
27305 +
27306                 p->config_storage[i] = s;
27307                 ca = ((data_config *)srv->config_context->data[i])->value;
27308 -       
27309 +
27310                 if (0 != config_insert_values_global(srv, ca, cv)) {
27311                         return HANDLER_ERROR;
27312                 }
27313 -       
27314 +
27315                 if (buffer_is_empty(p->balance_buf)) {
27316                         s->balance = PROXY_BALANCE_FAIR;
27317                 } else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("fair"))) {
27318 @@ -226,99 +258,99 @@
27319                 } else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("hash"))) {
27320                         s->balance = PROXY_BALANCE_HASH;
27321                 } else {
27322 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
27323 -                                       "proxy.balance has to be one of: fair, round-robin, hash, but not:", p->balance_buf);
27324 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
27325 +                               "proxy.balance has to be one of: fair, round-robin, hash, but not:", p->balance_buf);
27326                         return HANDLER_ERROR;
27327                 }
27328  
27329                 if (NULL != (du = array_get_element(ca, "proxy.server"))) {
27330                         size_t j;
27331                         data_array *da = (data_array *)du;
27332 -                       
27333 +
27334                         if (du->type != TYPE_ARRAY) {
27335 -                               log_error_write(srv, __FILE__, __LINE__, "sss", 
27336 +                               log_error_write(srv, __FILE__, __LINE__, "sss",
27337                                                 "unexpected type for key: ", "proxy.server", "array of strings");
27338 -                               
27339 +
27340                                 return HANDLER_ERROR;
27341                         }
27342 -                       
27343 -                       /* 
27344 +
27345 +                       /*
27346                          * proxy.server = ( "<ext>" => ...,
27347                          *                  "<ext>" => ... )
27348                          */
27349 -                       
27350 +
27351                         for (j = 0; j < da->value->used; j++) {
27352                                 data_array *da_ext = (data_array *)da->value->data[j];
27353                                 size_t n;
27354 -                               
27355 +
27356                                 if (da_ext->type != TYPE_ARRAY) {
27357 -                                       log_error_write(srv, __FILE__, __LINE__, "sssbs", 
27358 -                                                       "unexpected type for key: ", "proxy.server", 
27359 +                                       log_error_write(srv, __FILE__, __LINE__, "sssbs",
27360 +                                                       "unexpected type for key: ", "proxy.server",
27361                                                         "[", da->value->data[j]->key, "](string)");
27362 -                                       
27363 +
27364                                         return HANDLER_ERROR;
27365                                 }
27366 -                               
27367 -                               /* 
27368 -                                * proxy.server = ( "<ext>" => 
27369 -                                *                     ( "<host>" => ( ... ), 
27370 +
27371 +                               /*
27372 +                                * proxy.server = ( "<ext>" =>
27373 +                                *                     ( "<host>" => ( ... ),
27374                                  *                       "<host>" => ( ... )
27375 -                                *                     ), 
27376 +                                *                     ),
27377                                  *                    "<ext>" => ... )
27378                                  */
27379 -                               
27380 +
27381                                 for (n = 0; n < da_ext->value->used; n++) {
27382                                         data_array *da_host = (data_array *)da_ext->value->data[n];
27383 -                                       
27384 +
27385                                         data_proxy *df;
27386                                         data_array *dfa;
27387 -                                       
27388 -                                       config_values_t pcv[] = { 
27389 +
27390 +                                       config_values_t pcv[] = {
27391                                                 { "host",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 0 */
27392                                                 { "port",              NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
27393                                                 { NULL,                NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
27394                                         };
27395 -                                       
27396 +
27397                                         if (da_host->type != TYPE_ARRAY) {
27398 -                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS", 
27399 -                                                               "unexpected type for key:", 
27400 -                                                               "proxy.server", 
27401 +                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS",
27402 +                                                               "unexpected type for key:",
27403 +                                                               "proxy.server",
27404                                                                 "[", da_ext->value->data[n]->key, "](string)");
27405 -                                               
27406 +
27407                                                 return HANDLER_ERROR;
27408                                         }
27409 -                                       
27410 +
27411                                         df = data_proxy_init();
27412 -                                       
27413 +
27414                                         df->port = 80;
27415 -                                       
27416 +
27417                                         buffer_copy_string_buffer(df->key, da_host->key);
27418 -                                       
27419 +
27420                                         pcv[0].destination = df->host;
27421                                         pcv[1].destination = &(df->port);
27422 -                                       
27423 +
27424                                         if (0 != config_insert_values_internal(srv, da_host->value, pcv)) {
27425                                                 return HANDLER_ERROR;
27426                                         }
27427 -                                       
27428 +
27429                                         if (buffer_is_empty(df->host)) {
27430 -                                               log_error_write(srv, __FILE__, __LINE__, "sbbbs", 
27431 -                                                               "missing key (string):", 
27432 +                                               log_error_write(srv, __FILE__, __LINE__, "sbbbs",
27433 +                                                               "missing key (string):",
27434                                                                 da->key,
27435                                                                 da_ext->key,
27436                                                                 da_host->key,
27437                                                                 "host");
27438 -                                               
27439 +
27440                                                 return HANDLER_ERROR;
27441                                         }
27442 -                                       
27443 +
27444                                         /* if extension already exists, take it */
27445 -                                       
27446 +
27447                                         if (NULL == (dfa = (data_array *)array_get_element(s->extensions, da_ext->key->ptr))) {
27448                                                 dfa = data_array_init();
27449 -                                               
27450 +
27451                                                 buffer_copy_string_buffer(dfa->key, da_ext->key);
27452 -                                               
27453 +
27454                                                 array_insert_unique(dfa->value, (data_unset *)df);
27455                                                 array_insert_unique(s->extensions, (data_unset *)dfa);
27456                                         } else {
27457 @@ -328,67 +360,76 @@
27458                         }
27459                 }
27460         }
27461 -       
27462 +
27463         return HANDLER_GO_ON;
27464  }
27465  
27466  void proxy_connection_close(server *srv, handler_ctx *hctx) {
27467         plugin_data *p;
27468         connection *con;
27469 -       
27470 +
27471         if (NULL == hctx) return;
27472 -       
27473 +
27474         p    = hctx->plugin_data;
27475         con  = hctx->remote_conn;
27476 -       
27477 +
27478         if (hctx->fd != -1) {
27479 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
27480 +               fdevent_event_del(srv->ev, hctx->fd);
27481                 fdevent_unregister(srv->ev, hctx->fd);
27482  
27483 -               close(hctx->fd);
27484 +               close(hctx->fd->fd);
27485                 srv->cur_fds--;
27486         }
27487 -       
27488 +
27489         handler_ctx_free(hctx);
27490 -       con->plugin_ctx[p->id] = NULL;  
27491 +       con->plugin_ctx[p->id] = NULL;
27492  }
27493  
27494  static int proxy_establish_connection(server *srv, handler_ctx *hctx) {
27495         struct sockaddr *proxy_addr;
27496         struct sockaddr_in proxy_addr_in;
27497         socklen_t servlen;
27498 -       
27499 +
27500         plugin_data *p    = hctx->plugin_data;
27501         data_proxy *host= hctx->host;
27502 -       int proxy_fd       = hctx->fd;
27503 -       
27504 +       int proxy_fd       = hctx->fd->fd;
27505 +
27506         memset(&proxy_addr, 0, sizeof(proxy_addr));
27507 -       
27508 +
27509         proxy_addr_in.sin_family = AF_INET;
27510         proxy_addr_in.sin_addr.s_addr = inet_addr(host->host->ptr);
27511         proxy_addr_in.sin_port = htons(host->port);
27512         servlen = sizeof(proxy_addr_in);
27513 -               
27514 +
27515         proxy_addr = (struct sockaddr *) &proxy_addr_in;
27516 -       
27517 +
27518         if (-1 == connect(proxy_fd, proxy_addr, servlen)) {
27519 -               if (errno == EINPROGRESS || errno == EALREADY) {
27520 +#ifdef _WIN32
27521 +       errno = WSAGetLastError();
27522 +#endif
27523 +       switch(errno) {
27524 +#ifdef _WIN32
27525 +       case WSAEWOULDBLOCK:
27526 +#endif
27527 +       case EINPROGRESS:
27528 +       case EALREADY:
27529                         if (p->conf.debug) {
27530 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
27531 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
27532                                                 "connect delayed:", proxy_fd);
27533                         }
27534 -                       
27535 +
27536                         return 1;
27537 -               } else {
27538 -                       
27539 -                       log_error_write(srv, __FILE__, __LINE__, "sdsd", 
27540 +               default:
27541 +
27542 +                       log_error_write(srv, __FILE__, __LINE__, "sdsd",
27543                                         "connect failed:", proxy_fd, strerror(errno), errno);
27544 -                       
27545 +
27546                         return -1;
27547                 }
27548         }
27549 +       fprintf(stderr, "%s.%d: connected fd = %d\r\n", __FILE__, __LINE__, proxy_fd);
27550         if (p->conf.debug) {
27551 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
27552 +               log_error_write(srv, __FILE__, __LINE__, "sd",
27553                                 "connect succeeded: ", proxy_fd);
27554         }
27555  
27556 @@ -396,51 +437,52 @@
27557  }
27558  
27559  void proxy_set_header(connection *con, const char *key, const char *value) {
27560 -    data_string *ds_dst;
27561 +       data_string *ds_dst;
27562  
27563 -    if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27564 -          ds_dst = data_string_init();
27565 -    }
27566 -
27567 -    buffer_copy_string(ds_dst->key, key);
27568 -    buffer_copy_string(ds_dst->value, value);
27569 -    array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27570 +       if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27571 +               ds_dst = data_string_init();
27572 +       }
27573 +
27574 +       buffer_copy_string(ds_dst->key, key);
27575 +       buffer_copy_string(ds_dst->value, value);
27576 +       array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27577  }
27578  
27579  void proxy_append_header(connection *con, const char *key, const char *value) {
27580 -    data_string *ds_dst;
27581 +       data_string *ds_dst;
27582  
27583 -    if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27584 -          ds_dst = data_string_init();
27585 -    }
27586 -
27587 -    buffer_copy_string(ds_dst->key, key);
27588 -    buffer_append_string(ds_dst->value, value);
27589 -    array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27590 +       if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27591 +               ds_dst = data_string_init();
27592 +       }
27593 +
27594 +       buffer_copy_string(ds_dst->key, key);
27595 +       buffer_append_string(ds_dst->value, value);
27596 +       array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27597  }
27598  
27599  
27600  static int proxy_create_env(server *srv, handler_ctx *hctx) {
27601         size_t i;
27602 -       
27603 +
27604         connection *con   = hctx->remote_conn;
27605 +       plugin_data *p    = hctx->plugin_data;
27606         buffer *b;
27607 -       
27608 +
27609         /* build header */
27610  
27611         b = chunkqueue_get_append_buffer(hctx->wb);
27612 -       
27613 +
27614         /* request line */
27615         buffer_copy_string(b, get_http_method_name(con->request.http_method));
27616         BUFFER_APPEND_STRING_CONST(b, " ");
27617 -       
27618 +
27619         buffer_append_string_buffer(b, con->request.uri);
27620         BUFFER_APPEND_STRING_CONST(b, " HTTP/1.0\r\n");
27621  
27622         proxy_append_header(con, "X-Forwarded-For", (char *)inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
27623 -       /* http_host is NOT is just a pointer to a buffer 
27624 +       /* http_host is NOT is just a pointer to a buffer
27625          * which is NULL if it is not set */
27626 -       if (con->request.http_host && 
27627 +       if (con->request.http_host &&
27628             !buffer_is_empty(con->request.http_host)) {
27629                 proxy_set_header(con, "X-Host", con->request.http_host->ptr);
27630         }
27631 @@ -449,24 +491,25 @@
27632         /* request header */
27633         for (i = 0; i < con->request.headers->used; i++) {
27634                 data_string *ds;
27635 -               
27636 +
27637                 ds = (data_string *)con->request.headers->data[i];
27638 -               
27639 -               if (ds->value->used && ds->key->used) {
27640 -                       if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
27641 -                       
27642 -                       buffer_append_string_buffer(b, ds->key);
27643 -                       BUFFER_APPEND_STRING_CONST(b, ": ");
27644 -                       buffer_append_string_buffer(b, ds->value);
27645 -                       BUFFER_APPEND_STRING_CONST(b, "\r\n");
27646 -               }
27647 +
27648 +               if (buffer_is_empty(ds->value) || buffer_is_empty(ds->key)) continue;
27649 +
27650 +               if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
27651 +               if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Keep-Alive"))) continue;
27652 +
27653 +               buffer_append_string_buffer(b, ds->key);
27654 +               BUFFER_APPEND_STRING_CONST(b, ": ");
27655 +               buffer_append_string_buffer(b, ds->value);
27656 +               BUFFER_APPEND_STRING_CONST(b, "\r\n");
27657         }
27658 -       
27659 +
27660         BUFFER_APPEND_STRING_CONST(b, "\r\n");
27661 -       
27662 +
27663         hctx->wb->bytes_in += b->used - 1;
27664         /* body */
27665 -       
27666 +
27667         if (con->request.content_length) {
27668                 chunkqueue *req_cq = con->request_content_queue;
27669                 chunk *req_c;
27670 @@ -479,7 +522,7 @@
27671  
27672                         /* we announce toWrite octects
27673                          * now take all the request_content chunk that we need to fill this request
27674 -                        * */   
27675 +                        * */
27676  
27677                         switch (req_c->type) {
27678                         case FILE_CHUNK:
27679 @@ -507,223 +550,150 @@
27680  
27681                                 req_c->offset += weHave;
27682                                 req_cq->bytes_out += weHave;
27683 -                               
27684 +
27685                                 hctx->wb->bytes_in += weHave;
27686  
27687                                 break;
27688                         default:
27689                                 break;
27690                         }
27691 -                       
27692 +
27693                         offset += weHave;
27694                 }
27695  
27696         }
27697 -       
27698 +
27699         return 0;
27700  }
27701  
27702  static int proxy_set_state(server *srv, handler_ctx *hctx, proxy_connection_state_t state) {
27703         hctx->state = state;
27704         hctx->state_timestamp = srv->cur_ts;
27705 -       
27706 -       return 0;
27707 -}
27708  
27709 -
27710 -static int proxy_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
27711 -       char *s, *ns;
27712 -       int http_response_status = -1;
27713 -       
27714 -       UNUSED(srv);
27715 -
27716 -       /* \r\n -> \0\0 */
27717 -       
27718 -       buffer_copy_string_buffer(p->parse_response, in);
27719 -       
27720 -       for (s = p->parse_response->ptr; NULL != (ns = strstr(s, "\r\n")); s = ns + 2) {
27721 -               char *key, *value;
27722 -               int key_len;
27723 -               data_string *ds;
27724 -               int copy_header;
27725 -               
27726 -               ns[0] = '\0';
27727 -               ns[1] = '\0';
27728 -
27729 -               if (-1 == http_response_status) {
27730 -                       /* The first line of a Response message is the Status-Line */
27731 -
27732 -                       for (key=s; *key && *key != ' '; key++);
27733 -
27734 -                       if (*key) {
27735 -                               http_response_status = (int) strtol(key, NULL, 10);
27736 -                               if (http_response_status <= 0) http_response_status = 502;
27737 -                       } else {
27738 -                               http_response_status = 502;
27739 -                       }
27740 -
27741 -                       con->http_status = http_response_status;
27742 -                       con->parsed_response |= HTTP_STATUS;
27743 -                       continue;
27744 -               }
27745 -               
27746 -               if (NULL == (value = strchr(s, ':'))) {
27747 -                       /* now we expect: "<key>: <value>\n" */
27748 -
27749 -                       continue;
27750 -               }
27751 -
27752 -               key = s;
27753 -               key_len = value - key;
27754 -               
27755 -               value++;
27756 -               /* strip WS */
27757 -               while (*value == ' ' || *value == '\t') value++;
27758 -               
27759 -               copy_header = 1;
27760 -               
27761 -               switch(key_len) {
27762 -               case 4:
27763 -                       if (0 == strncasecmp(key, "Date", key_len)) {
27764 -                               con->parsed_response |= HTTP_DATE;
27765 -                       }
27766 -                       break;
27767 -               case 8:
27768 -                       if (0 == strncasecmp(key, "Location", key_len)) {
27769 -                               con->parsed_response |= HTTP_LOCATION;
27770 -                       }
27771 -                       break;
27772 -               case 10:
27773 -                       if (0 == strncasecmp(key, "Connection", key_len)) {
27774 -                               copy_header = 0;
27775 -                       }
27776 -                       break;
27777 -               case 14:
27778 -                       if (0 == strncasecmp(key, "Content-Length", key_len)) {
27779 -                               con->response.content_length = strtol(value, NULL, 10);
27780 -                               con->parsed_response |= HTTP_CONTENT_LENGTH;
27781 -                       }
27782 -                       break;
27783 -               default:
27784 -                       break;
27785 -               }
27786 -
27787 -               if (copy_header) {
27788 -                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
27789 -                               ds = data_response_init();
27790 -                       }
27791 -                       buffer_copy_string_len(ds->key, key, key_len);
27792 -                       buffer_copy_string(ds->value, value);
27793 -                       
27794 -                       array_insert_unique(con->response.headers, (data_unset *)ds);
27795 -               }
27796 -       }
27797 -       
27798         return 0;
27799  }
27800  
27801  
27802  static int proxy_demux_response(server *srv, handler_ctx *hctx) {
27803 -       int fin = 0;
27804 -       int b;
27805 -       ssize_t r;
27806 -       
27807         plugin_data *p    = hctx->plugin_data;
27808         connection *con   = hctx->remote_conn;
27809 -       int proxy_fd       = hctx->fd;
27810 -       
27811 -       /* check how much we have to read */
27812 -       if (ioctl(hctx->fd, FIONREAD, &b)) {
27813 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
27814 -                               "ioctl failed: ",
27815 -                               proxy_fd);
27816 +       chunkqueue *next_queue = NULL;
27817 +       chunk *c = NULL;
27818 +
27819 +       switch(srv->network_backend_read(srv, con, hctx->fd, hctx->rb)) {
27820 +       case NETWORK_STATUS_SUCCESS:
27821 +               /* we got content */
27822 +               break;
27823 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
27824 +               return 0;
27825 +       case NETWORK_STATUS_CONNECTION_CLOSE:
27826 +               /* we are done, get out of here */
27827 +               con->file_finished = 1;
27828 +
27829 +               /* close the chunk-queue with a empty chunk */
27830 +
27831 +               return 1;
27832 +       default:
27833 +               /* oops */
27834                 return -1;
27835         }
27836  
27837 +       /* looks like we got some content
27838 +       *
27839 +       * split off the header from the incoming stream
27840 +       */
27841  
27842 -       if (p->conf.debug) {
27843 -               log_error_write(srv, __FILE__, __LINE__, "sd",
27844 -                              "proxy - have to read:", b);
27845 -       }
27846 +       if (hctx->state == PROXY_STATE_RESPONSE_HEADER) {
27847 +               size_t i;
27848 +               int have_content_length = 0;
27849  
27850 -       if (b > 0) {
27851 -               if (hctx->response->used == 0) {
27852 -                       /* avoid too small buffer */
27853 -                       buffer_prepare_append(hctx->response, b + 1);
27854 -                       hctx->response->used = 1;
27855 -               } else {
27856 -                       buffer_prepare_append(hctx->response, hctx->response->used + b);
27857 -               }
27858 -               
27859 -               if (-1 == (r = read(hctx->fd, hctx->response->ptr + hctx->response->used - 1, b))) {
27860 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
27861 -                                       "unexpected end-of-file (perhaps the proxy process died):",
27862 -                                       proxy_fd, strerror(errno));
27863 -                       return -1;
27864 -               }
27865 -               
27866 -               /* this should be catched by the b > 0 above */
27867 -               assert(r);
27868 -               
27869 -               hctx->response->used += r;
27870 -               hctx->response->ptr[hctx->response->used - 1] = '\0';
27871 -
27872 -#if 0
27873 -               log_error_write(srv, __FILE__, __LINE__, "sdsbs", 
27874 -                               "demux: Response buffer len", hctx->response->used, ":", hctx->response, ":");
27875 -#endif
27876 +               http_response_reset(p->resp);
27877  
27878 -               if (0 == con->got_response) {
27879 -                       con->got_response = 1;
27880 -                       buffer_prepare_copy(hctx->response_header, 128);
27881 -               }
27882 -                               
27883 -               if (0 == con->file_started) {
27884 -                       char *c;
27885 -                               
27886 -                       /* search for the \r\n\r\n in the string */
27887 -                       if (NULL != (c = buffer_search_string_len(hctx->response, "\r\n\r\n", 4))) {
27888 -                               size_t hlen = c - hctx->response->ptr + 4;
27889 -                               size_t blen = hctx->response->used - hlen - 1;
27890 -                               /* found */
27891 -                               
27892 -                               buffer_append_string_len(hctx->response_header, hctx->response->ptr, c - hctx->response->ptr + 4);
27893 -#if 0
27894 -                               log_error_write(srv, __FILE__, __LINE__, "sb", "Header:", hctx->response_header);
27895 -#endif
27896 -                               /* parse the response header */
27897 -                               proxy_response_parse(srv, con, p, hctx->response_header);
27898 -                                       
27899 -                               /* enable chunked-transfer-encoding */
27900 -                               if (con->request.http_version == HTTP_VERSION_1_1 &&
27901 -                                   !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
27902 -                                       con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
27903 +               /* the response header is not fully received yet,
27904 +               *
27905 +               * extract the http-response header from the rb-cq
27906 +               */
27907 +               switch (http_response_parse_cq(hctx->rb, p->resp)) {
27908 +               case PARSE_ERROR:
27909 +                       /* parsing failed */
27910 +
27911 +                       con->http_status = 502; /* Bad Gateway */
27912 +                       return 1;
27913 +               case PARSE_NEED_MORE:
27914 +                       return 0;
27915 +               case PARSE_SUCCESS:
27916 +                       con->http_status = p->resp->status;
27917 +
27918 +                       chunkqueue_remove_finished_chunks(hctx->rb);
27919 +
27920 +                       /* copy the http-headers */
27921 +                       for (i = 0; i < p->resp->headers->used; i++) {
27922 +                               const char *ign[] = { "Status", "Connection", NULL };
27923 +                               size_t j;
27924 +                               data_string *ds;
27925 +
27926 +                               data_string *header = (data_string *)p->resp->headers->data[i];
27927 +
27928 +                               /* some headers are ignored by default */
27929 +                               for (j = 0; ign[j]; j++) {
27930 +                                       if (0 == strcasecmp(ign[j], header->key->ptr)) break;
27931 +                               }
27932 +                               if (ign[j]) continue;
27933 +
27934 +                               if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
27935 +                                       /* CGI/1.1 rev 03 - 7.2.1.2 */
27936 +                                       if (con->http_status == 0) con->http_status = 302;
27937 +                               } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
27938 +                                       have_content_length = 1;
27939                                 }
27940 -                                       
27941 -                               con->file_started = 1;
27942 -                               if (blen) {
27943 -                                       http_chunk_append_mem(srv, con, c + 4, blen + 1);
27944 -                                       joblist_append(srv, con);
27945 +                               
27946 +                               if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
27947 +                                       ds = data_response_init();
27948                                 }
27949 -                               hctx->response->used = 0;
27950 +                               buffer_copy_string_buffer(ds->key, header->key);
27951 +                               buffer_copy_string_buffer(ds->value, header->value);
27952 +
27953 +                               array_insert_unique(con->response.headers, (data_unset *)ds);
27954                         }
27955 -               } else {
27956 -                       http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
27957 -                       joblist_append(srv, con);
27958 -                       hctx->response->used = 0;
27959 +
27960 +                       con->file_started = 1;
27961 +
27962 +                       if (con->request.http_version == HTTP_VERSION_1_1 &&
27963 +                           !have_content_length) {
27964 +                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
27965 +                       }
27966 +
27967 +                       hctx->state = PROXY_STATE_RESPONSE_CONTENT;
27968 +                       break;
27969                 }
27970 -               
27971 -       } else {
27972 -               /* reading from upstream done */
27973 -               con->file_finished = 1;
27974 -               
27975 -               http_chunk_append_mem(srv, con, NULL, 0);
27976 -               joblist_append(srv, con);
27977 -               
27978 -               fin = 1;
27979         }
27980 -       
27981 -       return fin;
27982 +
27983 +       /* FIXME: pass the response-header to the other plugins to
27984 +       * setup the filter-queue
27985 +       *
27986 +       * - use next-queue instead of con->write_queue
27987 +       */
27988 +
27989 +       next_queue = con->write_queue;
27990 +
27991 +       assert(hctx->state == PROXY_STATE_RESPONSE_CONTENT);
27992 +
27993 +       /* FIXME: if we have a content-length or chunked-encoding
27994 +       * handle it.
27995 +       *
27996 +       * for now we wait for EOF on the socket */
27997 +
27998 +       /* copy the content to the next cq */
27999 +       for (c = hctx->rb->first; c; c = c->next) {
28000 +               http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
28001 +
28002 +               c->offset = c->mem->used - 1;
28003 +       }
28004 +
28005 +       chunkqueue_remove_finished_chunks(hctx->rb);
28006 +       joblist_append(srv, con);
28007 +
28008 +       return 0;
28009  }
28010  
28011  
28012 @@ -731,32 +701,32 @@
28013         data_proxy *host= hctx->host;
28014         plugin_data *p    = hctx->plugin_data;
28015         connection *con   = hctx->remote_conn;
28016 -       
28017 +
28018         int ret;
28019 -       
28020 -       if (!host || 
28021 -           (!host->host->used || !host->port)) return -1;
28022 -       
28023 +
28024 +       if (!host ||
28025 +               (!host->host->used || !host->port)) return -1;
28026 +
28027         switch(hctx->state) {
28028         case PROXY_STATE_INIT:
28029 -               if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) {
28030 +               if (-1 == (hctx->fd->fd = socket(AF_INET, SOCK_STREAM, 0))) {
28031                         log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
28032                         return HANDLER_ERROR;
28033                 }
28034 -               hctx->fde_ndx = -1;
28035 -               
28036 +               hctx->fd->fde_ndx = -1;
28037 +
28038                 srv->cur_fds++;
28039 -               
28040 +
28041                 fdevent_register(srv->ev, hctx->fd, proxy_handle_fdevent, hctx);
28042 -               
28043 +
28044                 if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
28045                         log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
28046 -                       
28047 +
28048                         return HANDLER_ERROR;
28049                 }
28050 -               
28051 +
28052                 /* fall through */
28053 -               
28054 +
28055         case PROXY_STATE_CONNECT:
28056                 /* try to finish the connect() */
28057                 if (hctx->state == PROXY_STATE_INIT) {
28058 @@ -764,16 +734,16 @@
28059                         switch (proxy_establish_connection(srv, hctx)) {
28060                         case 1:
28061                                 proxy_set_state(srv, hctx, PROXY_STATE_CONNECT);
28062 -                               
28063 +
28064                                 /* connection is in progress, wait for an event and call getsockopt() below */
28065 -                               
28066 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28067 -                               
28068 +
28069 +                               fdevent_event_add(srv->ev, hctx->fd, FDEVENT_OUT);
28070 +
28071                                 return HANDLER_WAIT_FOR_EVENT;
28072                         case -1:
28073                                 /* if ECONNREFUSED choose another connection -> FIXME */
28074 -                               hctx->fde_ndx = -1;
28075 -                               
28076 +                               hctx->fd->fde_ndx = -1;
28077 +
28078                                 return HANDLER_ERROR;
28079                         default:
28080                                 /* everything is ok, go on */
28081 @@ -782,152 +752,152 @@
28082                 } else {
28083                         int socket_error;
28084                         socklen_t socket_error_len = sizeof(socket_error);
28085 -               
28086 -                       /* we don't need it anymore */  
28087 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
28088 +
28089 +                       /* we don't need it anymore */
28090 +                       fdevent_event_del(srv->ev, hctx->fd);
28091  
28092                         /* try to finish the connect() */
28093 -                       if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
28094 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
28095 +                       if (0 != getsockopt(hctx->fd->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
28096 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
28097                                                 "getsockopt failed:", strerror(errno));
28098 -                               
28099 +
28100                                 return HANDLER_ERROR;
28101                         }
28102                         if (socket_error != 0) {
28103                                 log_error_write(srv, __FILE__, __LINE__, "ss",
28104 -                                               "establishing connection failed:", strerror(socket_error), 
28105 +                                               "establishing connection failed:", strerror(socket_error),
28106                                                 "port:", hctx->host->port);
28107 -                               
28108 +
28109                                 return HANDLER_ERROR;
28110                         }
28111                         if (p->conf.debug) {
28112 -                               log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - connect - delayed success"); 
28113 +                               log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - connect - delayed success");
28114                         }
28115                 }
28116 -               
28117 +
28118                 proxy_set_state(srv, hctx, PROXY_STATE_PREPARE_WRITE);
28119                 /* fall through */
28120         case PROXY_STATE_PREPARE_WRITE:
28121                 proxy_create_env(srv, hctx);
28122 -               
28123 +
28124                 proxy_set_state(srv, hctx, PROXY_STATE_WRITE);
28125 -               
28126 +
28127                 /* fall through */
28128         case PROXY_STATE_WRITE:;
28129 -               ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); 
28130 +               ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb);
28131  
28132                 chunkqueue_remove_finished_chunks(hctx->wb);
28133  
28134 -               if (-1 == ret) {
28135 -                       if (errno != EAGAIN &&
28136 -                           errno != EINTR) {
28137 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
28138 -                               
28139 -                               return HANDLER_ERROR;
28140 -                       } else {
28141 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28142 +               switch(ret) {
28143 +               case NETWORK_STATUS_FATAL_ERROR:
28144 +                       log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
28145  
28146 -                               return HANDLER_WAIT_FOR_EVENT;
28147 -                       }
28148 +                       return HANDLER_ERROR;
28149 +               case NETWORK_STATUS_WAIT_FOR_EVENT:
28150 +
28151 +                       fdevent_event_add(srv->ev, hctx->fd, FDEVENT_OUT);
28152 +
28153 +                       return HANDLER_WAIT_FOR_EVENT;
28154                 }
28155  
28156                 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
28157 -                       proxy_set_state(srv, hctx, PROXY_STATE_READ);
28158 +                       proxy_set_state(srv, hctx, PROXY_STATE_RESPONSE_HEADER);
28159  
28160 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
28161 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
28162 +                       fdevent_event_del(srv->ev, hctx->fd);
28163 +                       fdevent_event_add(srv->ev, hctx->fd, FDEVENT_IN);
28164                 } else {
28165 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28166 -                               
28167 +                       fdevent_event_add(srv->ev, hctx->fd, FDEVENT_OUT);
28168 +
28169                         return HANDLER_WAIT_FOR_EVENT;
28170                 }
28171 -               
28172 +
28173                 return HANDLER_WAIT_FOR_EVENT;
28174 -       case PROXY_STATE_READ:
28175 +       case PROXY_STATE_RESPONSE_CONTENT:
28176 +       case PROXY_STATE_RESPONSE_HEADER:
28177                 /* waiting for a response */
28178 +
28179                 return HANDLER_WAIT_FOR_EVENT;
28180         default:
28181                 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
28182                 return HANDLER_ERROR;
28183         }
28184 -       
28185 +
28186         return HANDLER_GO_ON;
28187  }
28188  
28189 -#define PATCH(x) \
28190 -       p->conf.x = s->x;
28191  static int mod_proxy_patch_connection(server *srv, connection *con, plugin_data *p) {
28192         size_t i, j;
28193         plugin_config *s = p->config_storage[0];
28194 -       
28195 -       PATCH(extensions);
28196 -       PATCH(debug);
28197 -       PATCH(balance);
28198 -       
28199 +
28200 +       PATCH_OPTION(extensions);
28201 +       PATCH_OPTION(debug);
28202 +       PATCH_OPTION(balance);
28203 +       PATCH_OPTION(last_used_backends);
28204 +
28205         /* skip the first, the global context */
28206         for (i = 1; i < srv->config_context->used; i++) {
28207                 data_config *dc = (data_config *)srv->config_context->data[i];
28208                 s = p->config_storage[i];
28209 -               
28210 +
28211                 /* condition didn't match */
28212                 if (!config_check_cond(srv, con, dc)) continue;
28213 -               
28214 +
28215                 /* merge config */
28216                 for (j = 0; j < dc->value->used; j++) {
28217                         data_unset *du = dc->value->data[j];
28218 -                       
28219 +
28220                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.server"))) {
28221 -                               PATCH(extensions);
28222 +                               PATCH_OPTION(extensions);
28223                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.debug"))) {
28224 -                               PATCH(debug);
28225 +                               PATCH_OPTION(debug);
28226                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.balance"))) {
28227 -                               PATCH(balance);
28228 +                               PATCH_OPTION(balance);
28229 +                               PATCH_OPTION(last_used_backends);
28230                         }
28231                 }
28232         }
28233 -       
28234 +
28235         return 0;
28236  }
28237 -#undef PATCH
28238  
28239  SUBREQUEST_FUNC(mod_proxy_handle_subrequest) {
28240         plugin_data *p = p_d;
28241 -       
28242 +
28243         handler_ctx *hctx = con->plugin_ctx[p->id];
28244         data_proxy *host;
28245 -       
28246 +
28247         if (NULL == hctx) return HANDLER_GO_ON;
28248  
28249         mod_proxy_patch_connection(srv, con, p);
28250 -       
28251 +
28252         host = hctx->host;
28253 -       
28254 +
28255         /* not my job */
28256         if (con->mode != p->id) return HANDLER_GO_ON;
28257 -       
28258 +
28259         /* ok, create the request */
28260         switch(proxy_write_request(srv, hctx)) {
28261         case HANDLER_ERROR:
28262 -               log_error_write(srv, __FILE__, __LINE__,  "sbdd", "proxy-server disabled:", 
28263 +               log_error_write(srv, __FILE__, __LINE__,  "sbdd", "proxy-server disabled:",
28264                                 host->host,
28265                                 host->port,
28266 -                               hctx->fd);
28267 -               
28268 +                               hctx->fd->fd);
28269 +
28270                 /* disable this server */
28271                 host->is_disabled = 1;
28272                 host->disable_ts = srv->cur_ts;
28273 -               
28274 +
28275                 proxy_connection_close(srv, hctx);
28276 -       
28277 -               /* reset the enviroment and restart the sub-request */  
28278 +
28279 +               /* reset the enviroment and restart the sub-request */
28280                 buffer_reset(con->physical.path);
28281                 con->mode = DIRECT;
28282  
28283                 joblist_append(srv, con);
28284  
28285 -               /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop 
28286 -                * and hope that the childs will be restarted 
28287 -                * 
28288 +               /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
28289 +                * and hope that the childs will be restarted
28290 +                *
28291                  */
28292  
28293                 return HANDLER_WAIT_FOR_FD;
28294 @@ -938,7 +908,7 @@
28295         default:
28296                 break;
28297         }
28298 -       
28299 +
28300         if (con->file_started == 1) {
28301                 return HANDLER_FINISHED;
28302         } else {
28303 @@ -951,13 +921,14 @@
28304         handler_ctx *hctx = ctx;
28305         connection  *con  = hctx->remote_conn;
28306         plugin_data *p    = hctx->plugin_data;
28307 -       
28308 -       
28309 +
28310 +
28311         if ((revents & FDEVENT_IN) &&
28312 -           hctx->state == PROXY_STATE_READ) {
28313 +           (hctx->state == PROXY_STATE_RESPONSE_HEADER ||
28314 +            hctx->state == PROXY_STATE_RESPONSE_CONTENT)) {
28315  
28316                 if (p->conf.debug) {
28317 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
28318 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
28319                                         "proxy: fdevent-in", hctx->state);
28320                 }
28321  
28322 @@ -965,11 +936,15 @@
28323                 case 0:
28324                         break;
28325                 case 1:
28326 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
28327 +                                       "proxy: request done", hctx->fd->fd);
28328                         hctx->host->usage--;
28329 -                       
28330 +
28331 +                       http_chunk_append_mem(srv, con, NULL, 0);
28332 +
28333                         /* we are done */
28334                         proxy_connection_close(srv, hctx);
28335 -                       
28336 +
28337                         joblist_append(srv, con);
28338                         return HANDLER_FINISHED;
28339                 case -1:
28340 @@ -982,53 +957,53 @@
28341                                 /* response might have been already started, kill the connection */
28342                                 connection_set_state(srv, con, CON_STATE_ERROR);
28343                         }
28344 -                       
28345 +
28346                         joblist_append(srv, con);
28347                         return HANDLER_FINISHED;
28348                 }
28349         }
28350 -       
28351 +
28352         if (revents & FDEVENT_OUT) {
28353                 if (p->conf.debug) {
28354 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
28355 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
28356                                         "proxy: fdevent-out", hctx->state);
28357                 }
28358  
28359                 if (hctx->state == PROXY_STATE_CONNECT ||
28360                     hctx->state == PROXY_STATE_WRITE) {
28361                         /* we are allowed to send something out
28362 -                        * 
28363 +                        *
28364                          * 1. in a unfinished connect() call
28365                          * 2. in a unfinished write() call (long POST request)
28366                          */
28367                         return mod_proxy_handle_subrequest(srv, con, p);
28368                 } else {
28369 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
28370 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
28371                                         "proxy: out", hctx->state);
28372                 }
28373         }
28374 -       
28375 +
28376         /* perhaps this issue is already handled */
28377         if (revents & FDEVENT_HUP) {
28378                 if (p->conf.debug) {
28379 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
28380 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
28381                                         "proxy: fdevent-hup", hctx->state);
28382                 }
28383 -               
28384 +
28385                 if (hctx->state == PROXY_STATE_CONNECT) {
28386                         /* connect() -> EINPROGRESS -> HUP */
28387 -                       
28388 +
28389                         /**
28390 -                        * what is proxy is doing if it can't reach the next hop ? 
28391 -                        * 
28392 +                        * what is proxy is doing if it can't reach the next hop ?
28393 +                        *
28394                          */
28395 -                       
28396 +
28397                         proxy_connection_close(srv, hctx);
28398                         joblist_append(srv, con);
28399 -                       
28400 +
28401                         con->http_status = 503;
28402                         con->mode = DIRECT;
28403 -                       
28404 +
28405                         return HANDLER_FINISHED;
28406                 }
28407  
28408 @@ -1038,13 +1013,13 @@
28409                 joblist_append(srv, con);
28410         } else if (revents & FDEVENT_ERR) {
28411                 /* kill all connections to the proxy process */
28412 -               
28413 +
28414                 log_error_write(srv, __FILE__, __LINE__, "sd", "proxy-FDEVENT_ERR, but no HUP", revents);
28415  
28416                 joblist_append(srv, con);
28417                 proxy_connection_close(srv, hctx);
28418         }
28419 -       
28420 +
28421         return HANDLER_FINISHED;
28422  }
28423  
28424 @@ -1058,44 +1033,48 @@
28425         buffer *fn;
28426         data_array *extension = NULL;
28427         size_t path_info_offset;
28428 -       
28429 +       data_integer *last_used_backend;
28430 +       data_proxy *host = NULL;
28431 +       handler_ctx *hctx = NULL;
28432 +
28433 +       array *backends = NULL;
28434 +
28435         /* Possibly, we processed already this request */
28436         if (con->file_started == 1) return HANDLER_GO_ON;
28437 -       
28438 +
28439         mod_proxy_patch_connection(srv, con, p);
28440 -       
28441 +
28442         fn = con->uri.path;
28443  
28444         if (fn->used == 0) {
28445                 return HANDLER_ERROR;
28446         }
28447 -       
28448 +
28449         s_len = fn->used - 1;
28450 -       
28451 -       
28452 +
28453         path_info_offset = 0;
28454  
28455 -       if (p->conf.debug) {    
28456 +       if (p->conf.debug) {
28457                 log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - start");
28458         }
28459  
28460         /* check if extension matches */
28461         for (k = 0; k < p->conf.extensions->used; k++) {
28462                 size_t ct_len;
28463 -               
28464 +
28465                 extension = (data_array *)p->conf.extensions->data[k];
28466 -               
28467 +
28468                 if (extension->key->used == 0) continue;
28469 -               
28470 +
28471                 ct_len = extension->key->used - 1;
28472 -               
28473 +
28474                 if (s_len < ct_len) continue;
28475 -               
28476 +
28477                 /* check extension in the form "/proxy_pattern" */
28478                 if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
28479                         if (s_len > ct_len + 1) {
28480                                 char *pi_offset;
28481 -                               
28482 +
28483                                 if (0 != (pi_offset = strchr(fn->ptr + ct_len + 1, '/'))) {
28484                                         path_info_offset = pi_offset - fn->ptr;
28485                                 }
28486 @@ -1106,12 +1085,14 @@
28487                         break;
28488                 }
28489         }
28490 -       
28491 +
28492         if (k == p->conf.extensions->used) {
28493                 return HANDLER_GO_ON;
28494         }
28495  
28496 -       if (p->conf.debug) {    
28497 +       backends = extension->value;
28498 +
28499 +       if (p->conf.debug) {
28500                 log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - ext found");
28501         }
28502  
28503 @@ -1120,34 +1101,34 @@
28504                 /* hash balancing */
28505  
28506                 if (p->conf.debug) {
28507 -                       log_error_write(srv, __FILE__, __LINE__,  "sd", 
28508 -                                       "proxy - used hash balancing, hosts:", extension->value->used);
28509 +                       log_error_write(srv, __FILE__, __LINE__,  "sd",
28510 +                                       "proxy - used hash balancing, hosts:", backends->used);
28511                 }
28512  
28513 -               for (k = 0, ndx = -1, last_max = ULONG_MAX; k < extension->value->used; k++) {
28514 -                       data_proxy *host = (data_proxy *)extension->value->data[k];
28515 +               for (k = 0, ndx = -1, last_max = ULONG_MAX; k < backends->used; k++) {
28516                         unsigned long cur_max;
28517  
28518 -                       if (host->is_disabled) continue;
28519 -                       
28520 +                       data_proxy *cur = (data_proxy *)backends->data[k];
28521 +
28522 +                       if (cur->is_disabled) continue;
28523 +
28524                         cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) +
28525 -                               generate_crc32c(CONST_BUF_LEN(host->host)) + /* we can cache this */
28526 +                               generate_crc32c(CONST_BUF_LEN(cur->host)) + /* we can cache this */
28527                                 generate_crc32c(CONST_BUF_LEN(con->uri.authority));
28528 -                       
28529 +
28530                         if (p->conf.debug) {
28531 -                               log_error_write(srv, __FILE__, __LINE__,  "sbbbd", 
28532 +                               log_error_write(srv, __FILE__, __LINE__,  "sbbbd",
28533                                                 "proxy - election:",
28534                                                 con->uri.path,
28535 -                                               host->host,
28536 +                                               cur->host,
28537                                                 con->uri.authority,
28538                                                 cur_max);
28539                         }
28540  
28541 -                       if ((last_max == ULONG_MAX) || /* first round */
28542 -                           (cur_max > last_max)) {
28543 +                       if (host == NULL || (cur_max > last_max)) {
28544                                 last_max = cur_max;
28545  
28546 -                               ndx = k;
28547 +                               host = cur;
28548                         }
28549                 }
28550  
28551 @@ -1155,19 +1136,20 @@
28552         case PROXY_BALANCE_FAIR:
28553                 /* fair balancing */
28554                 if (p->conf.debug) {
28555 -                       log_error_write(srv, __FILE__, __LINE__,  "s", 
28556 +                       log_error_write(srv, __FILE__, __LINE__,  "s",
28557                                         "proxy - used fair balancing");
28558                 }
28559  
28560 -               for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) {
28561 -                       data_proxy *host = (data_proxy *)extension->value->data[k];
28562 -               
28563 -                       if (host->is_disabled) continue;
28564 -
28565 -                       if (host->usage < max_usage) {
28566 -                               max_usage = host->usage;
28567 -                       
28568 -                               ndx = k;
28569 +               /* try to find the host with the lowest load */
28570 +               for (k = 0, max_usage = 0; k < backends->used; k++) {
28571 +                       data_proxy *cur = (data_proxy *)backends->data[k];
28572 +
28573 +                       if (cur->is_disabled) continue;
28574 +
28575 +                       if (NULL == host || cur->usage < max_usage) {
28576 +                               max_usage = cur->usage;
28577 +
28578 +                               host = cur;
28579                         }
28580                 }
28581  
28582 @@ -1175,89 +1157,100 @@
28583         case PROXY_BALANCE_RR:
28584                 /* round robin */
28585                 if (p->conf.debug) {
28586 -                       log_error_write(srv, __FILE__, __LINE__,  "s", 
28587 +                       log_error_write(srv, __FILE__, __LINE__,  "s",
28588                                         "proxy - used round-robin balancing");
28589                 }
28590  
28591                 /* just to be sure */
28592 -               assert(extension->value->used < INT_MAX);
28593 -               
28594 -               for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) {
28595 -                       data_proxy *host = (data_proxy *)extension->value->data[k];
28596 -               
28597 -                       if (host->is_disabled) continue;
28598 -
28599 -                       /* first usable ndx */
28600 -                       if (max_usage == INT_MAX) {
28601 -                               max_usage = k;
28602 -                       }
28603 +               assert(backends->used < INT_MAX);
28604  
28605 -                       /* get next ndx */
28606 -                       if ((int)k > host->last_used_ndx) {
28607 -                               ndx = k;
28608 -                               host->last_used_ndx = k;
28609 +               /* send each request to another host:
28610 +                *
28611 +                * e.g.:
28612 +                *
28613 +                * if we have three hosts it is
28614 +                *
28615 +                * 1 .. 2 .. 3 .. 1 .. 2 .. 3
28616 +                *
28617 +                **/
28618  
28619 -                               break;
28620 -                       }
28621 +               /* walk through the list */
28622 +               last_used_backend = (data_integer *)array_get_element(p->conf.last_used_backends, extension->key->ptr);
28623 +
28624 +               if (NULL == last_used_backend) {
28625 +                       last_used_backend = data_integer_init();
28626 +
28627 +                       buffer_copy_string_buffer(last_used_backend->key, extension->key);
28628 +                       last_used_backend->value = 0;
28629 +
28630 +                       array_insert_unique(p->conf.last_used_backends, (data_unset *)last_used_backend);
28631 +               }
28632 +
28633 +               /* scan all but the last host to see if they are up
28634 +                * take the first running host */
28635 +               for (k = last_used_backend->value + 1; (int)(k % backends->used) != last_used_backend->value; k++) {
28636 +                       data_proxy *cur = (data_proxy *)backends->data[k % backends->used];
28637 +
28638 +                       if (cur->is_disabled) continue;
28639 +
28640 +                       host = cur;
28641 +
28642 +                       last_used_backend->value = k;
28643 +
28644 +                       break;
28645                 }
28646 -               
28647 -               /* didn't found a higher id, wrap to the start */
28648 -               if (ndx != -1 && max_usage != INT_MAX) {
28649 -                       ndx = max_usage;
28650 +
28651 +               if (NULL == host) {
28652 +                       /* we found nothing better, fallback to the last used backend
28653 +                        * and check if it is still up */
28654 +                       host = (data_proxy *)backends->data[last_used_backend->value];
28655 +
28656 +                       if (host->is_disabled) host = NULL;
28657                 }
28658  
28659                 break;
28660         default:
28661                 break;
28662         }
28663 -       
28664 -       /* found a server */
28665 -       if (ndx != -1) {
28666 -               data_proxy *host = (data_proxy *)extension->value->data[ndx];
28667 -               
28668 -               /* 
28669 -                * if check-local is disabled, use the uri.path handler 
28670 -                * 
28671 -                */
28672 -               
28673 -               /* init handler-context */
28674 -               handler_ctx *hctx;
28675 -               hctx = handler_ctx_init();
28676 -                               
28677 -               hctx->path_info_offset = path_info_offset;
28678 -               hctx->remote_conn      = con;
28679 -               hctx->plugin_data      = p;
28680 -               hctx->host             = host;
28681 -                               
28682 -               con->plugin_ctx[p->id] = hctx;
28683 -               
28684 -               host->usage++;
28685 -               
28686 -               con->mode = p->id;
28687 -               
28688 -               if (p->conf.debug) {
28689 -                       log_error_write(srv, __FILE__, __LINE__,  "sbd", 
28690 -                                       "proxy - found a host",
28691 -                                       host->host, host->port);
28692 -               }
28693  
28694 -               return HANDLER_GO_ON;
28695 -       } else {
28696 -               /* no handler found */
28697 +       /* we havn't found a host */
28698 +       if (NULL == host) {
28699                 con->http_status = 500;
28700 -               
28701 -               log_error_write(srv, __FILE__, __LINE__,  "sb", 
28702 -                               "no proxy-handler found for:", 
28703 +
28704 +               log_error_write(srv, __FILE__, __LINE__,  "sb",
28705 +                               "no proxy-handler found for:",
28706                                 fn);
28707 -               
28708 +
28709                 return HANDLER_FINISHED;
28710         }
28711 +
28712 +       /* init handler-context */
28713 +       hctx = handler_ctx_init();
28714 +
28715 +       hctx->path_info_offset = path_info_offset;
28716 +       hctx->remote_conn      = con;
28717 +       hctx->plugin_data      = p;
28718 +       hctx->host             = host;
28719 +
28720 +       con->plugin_ctx[p->id] = hctx;
28721 +
28722 +       host->usage++;
28723 +
28724 +       /* we handle this request */
28725 +       con->mode = p->id;
28726 +
28727 +       if (p->conf.debug) {
28728 +               log_error_write(srv, __FILE__, __LINE__,  "sbd",
28729 +                               "proxy - found a host",
28730 +                               host->host, host->port);
28731 +       }
28732 +
28733         return HANDLER_GO_ON;
28734  }
28735  
28736  static handler_t mod_proxy_connection_close_callback(server *srv, connection *con, void *p_d) {
28737         plugin_data *p = p_d;
28738 -       
28739 +
28740         proxy_connection_close(srv, con->plugin_ctx[p->id]);
28741  
28742         return HANDLER_GO_ON;
28743 @@ -1276,11 +1269,11 @@
28744                 size_t i, n, k;
28745                 for (i = 0; i < srv->config_context->used; i++) {
28746                         plugin_config *s = p->config_storage[i];
28747 -                       
28748 -                       if (!s) continue; 
28749 +
28750 +                       if (!s) continue;
28751  
28752                         /* get the extensions for all configs */
28753 -                       
28754 +
28755                         for (k = 0; k < s->extensions->used; k++) {
28756                                 data_array *extension = (data_array *)s->extensions->data[k];
28757  
28758 @@ -1290,8 +1283,8 @@
28759  
28760                                         if (!host->is_disabled ||
28761                                             srv->cur_ts - host->disable_ts < 5) continue;
28762 -                       
28763 -                                       log_error_write(srv, __FILE__, __LINE__,  "sbd", 
28764 +
28765 +                                       log_error_write(srv, __FILE__, __LINE__,  "sbd",
28766                                                         "proxy - re-enabled:",
28767                                                         host->host, host->port);
28768  
28769 @@ -1317,8 +1310,8 @@
28770         p->handle_uri_clean        = mod_proxy_check_extension;
28771         p->handle_subrequest       = mod_proxy_handle_subrequest;
28772         p->handle_trigger          = mod_proxy_trigger;
28773 -       
28774 +
28775         p->data         = NULL;
28776 -       
28777 +
28778         return 0;
28779  }
28780 --- ../lighttpd-1.4.11/src/mod_proxy_core.c     1970-01-01 03:00:00.000000000 +0300
28781 +++ lighttpd-1.4.12/src/mod_proxy_core.c        2006-07-18 17:34:32.000000000 +0300
28782 @@ -0,0 +1,1709 @@
28783 +#include <string.h>
28784 +#include <stdlib.h>
28785 +#include <fcntl.h>
28786 +#include <errno.h>
28787 +#include <ctype.h>
28788 +
28789 +#include "buffer.h"
28790 +#include "array.h"
28791 +#include "log.h"
28792 +
28793 +#include "base.h"
28794 +#include "plugin.h"
28795 +#include "joblist.h"
28796 +#include "sys-files.h"
28797 +#include "inet_ntop_cache.h"
28798 +#include "http_resp.h"
28799 +#include "http_chunk.h"
28800 +#include "crc32.h"
28801 +
28802 +#include "mod_proxy_core_pool.h"       
28803 +#include "mod_proxy_core_backend.h"
28804 +#include "mod_proxy_core_backlog.h"
28805 +#include "mod_proxy_core_rewrites.h"
28806 +
28807 +#define CONFIG_PROXY_CORE_REWRITE_REQUEST "proxy-core.rewrite-request"
28808 +#define CONFIG_PROXY_CORE_REWRITE_RESPONSE "proxy-core.rewrite-response"
28809 +
28810 +typedef enum {
28811 +       PROXY_PROTOCOL_UNSET,
28812 +       PROXY_PROTOCOL_HTTP,
28813 +       PROXY_PROTOCOL_HTTPS,
28814 +       PROXY_PROTOCOL_FASTCGI,
28815 +       PROXY_PROTOCOL_SCGI
28816 +} proxy_protocol_t;
28817 +
28818 +typedef struct {
28819 +       proxy_backends *backends;
28820 +
28821 +       proxy_backlog *backlog;
28822 +
28823 +       proxy_rewrites *request_rewrites;
28824 +       proxy_rewrites *response_rewrites;
28825 +
28826 +       int debug;
28827 +
28828 +       proxy_balance_t balancer;
28829 +       proxy_protocol_t protocol;
28830 +} plugin_config;
28831 +
28832 +typedef struct {
28833 +       PLUGIN_DATA;
28834 +
28835 +       http_resp *resp;
28836 +
28837 +       array *possible_balancers;
28838 +       array *possible_protocols;
28839 +
28840 +       /* for parsing only */
28841 +       array *backends_arr;
28842 +       buffer *protocol_buf;
28843 +       buffer *balance_buf;
28844 +
28845 +       buffer *replace_buf;
28846 +
28847 +       plugin_config **config_storage;
28848 +
28849 +       plugin_config conf;
28850 +} plugin_data;
28851 +
28852 +int array_insert_int(array *a, const char *key, int val) {
28853 +       data_integer *di;
28854 +
28855 +       if (NULL == (di = (data_integer *)array_get_unused_element(a, TYPE_INTEGER))) {
28856 +               di = data_integer_init();
28857 +       }
28858 +
28859 +       buffer_copy_string(di->key, key);
28860 +       di->value = val;
28861 +       array_insert_unique(a, (data_unset *)di);
28862 +
28863 +       return 0;
28864 +}
28865 +
28866 +INIT_FUNC(mod_proxy_core_init) {
28867 +       plugin_data *p;
28868 +
28869 +       p = calloc(1, sizeof(*p));
28870 +
28871 +       /* create some backends as long as we don't have the config-parser */
28872 +
28873 +       p->possible_balancers = array_init();
28874 +       array_insert_int(p->possible_balancers, "fair", PROXY_BALANCE_FAIR);
28875 +       array_insert_int(p->possible_balancers, "hash", PROXY_BALANCE_RR);
28876 +       array_insert_int(p->possible_balancers, "round-robin", PROXY_BALANCE_HASH);
28877 +
28878 +       p->possible_protocols = array_init();
28879 +       array_insert_int(p->possible_protocols, "http", PROXY_PROTOCOL_HTTP);
28880 +       array_insert_int(p->possible_protocols, "fastcgi", PROXY_PROTOCOL_FASTCGI);
28881 +       array_insert_int(p->possible_protocols, "scgi", PROXY_PROTOCOL_SCGI);
28882 +       array_insert_int(p->possible_protocols, "https", PROXY_PROTOCOL_HTTPS);
28883 +
28884 +       p->balance_buf = buffer_init();
28885 +       p->protocol_buf = buffer_init();
28886 +       p->replace_buf = buffer_init();
28887 +       p->backends_arr = array_init();
28888 +
28889 +       p->resp = http_response_init();
28890 +
28891 +       return p;
28892 +}
28893 +
28894 +FREE_FUNC(mod_proxy_core_free) {
28895 +       plugin_data *p = p_d;
28896 +
28897 +       if (!p) return HANDLER_GO_ON;
28898 +
28899 +       if (p->config_storage) {
28900 +               size_t i;
28901 +               for (i = 0; i < srv->config_context->used; i++) {
28902 +                       plugin_config *s = p->config_storage[i];
28903 +
28904 +                       if (!s) continue;
28905 +
28906 +                       proxy_backends_free(s->backends);
28907 +                       proxy_backlog_free(s->backlog);
28908 +
28909 +
28910 +                       free(s);
28911 +               }
28912 +               free(p->config_storage);
28913 +       }
28914 +
28915 +       array_free(p->possible_protocols);
28916 +       array_free(p->possible_balancers);
28917 +       array_free(p->backends_arr);
28918 +
28919 +       buffer_free(p->balance_buf);
28920 +       buffer_free(p->protocol_buf);
28921 +       buffer_free(p->replace_buf);
28922 +       
28923 +       http_response_free(p->resp);
28924 +
28925 +       free(p);
28926 +
28927 +       return HANDLER_GO_ON;
28928 +}
28929 +
28930 +static handler_t mod_proxy_core_config_parse_rewrites(proxy_rewrites *dest, array *src, const char *config_key) {
28931 +       data_unset *du;
28932 +       size_t j;
28933 +
28934 +       if (NULL != (du = array_get_element(src, config_key))) {
28935 +               data_array *keys = (data_array *)du;
28936 +
28937 +               if (keys->type != TYPE_ARRAY) {
28938 +                       ERROR("%s = <...>", 
28939 +                               config_key);
28940 +
28941 +                       return HANDLER_ERROR;
28942 +               }
28943 +
28944 +               /*
28945 +                * proxy-core.rewrite-request = (
28946 +                *   "_uri" => ( ... ) 
28947 +                * )
28948 +                */
28949 +
28950 +               for (j = 0; j < keys->value->used; j++) {
28951 +                       size_t k;
28952 +                       data_array *headers = (data_array *)keys->value->data[j];
28953 +
28954 +                       /* keys->key should be "_uri" and the value a array of rewrite */
28955 +                       if (headers->type != TYPE_ARRAY) {
28956 +                               ERROR("%s = ( %s => <...> ) has to a array", 
28957 +                                       config_key,
28958 +                                       BUF_STR(headers->key));
28959 +
28960 +                               return HANDLER_ERROR;
28961 +                       }
28962 +
28963 +                       TRACE("%s: header-field: %s", config_key, BUF_STR(headers->key));
28964 +
28965 +                       if (headers->value->used > 1) {
28966 +                               ERROR("%s = ( %s => <...> ) has to a array with only one element", 
28967 +                                       config_key,
28968 +                                       BUF_STR(headers->key));
28969 +
28970 +                               return HANDLER_ERROR;
28971 +
28972 +                       }
28973 +
28974 +                       for (k = 0; k < headers->value->used; k++) {
28975 +                               data_string *rewrites = (data_string *)headers->value->data[k];
28976 +                               proxy_rewrite *rw;
28977 +
28978 +                               /* keys->key should be "_uri" and the value a array of rewrite */
28979 +                               if (rewrites->type != TYPE_STRING) {
28980 +                                       ERROR("%s = ( \"%s\" => ( \"%s\" => <value> ) ) has to a string", 
28981 +                                               config_key,
28982 +                                               BUF_STR(headers->key),
28983 +                                               BUF_STR(rewrites->key));
28984 +
28985 +                                       return HANDLER_ERROR;
28986 +                               }
28987 +                       
28988 +                               TRACE("%s: rewrites-field: %s -> %s", 
28989 +                                               config_key, 
28990 +                                               BUF_STR(headers->key), 
28991 +                                               BUF_STR(rewrites->key));
28992 +
28993 +                               rw = proxy_rewrite_init();
28994 +
28995 +                               if (0 != proxy_rewrite_set_regex(rw, rewrites->key)) {
28996 +                                       return HANDLER_ERROR;
28997 +                               }
28998 +                               buffer_copy_string_buffer(rw->replace, rewrites->value);
28999 +                               buffer_copy_string_buffer(rw->match, rewrites->key);
29000 +                               buffer_copy_string_buffer(rw->header, headers->key);
29001 +
29002 +                               proxy_rewrites_add(dest, rw);
29003 +                       }
29004 +               }
29005 +       }
29006 +
29007 +       return HANDLER_GO_ON;
29008 +}
29009 +
29010 +
29011 +SETDEFAULTS_FUNC(mod_proxy_core_set_defaults) {
29012 +       plugin_data *p = p_d;
29013 +       size_t i, j;
29014 +
29015 +       config_values_t cv[] = {
29016 +               { "proxy-core.backends",       NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
29017 +               { "proxy-core.debug",          NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
29018 +               { "proxy-core.balancer",       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 2 */
29019 +               { "proxy-core.protocol",       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 3 */
29020 +               { CONFIG_PROXY_CORE_REWRITE_REQUEST, NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
29021 +               { CONFIG_PROXY_CORE_REWRITE_RESPONSE, NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },/* 5 */
29022 +               { NULL,                        NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
29023 +       };
29024 +
29025 +       p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
29026 +
29027 +       for (i = 0; i < srv->config_context->used; i++) {
29028 +               plugin_config *s;
29029 +               array *ca;
29030 +               proxy_backend *backend;
29031 +
29032 +               array_reset(p->backends_arr);
29033 +               buffer_reset(p->balance_buf);
29034 +               buffer_reset(p->protocol_buf);
29035 +
29036 +               s = malloc(sizeof(plugin_config));
29037 +               s->debug     = 0;
29038 +               s->balancer  = PROXY_BALANCE_UNSET;
29039 +               s->protocol  = PROXY_PROTOCOL_UNSET;
29040 +               s->backends  = proxy_backends_init();
29041 +               s->backlog   = proxy_backlog_init();
29042 +               s->response_rewrites   = proxy_rewrites_init();
29043 +               s->request_rewrites   = proxy_rewrites_init();
29044 +
29045 +               cv[0].destination = p->backends_arr;
29046 +               cv[1].destination = &(s->debug);
29047 +               cv[2].destination = p->balance_buf; /* parse into a constant */
29048 +               cv[3].destination = p->protocol_buf; /* parse into a constant */
29049 +
29050 +               buffer_reset(p->balance_buf);
29051 +
29052 +               p->config_storage[i] = s;
29053 +               ca = ((data_config *)srv->config_context->data[i])->value;
29054 +
29055 +               if (0 != config_insert_values_global(srv, ca, cv)) {
29056 +                       return HANDLER_ERROR;
29057 +               }
29058 +
29059 +               if (!buffer_is_empty(p->balance_buf)) {
29060 +                       data_integer *di;
29061 +                       
29062 +                       if (NULL == (di = (data_integer *)array_get_element(p->possible_balancers, BUF_STR(p->balance_buf)))) {
29063 +                               ERROR("proxy.balance has to be on of 'fair', 'round-robin', 'hash', got %s", BUF_STR(p->balance_buf));
29064 +
29065 +                               return HANDLER_ERROR;
29066 +                       }
29067 +
29068 +                       s->balancer = di->value;
29069 +               }
29070 +
29071 +               if (!buffer_is_empty(p->protocol_buf)) {
29072 +                       data_integer *di;
29073 +                       
29074 +                       if (NULL == (di = (data_integer *)array_get_element(p->possible_protocols, BUF_STR(p->protocol_buf)))) {
29075 +                               ERROR("proxy.balance has to be on of 'fair', 'round-robin', 'hash', got %s", BUF_STR(p->protocol_buf));
29076 +
29077 +                               return HANDLER_ERROR;
29078 +                       }
29079 +
29080 +                       s->protocol = di->value;
29081 +               }
29082 +
29083 +               if (p->backends_arr->used) {
29084 +                       backend = proxy_backend_init();
29085 +
29086 +                       /* check if the backends have a valid host-name */
29087 +                       for (j = 0; j < p->backends_arr->used; j++) {
29088 +                               data_string *ds = (data_string *)p->backends_arr->data[j];
29089 +
29090 +                               /* the values should be ips or hostnames */
29091 +                               if (0 != proxy_address_pool_add_string(backend->address_pool, ds->value)) {
29092 +                                       return HANDLER_ERROR;
29093 +                               }
29094 +                       }
29095 +
29096 +                       proxy_backends_add(s->backends, backend);
29097 +               }
29098 +
29099 +               if (HANDLER_GO_ON != mod_proxy_core_config_parse_rewrites(s->request_rewrites, ca, CONFIG_PROXY_CORE_REWRITE_REQUEST)) {
29100 +                       return HANDLER_ERROR;
29101 +               }
29102 +               
29103 +               if (HANDLER_GO_ON != mod_proxy_core_config_parse_rewrites(s->response_rewrites, ca, CONFIG_PROXY_CORE_REWRITE_RESPONSE)) {
29104 +                       return HANDLER_ERROR;
29105 +               }
29106 +       }
29107 +
29108 +       return HANDLER_GO_ON;
29109 +}
29110 +
29111 +
29112 +typedef enum {
29113 +       PROXY_STATE_UNSET,
29114 +       PROXY_STATE_CONNECTING,
29115 +       PROXY_STATE_CONNECTED,
29116 +       PROXY_STATE_WRITE_REQUEST_HEADER,
29117 +       PROXY_STATE_WRITE_REQUEST_BODY,
29118 +       PROXY_STATE_READ_RESPONSE_HEADER,
29119 +       PROXY_STATE_READ_RESPONSE_BODY
29120 +} proxy_state_t;
29121 +
29122 +typedef struct {
29123 +       proxy_connection *proxy_con;
29124 +       proxy_backend *proxy_backend;
29125 +
29126 +       connection *remote_con;
29127 +
29128 +       array *request_headers;
29129 +
29130 +       int is_chunked;
29131 +       
29132 +       /**
29133 +        * chunkqueues
29134 +        * - the encoded_rb is the raw network stuff
29135 +        * - the rb is filtered through the stream decoder
29136 +        *
29137 +        * - wb is the normal bytes stream
29138 +        * - encoded_wb is encoded for the network by the stream encoder
29139 +        */
29140 +       chunkqueue *recv;
29141 +       chunkqueue *recv_raw;
29142 +       chunkqueue *send_raw;
29143 +       chunkqueue *send;
29144 +       
29145 +       off_t bytes_read;
29146 +       off_t content_length;
29147 +
29148 +       proxy_state_t state;
29149 +} proxy_session;
29150 +
29151 +proxy_session *proxy_session_init(void) {
29152 +       proxy_session *sess;
29153 +
29154 +       sess = calloc(1, sizeof(*sess));
29155 +
29156 +       sess->state = PROXY_STATE_UNSET;
29157 +       sess->request_headers = array_init();
29158 +
29159 +       sess->recv = chunkqueue_init();
29160 +       sess->recv_raw = chunkqueue_init();
29161 +       sess->send_raw = chunkqueue_init();
29162 +       sess->send = chunkqueue_init();
29163 +
29164 +       sess->is_chunked = 0;
29165 +
29166 +       return sess;
29167 +}
29168 +
29169 +void proxy_session_free(proxy_session *sess) {
29170 +       if (!sess) return;
29171 +
29172 +       array_free(sess->request_headers);
29173 +
29174 +       chunkqueue_free(sess->recv);
29175 +       chunkqueue_free(sess->recv_raw);
29176 +       chunkqueue_free(sess->send_raw);
29177 +       chunkqueue_free(sess->send);
29178 +
29179 +       free(sess);
29180 +}
29181 +
29182 +handler_t proxy_connection_connect(proxy_connection *con) {
29183 +       int fd;
29184 +       
29185 +       if (-1 == (fd = socket(con->address->addr.plain.sa_family, SOCK_STREAM, 0))) {
29186 +       }
29187 +
29188 +       fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
29189 +
29190 +       con->sock->fd = fd;
29191 +       con->sock->fde_ndx = -1;
29192 +       con->sock->type = IOSOCKET_TYPE_SOCKET;
29193 +
29194 +       if (-1 == connect(fd, &(con->address->addr.plain), sizeof(con->address->addr))) {
29195 +               switch(errno) {
29196 +               case EINPROGRESS:
29197 +               case EALREADY:
29198 +               case EINTR:
29199 +                       return HANDLER_WAIT_FOR_EVENT;
29200 +               default:
29201 +                       close(fd);
29202 +                       con->sock->fd = -1;
29203 +
29204 +                       return HANDLER_ERROR;
29205 +               }
29206 +       }
29207 +
29208 +       return HANDLER_GO_ON;
29209 +}
29210 +
29211 +/**
29212 + * event-handler for idling connections
29213 + *
29214 + * unused (idling) keep-alive connections are not bound to a session
29215 + * and need their own event-handler 
29216 + *
29217 + * if the connection closes (we get a FDEVENT_IN), close our side too and 
29218 + * let the trigger-func handle the cleanup
29219 + *
29220 + * @see proxy_trigger
29221 + */
29222 +
29223 +
29224 +static handler_t proxy_handle_fdevent_idle(void *s, void *ctx, int revents) {
29225 +       server      *srv  = (server *)s;
29226 +       proxy_connection *proxy_con = ctx;
29227 +
29228 +       if (revents & FDEVENT_IN) {
29229 +               switch (proxy_con->state) {
29230 +               case PROXY_CONNECTION_STATE_IDLE:
29231 +                       proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29232 +
29233 +                       /* close + unregister have to be in the same call,
29234 +                        * otherwise we get a events for a re-opened fd */
29235 +
29236 +                       fdevent_event_del(srv->ev, proxy_con->sock);
29237 +
29238 +                       break;
29239 +               case PROXY_CONNECTION_STATE_CLOSED:
29240 +                       /* poll() is state-driven, we will get events as long as it isn't disabled
29241 +                        * the close() above should disable the events too */
29242 +                       ERROR("%s", "hurry up buddy, I got another event for a closed idle-connection");
29243 +                       break;
29244 +               default:
29245 +                       ERROR("invalid connection state: %d, should be idle", proxy_con->state);
29246 +                       break;
29247 +               }
29248 +       }
29249 +
29250 +       return HANDLER_GO_ON;
29251 +}
29252 +
29253 +void chunkqueue_skip(chunkqueue *cq, off_t skip) {
29254 +       chunk *c;
29255 +
29256 +       for (c = cq->first; c && skip; c = c->next) {
29257 +               if (skip > c->mem->used - c->offset - 1) {
29258 +                       skip -= c->mem->used - c->offset - 1;
29259 +               } else {
29260 +                       c->offset += skip;
29261 +                       skip = 0;
29262 +               }
29263 +       }
29264 +
29265 +       return;
29266 +}
29267 +
29268 +int proxy_http_stream_decoder(server *srv, proxy_session *sess, chunkqueue *raw, chunkqueue *decoded) {
29269 +       chunk *c;
29270 +
29271 +       if (sess->is_chunked) {
29272 +               do {
29273 +                       /* the start should always be a chunk-length */
29274 +                       off_t chunk_len = 0;
29275 +                       char *err = NULL;
29276 +                       int chunklen_strlen = 0;
29277 +                       char ch;
29278 +                       off_t we_have = 0, we_need = 0;
29279 +
29280 +                       c = raw->first;
29281 +
29282 +                       chunk_len = strtol(BUF_STR(c->mem) + c->offset, &err, 16);
29283 +                       if (!(*err == ' ' || *err == '\r' || *err == ';')) {
29284 +                               if (*err == '\0') {
29285 +                                       /* we just need more data */
29286 +                                       return 0;
29287 +                               }
29288 +                               return -1;
29289 +                       }
29290 +
29291 +                       if (chunk_len < 0) {
29292 +                               ERROR("chunk_len is negative: %Ld", chunk_len);
29293 +                               return -1;
29294 +                       }
29295 +
29296 +                       chunklen_strlen = err - (BUF_STR(c->mem) + c->offset);
29297 +                       chunklen_strlen++; /* skip the err-char */ 
29298 +                       
29299 +                       do {
29300 +                               ch = BUF_STR(c->mem)[c->offset + chunklen_strlen];
29301 +       
29302 +                               switch (ch) {
29303 +                               case '\n':
29304 +                               case '\0':
29305 +                                       /* bingo, chunk-header is finished */
29306 +                                       break;
29307 +                               default:
29308 +                                       break;
29309 +                               }
29310 +                               chunklen_strlen++;
29311 +                       } while (ch != '\n' && c != '\0');
29312 +
29313 +                       if (ch != '\n') {
29314 +                               ERROR("%s", "missing the CRLF");
29315 +                               return 0;
29316 +                       }
29317 +
29318 +                       we_need = chunk_len + chunklen_strlen + 2;
29319 +                       /* do we have the full chunk ? */
29320 +                       for (c = raw->first; c; c = c->next) {
29321 +                               we_have += c->mem->used - 1 - c->offset;
29322 +
29323 +                               /* we have enough, jump out */
29324 +                               if (we_have > we_need) break;
29325 +                       }
29326 +
29327 +                       /* get more data */
29328 +                       if (we_have < we_need) {
29329 +                               return 0;
29330 +                       }
29331 +
29332 +                       /* skip the chunk-header */
29333 +                       chunkqueue_skip(raw, chunklen_strlen);
29334 +
29335 +                       /* final chunk */
29336 +                       if (chunk_len == 0) {
29337 +                               chunkqueue_skip(raw, 2);
29338 +
29339 +                               return 1;
29340 +                       }
29341 +
29342 +                       /* we have enough, copy the data */     
29343 +                       for (c = raw->first; c && chunk_len; c = c->next) {
29344 +                               off_t we_want = 0;
29345 +                               buffer *b = chunkqueue_get_append_buffer(decoded);
29346 +
29347 +                               we_want = chunk_len > (c->mem->used - c->offset - 1) ? c->mem->used - c->offset - 1: chunk_len;
29348 +
29349 +                               buffer_copy_string_len(b, c->mem->ptr + c->offset, we_want);
29350 +
29351 +                               c->offset += we_want;
29352 +                               chunk_len -= we_want;
29353 +                       }
29354 +
29355 +                       /* skip the \r\n */
29356 +                       chunkqueue_skip(raw, 2);
29357 +
29358 +                       /* we are done, give the connection to someone else */
29359 +                       chunkqueue_remove_finished_chunks(raw);
29360 +               } while (1);
29361 +       } else {
29362 +               /* no chunked encoding, ok, perhaps a content-length ? */
29363 +
29364 +               chunkqueue_remove_finished_chunks(raw);
29365 +               for (c = raw->first; c; c = c->next) {
29366 +                       buffer *b;
29367 +
29368 +                       if (c->mem->used == 0) continue;
29369 +                      
29370 +                       b = chunkqueue_get_append_buffer(decoded);
29371 +
29372 +                       sess->bytes_read += c->mem->used - c->offset - 1;
29373 +
29374 +                       buffer_copy_string_len(b, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
29375 +
29376 +                       c->offset = c->mem->used - 1;
29377 +
29378 +                       if (sess->bytes_read == sess->content_length) {
29379 +                               break;
29380 +                       }
29381 +
29382 +               }
29383 +               if (sess->bytes_read == sess->content_length) {
29384 +                       return 1; /* finished */
29385 +               }
29386 +       }
29387 +
29388 +       return 0;
29389 +}
29390 +/* don't call any proxy functions directly */
29391 +static handler_t proxy_handle_fdevent(void *s, void *ctx, int revents) {
29392 +       server      *srv  = (server *)s;
29393 +       proxy_session *sess = ctx;
29394 +
29395 +       if (revents & FDEVENT_OUT) {
29396 +               switch (sess->state) {
29397 +               case PROXY_STATE_CONNECTING: /* delayed connect */
29398 +               case PROXY_STATE_WRITE_REQUEST_HEADER:
29399 +               case PROXY_STATE_WRITE_REQUEST_BODY:
29400 +                       /* we are still connection */
29401 +
29402 +                       joblist_append(srv, sess->remote_con);
29403 +                       break;
29404 +               default:
29405 +                       ERROR("oops, unexpected state for fdevent-out %d", sess->state);
29406 +                       break;
29407 +               }
29408 +       } else if (revents & FDEVENT_IN) {
29409 +               chunk *c;
29410 +
29411 +               switch (sess->state) {
29412 +               case PROXY_STATE_READ_RESPONSE_HEADER:
29413 +                       /* call our header parser */
29414 +                       joblist_append(srv, sess->remote_con);
29415 +                       break;
29416 +               case PROXY_STATE_READ_RESPONSE_BODY:
29417 +                       /* we should be in the WRITE state now, 
29418 +                        * just read in the content and forward it to the outgoing connection
29419 +                        * */
29420 +
29421 +                       chunkqueue_remove_finished_chunks(sess->recv_raw);
29422 +                       switch (srv->network_backend_read(srv, sess->remote_con, sess->proxy_con->sock, sess->recv_raw)) {
29423 +                       case NETWORK_STATUS_CONNECTION_CLOSE:
29424 +                               fdevent_event_del(srv->ev,sess->proxy_con->sock);
29425 +
29426 +                               /* the connection is gone
29427 +                                * make the connect */
29428 +                               sess->remote_con->file_finished = 1;
29429 +                               sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29430 +
29431 +                       case NETWORK_STATUS_SUCCESS:
29432 +                               /* read even more, do we have all the content */
29433 +
29434 +                               /* how much do we want to read ? */
29435 +                               
29436 +                               /* call stream-decoder (HTTP-chunked, FastCGI, ... ) */
29437 +
29438 +                               switch (proxy_http_stream_decoder(srv, sess, sess->recv_raw, sess->recv)) {
29439 +                               case 0:
29440 +                                       /* need more */
29441 +                                       break;
29442 +                               case -1:
29443 +                                       /* error */
29444 +                                       break;
29445 +                               case 1:
29446 +                                       /* we are done */
29447 +                                       sess->remote_con->file_finished = 1;
29448 +
29449 +                                       break;
29450 +                               }
29451 +                               chunkqueue_remove_finished_chunks(sess->recv_raw);
29452 +
29453 +                               /* copy the content to the next cq */
29454 +                               for (c = sess->recv->first; c; c = c->next) {
29455 +                                       if (c->mem->used == 0) continue;
29456 +
29457 +                                       http_chunk_append_mem(srv, sess->remote_con, c->mem->ptr + c->offset, c->mem->used - c->offset);
29458 +       
29459 +                                       c->offset = c->mem->used - 1;
29460 +
29461 +                               }
29462 +                               chunkqueue_remove_finished_chunks(sess->recv);
29463 +
29464 +                               if (sess->remote_con->file_finished) {
29465 +                                       /* send final HTTP-Chunk packet */
29466 +                                       http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
29467 +                               }
29468 +                               
29469 +                               break;
29470 +                       default:
29471 +                               ERROR("%s", "oops, we failed to read");
29472 +                               break;
29473 +                       }
29474 +
29475 +                       joblist_append(srv, sess->remote_con);
29476 +                       break;
29477 +               default:
29478 +                       ERROR("oops, unexpected state for fdevent-in %d", sess->state);
29479 +                       break;
29480 +               }
29481 +       }
29482 +
29483 +       if (revents & FDEVENT_HUP) {
29484 +               /* someone closed our connection */
29485 +               switch (sess->state) {
29486 +               case PROXY_STATE_CONNECTING:
29487 +                       /* let the getsockopt() catch this */
29488 +                       joblist_append(srv, sess->remote_con);
29489 +                       break;
29490 +               default:
29491 +                       ERROR("oops, unexpected state for fdevent-hup %d", sess->state);
29492 +                       break;
29493 +               }
29494 +       }
29495 +
29496 +       return HANDLER_GO_ON;
29497 +}
29498 +
29499 +int pcre_replace(pcre *match, buffer *replace, buffer *match_buf, buffer *result) {
29500 +       const char *pattern = replace->ptr;
29501 +       size_t pattern_len = replace->used - 1;
29502 +
29503 +# define N 10
29504 +       int ovec[N * 3];
29505 +       int n;
29506 +
29507 +       if ((n = pcre_exec(match, NULL, match_buf->ptr, match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
29508 +               if (n != PCRE_ERROR_NOMATCH) {
29509 +                       return n;
29510 +               }
29511 +       } else {
29512 +               const char **list;
29513 +               size_t start, end;
29514 +               size_t k;
29515 +
29516 +               /* it matched */
29517 +               pcre_get_substring_list(match_buf->ptr, ovec, n, &list);
29518 +
29519 +               /* search for $[0-9] */
29520 +
29521 +               buffer_reset(result);
29522 +
29523 +               start = 0; end = pattern_len;
29524 +               for (k = 0; k < pattern_len; k++) {
29525 +                       if ((pattern[k] == '$') &&
29526 +                           isdigit((unsigned char)pattern[k + 1])) {
29527 +                               /* got one */
29528 +
29529 +                               size_t num = pattern[k + 1] - '0';
29530 +
29531 +                               end = k;
29532 +
29533 +                               buffer_append_string_len(result, pattern + start, end - start);
29534 +
29535 +                               /* n is always > 0 */
29536 +                               if (num < (size_t)n) {
29537 +                                       buffer_append_string(result, list[num]);
29538 +                               }
29539 +
29540 +                               k++;
29541 +                               start = k + 1;
29542 +                       }
29543 +               }
29544 +
29545 +               buffer_append_string_len(result, pattern + start, pattern_len - start);
29546 +
29547 +               pcre_free(list);
29548 +       }
29549 +
29550 +       return n;
29551 +}
29552 +
29553 +/**
29554 + * generate a HTTP/1.1 proxy request from the set of request-headers
29555 + *
29556 + * TODO: this is HTTP-proxy specific and will be moved moved into a separate backed
29557 + *
29558 + */
29559 +int proxy_get_request_chunk(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq) {
29560 +       buffer *b;
29561 +       size_t i;
29562 +       
29563 +       b = chunkqueue_get_append_buffer(cq);
29564 +
29565 +       /* request line */
29566 +       buffer_copy_string(b, get_http_method_name(con->request.http_method));
29567 +       BUFFER_APPEND_STRING_CONST(b, " ");
29568 +
29569 +       /* check if we want to rewrite the uri */
29570 +
29571 +       for (i = 0; i < p->conf.request_rewrites->used; i++) {
29572 +               proxy_rewrite *rw = p->conf.request_rewrites->ptr[i];
29573 +
29574 +               if (buffer_is_equal_string(rw->header, CONST_STR_LEN("_uri"))) {
29575 +                       int ret;
29576 +
29577 +                       if ((ret = pcre_replace(rw->regex, rw->replace, con->request.uri, p->replace_buf)) < 0) {
29578 +                               switch (ret) {
29579 +                               case PCRE_ERROR_NOMATCH:
29580 +                                       /* hmm, ok. no problem */
29581 +                                       buffer_append_string_buffer(b, con->request.uri);
29582 +                                       break;
29583 +                               default:
29584 +                                       TRACE("oops, pcre_replace failed with: %d", ret);
29585 +                                       break;
29586 +                               }
29587 +                       } else {
29588 +                               buffer_append_string_buffer(b, p->replace_buf);
29589 +                       }
29590 +
29591 +                       break;
29592 +               }
29593 +       }
29594 +
29595 +       if (i == p->conf.request_rewrites->used) {
29596 +               /* not found */
29597 +               buffer_append_string_buffer(b, con->request.uri);
29598 +       }
29599 +
29600 +       BUFFER_APPEND_STRING_CONST(b, " HTTP/1.1\r\n");
29601 +
29602 +       for (i = 0; i < sess->request_headers->used; i++) {
29603 +               data_string *ds;
29604 +
29605 +               ds = (data_string *)sess->request_headers->data[i];
29606 +
29607 +               buffer_append_string_buffer(b, ds->key);
29608 +               BUFFER_APPEND_STRING_CONST(b, ": ");
29609 +               buffer_append_string_buffer(b, ds->value);
29610 +               BUFFER_APPEND_STRING_CONST(b, "\r\n");
29611 +       }
29612 +
29613 +       BUFFER_APPEND_STRING_CONST(b, "\r\n");
29614 +       
29615 +       return 0;
29616 +}
29617 +
29618 +void proxy_set_header(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
29619 +       data_string *ds_dst;
29620 +
29621 +       if (NULL != (ds_dst = (data_string *)array_get_element(hdrs, key))) {
29622 +               buffer_copy_string_len(ds_dst->value, value, val_len);
29623 +               return;
29624 +       }
29625 +
29626 +       if (NULL == (ds_dst = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
29627 +               ds_dst = data_string_init();
29628 +       }
29629 +
29630 +       buffer_copy_string_len(ds_dst->key, key, key_len);
29631 +       buffer_copy_string_len(ds_dst->value, value, val_len);
29632 +       array_insert_unique(hdrs, (data_unset *)ds_dst);
29633 +}
29634 +
29635 +void proxy_append_header(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
29636 +       data_string *ds_dst;
29637 +
29638 +       if (NULL == (ds_dst = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
29639 +               ds_dst = data_string_init();
29640 +       }
29641 +
29642 +       buffer_copy_string_len(ds_dst->key, key, key_len);
29643 +       buffer_append_string_len(ds_dst->value, value, val_len);
29644 +       array_insert_unique(hdrs, (data_unset *)ds_dst);
29645 +}
29646 +
29647 +
29648 +/**
29649 + * build the request-header array and call the backend specific request formater
29650 + * to fill the chunkqueue
29651 + */
29652 +int proxy_get_request_header(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
29653 +       /* request line */
29654 +       const char *remote_ip;
29655 +       size_t i;
29656 +
29657 +       remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
29658 +       proxy_append_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-For"), remote_ip, strlen(remote_ip));
29659 +
29660 +       /* http_host is NOT is just a pointer to a buffer
29661 +        * which is NULL if it is not set */
29662 +       if (con->request.http_host &&
29663 +           !buffer_is_empty(con->request.http_host)) {
29664 +               proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Host"), CONST_BUF_LEN(con->request.http_host));
29665 +       }
29666 +       if (con->conf.is_ssl) {
29667 +               proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-Proto"), CONST_STR_LEN("https"));
29668 +       } else {
29669 +               proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-Proto"), CONST_STR_LEN("http"));
29670 +       }
29671 +
29672 +       /* request header */
29673 +       for (i = 0; i < con->request.headers->used; i++) {
29674 +               data_string *ds;
29675 +               size_t k;
29676 +
29677 +               ds = (data_string *)con->request.headers->data[i];
29678 +
29679 +               if (buffer_is_empty(ds->value) || buffer_is_empty(ds->key)) continue;
29680 +
29681 +               if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
29682 +               if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Keep-Alive"))) continue;
29683 +
29684 +               for (k = 0; k < p->conf.request_rewrites->used; k++) {
29685 +                       proxy_rewrite *rw = p->conf.request_rewrites->ptr[k];
29686 +
29687 +                       if (buffer_is_equal(rw->header, ds->key)) {
29688 +                               int ret;
29689 +
29690 +                               if ((ret = pcre_replace(rw->regex, rw->replace, ds->value, p->replace_buf)) < 0) {
29691 +                                       switch (ret) {
29692 +                                       case PCRE_ERROR_NOMATCH:
29693 +                                               /* hmm, ok. no problem */
29694 +                                               proxy_set_header(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
29695 +                                               break;
29696 +                                       default:
29697 +                                               TRACE("oops, pcre_replace failed with: %d", ret);
29698 +                                               break;
29699 +                                       }
29700 +                               } else {
29701 +                                       proxy_set_header(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(p->replace_buf));
29702 +                               }
29703 +
29704 +                               break;
29705 +                       }
29706 +               }
29707 +
29708 +               if (k == p->conf.request_rewrites->used) {
29709 +                       proxy_set_header(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
29710 +               }
29711 +       }
29712 +
29713 +       proxy_get_request_chunk(srv, con, p, sess, sess->send_raw);
29714 +
29715 +       return 0;
29716 +}
29717 +
29718 +/**
29719 + * parse the response header
29720 + *
29721 + * NOTE: this can be used by all backends as they all send a HTTP-Response a clean block
29722 + * - fastcgi needs some decoding for the protocol
29723 + */
29724 +parse_status_t proxy_parse_response_header(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq) {
29725 +       int have_content_length = 0;
29726 +       size_t i;
29727 +
29728 +       http_response_reset(p->resp);
29729 +       
29730 +       switch (http_response_parse_cq(cq, p->resp)) {
29731 +       case PARSE_ERROR:
29732 +               /* parsing failed */
29733 +
29734 +               return PARSE_ERROR;
29735 +       case PARSE_NEED_MORE:
29736 +               return PARSE_NEED_MORE;
29737 +       case PARSE_SUCCESS:
29738 +               con->http_status = p->resp->status;
29739 +
29740 +               chunkqueue_remove_finished_chunks(cq);
29741 +
29742 +               sess->content_length = -1;
29743 +
29744 +               /* copy the http-headers */
29745 +               for (i = 0; i < p->resp->headers->used; i++) {
29746 +                       const char *ign[] = { "Status", "Connection", NULL };
29747 +                       size_t j, k;
29748 +                       data_string *ds;
29749 +
29750 +                       data_string *header = (data_string *)p->resp->headers->data[i];
29751 +
29752 +                       /* some headers are ignored by default */
29753 +                       for (j = 0; ign[j]; j++) {
29754 +                               if (0 == strcasecmp(ign[j], header->key->ptr)) break;
29755 +                       }
29756 +                       if (ign[j]) continue;
29757 +
29758 +                       if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
29759 +                               /* CGI/1.1 rev 03 - 7.2.1.2 */
29760 +                               if (con->http_status == 0) con->http_status = 302;
29761 +                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
29762 +                               have_content_length = 1;
29763 +
29764 +                               sess->content_length = strtol(header->value->ptr, NULL, 10);
29765 +
29766 +                               if (sess->content_length < 0) {
29767 +                                       return PARSE_ERROR;
29768 +                               }
29769 +                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Transfer-Encoding"))) {
29770 +                               if (strstr(header->value->ptr, "chunked")) {
29771 +                                       sess->is_chunked = 1;
29772 +                               }
29773 +                               /* ignore the header */
29774 +                               continue;
29775 +                       }
29776 +                       
29777 +                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
29778 +                               ds = data_response_init();
29779 +                       }
29780 +
29781 +
29782 +                       buffer_copy_string_buffer(ds->key, header->key);
29783 +
29784 +                       for (k = 0; k < p->conf.response_rewrites->used; k++) {
29785 +                               proxy_rewrite *rw = p->conf.response_rewrites->ptr[k];
29786 +
29787 +                               if (buffer_is_equal(rw->header, header->key)) {
29788 +                                       int ret;
29789 +       
29790 +                                       if ((ret = pcre_replace(rw->regex, rw->replace, header->value, p->replace_buf)) < 0) {
29791 +                                               switch (ret) {
29792 +                                               case PCRE_ERROR_NOMATCH:
29793 +                                                       /* hmm, ok. no problem */
29794 +                                                       buffer_append_string_buffer(ds->value, header->value);
29795 +                                                       break;
29796 +                                               default:
29797 +                                                       TRACE("oops, pcre_replace failed with: %d", ret);
29798 +                                                       break;
29799 +                                               }
29800 +                                       } else {
29801 +                                               buffer_append_string_buffer(ds->value, p->replace_buf);
29802 +                                       }
29803 +
29804 +                                       break;
29805 +                               }
29806 +                       }
29807 +
29808 +                       if (k == p->conf.response_rewrites->used) {
29809 +                               buffer_copy_string_buffer(ds->value, header->value);
29810 +                       }
29811 +
29812 +                       array_insert_unique(con->response.headers, (data_unset *)ds);
29813 +               }
29814 +
29815 +               /* does the client allow us to send chunked encoding ? */
29816 +               if (con->request.http_version == HTTP_VERSION_1_1 &&
29817 +                   !have_content_length) {
29818 +                       con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
29819 +               }
29820 +
29821 +               break;
29822 +       }
29823 +
29824 +       return PARSE_SUCCESS; /* we have a full header */
29825 +}
29826 +
29827 +/* we are event-driven
29828 + * 
29829 + * the first entry is connect() call, if the doesn't need a event 
29830 + *
29831 + * a bit boring
29832 + * - connect (+ delayed connect)
29833 + * - write header + content
29834 + * - read header + content
29835 + *
29836 + * as soon as have read the response header we switch con->file_started and return HANDLER_GO_ON to
29837 + * tell the core we are ready to stream out the content.
29838 + *  */
29839 +handler_t proxy_state_engine(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
29840 +       /* do we have a connection ? */
29841 +
29842 +       if (sess->state == PROXY_STATE_UNSET) {
29843 +               /* we are not started yet */
29844 +               switch(proxy_connection_connect(sess->proxy_con)) {
29845 +               case HANDLER_WAIT_FOR_EVENT:
29846 +                       /* waiting on the connect call */
29847 +
29848 +                       fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
29849 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_OUT);
29850 +
29851 +                       sess->state = PROXY_STATE_CONNECTING;
29852 +                       sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTING;
29853 +                       
29854 +                       return HANDLER_WAIT_FOR_EVENT;
29855 +               case HANDLER_GO_ON:
29856 +                       /* we are connected */
29857 +                       sess->state = PROXY_STATE_CONNECTED;
29858 +                       sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
29859 +                       fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
29860 +
29861 +                       break;
29862 +               case HANDLER_ERROR:
29863 +               default:
29864 +                       /* not good, something failed */
29865 +                       return HANDLER_ERROR;
29866 +               
29867 +               }
29868 +       } else if (sess->state == PROXY_STATE_CONNECTING) {
29869 +               int socket_error;
29870 +               socklen_t socket_error_len = sizeof(socket_error);
29871 +
29872 +               fdevent_event_del(srv->ev, sess->proxy_con->sock);
29873 +
29874 +               if (0 != getsockopt(sess->proxy_con->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
29875 +                       ERROR("getsockopt failed:", strerror(errno));
29876 +
29877 +                       return HANDLER_ERROR;
29878 +               }
29879 +               if (socket_error != 0) {
29880 +                       switch (socket_error) {
29881 +                       case ECONNREFUSED:
29882 +                               /* there is no-one on the other side */
29883 +                               sess->proxy_con->address->disabled_until = srv->cur_ts + 2;
29884 +
29885 +                               TRACE("address %s refused us, disabling for 2 sec", sess->proxy_con->address->name->ptr);
29886 +                               break;
29887 +                       case EHOSTUNREACH:
29888 +                               /* there is no-one on the other side */
29889 +                               sess->proxy_con->address->disabled_until = srv->cur_ts + 60;
29890 +
29891 +                               TRACE("host %s is unreachable, disabling for 60 sec", sess->proxy_con->address->name->ptr);
29892 +                               break;
29893 +                       default:
29894 +                               sess->proxy_con->address->disabled_until = srv->cur_ts + 60;
29895 +
29896 +                               TRACE("connected finally failed: %s (%d)", strerror(socket_error), socket_error);
29897 +
29898 +                               TRACE("connect to address %s failed and I don't know why, disabling for 10 sec", sess->proxy_con->address->name->ptr);
29899 +
29900 +                               break;
29901 +                       }
29902 +
29903 +                       sess->proxy_con->address->state = PROXY_ADDRESS_STATE_DISABLED;
29904 +
29905 +                       sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29906 +                       return HANDLER_COMEBACK;
29907 +               }
29908 +
29909 +               sess->state = PROXY_STATE_CONNECTED;
29910 +               sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
29911 +       }
29912 +
29913 +       if (sess->state == PROXY_STATE_CONNECTED) {
29914 +               /* build the header */
29915 +               proxy_get_request_header(srv, con, p, sess);
29916 +
29917 +               sess->state = PROXY_STATE_WRITE_REQUEST_HEADER;
29918 +       }
29919 +
29920 +       switch (sess->state) {
29921 +       case PROXY_STATE_WRITE_REQUEST_HEADER:
29922 +               /* create the request-packet */ 
29923 +               fdevent_event_del(srv->ev, sess->proxy_con->sock);
29924 +
29925 +               switch (srv->network_backend_write(srv, con, sess->proxy_con->sock, sess->send_raw)) {
29926 +               case NETWORK_STATUS_SUCCESS:
29927 +                       sess->state = PROXY_STATE_WRITE_REQUEST_BODY;
29928 +                       break;
29929 +               case NETWORK_STATUS_WAIT_FOR_EVENT:
29930 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_OUT);
29931 +
29932 +                       return HANDLER_WAIT_FOR_EVENT;
29933 +               case NETWORK_STATUS_CONNECTION_CLOSE:
29934 +                       sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29935 +
29936 +                       /* this connection is closed, restart the request with a new connection */
29937 +
29938 +                       return HANDLER_COMEBACK;
29939 +               default:
29940 +                       return HANDLER_ERROR;
29941 +               }
29942 +               /* fall through */
29943 +       case PROXY_STATE_WRITE_REQUEST_BODY:
29944 +               fdevent_event_del(srv->ev, sess->proxy_con->sock);
29945 +               sess->state = PROXY_STATE_READ_RESPONSE_HEADER;
29946 +
29947 +       case PROXY_STATE_READ_RESPONSE_HEADER:
29948 +               fdevent_event_del(srv->ev, sess->proxy_con->sock);
29949 +
29950 +               chunkqueue_remove_finished_chunks(sess->recv_raw);
29951 +
29952 +               switch (srv->network_backend_read(srv, con, sess->proxy_con->sock, sess->recv_raw)) {
29953 +               case NETWORK_STATUS_SUCCESS:
29954 +                       /* we read everything from the socket, do we have a full header ? */
29955 +
29956 +                       switch (proxy_parse_response_header(srv, con, p, sess, sess->recv_raw)) {
29957 +                       case PARSE_ERROR:
29958 +                               con->http_status = 502; /* bad gateway */
29959 +
29960 +                               return HANDLER_FINISHED;
29961 +                       case PARSE_NEED_MORE:
29962 +                               /* we need more */
29963 +                               fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
29964 +
29965 +                               return HANDLER_WAIT_FOR_EVENT;
29966 +                       case PARSE_SUCCESS:
29967 +                               break;
29968 +                       default:
29969 +                               return HANDLER_ERROR;
29970 +                       }
29971 +                       
29972 +                       con->file_started = 1;
29973 +
29974 +                       sess->state = PROXY_STATE_READ_RESPONSE_BODY;
29975 +
29976 +                       /**
29977 +                        * set the event to pass the content through to the server
29978 +                        *
29979 +                        * this triggers the event-handler
29980 +                        * @see proxy_handle_fdevent
29981 +                        */
29982 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
29983 +
29984 +                       return HANDLER_GO_ON; /* tell http_response_prepare that we are done with the header */
29985 +               case NETWORK_STATUS_WAIT_FOR_EVENT:
29986 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
29987 +                       return HANDLER_WAIT_FOR_EVENT;
29988 +               case NETWORK_STATUS_CONNECTION_CLOSE:
29989 +                       if (chunkqueue_length(sess->recv_raw) == 0) {
29990 +                               /* the connection went away before we got something back */
29991 +                               sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29992 +
29993 +                               /**
29994 +                                * we might run into a 'race-condition' 
29995 +                                *
29996 +                                * 1. proxy-con is keep-alive, idling and just being closed (FDEVENT_IN) [fd=27]
29997 +                                * 2. new connection comes in, we use the idling connection [fd=14]
29998 +                                * 3. we write(), successful [to fd=27]
29999 +                                * 3. we read() ... and finally receive the close-event for the connection
30000 +                                */
30001 +
30002 +                               con->http_status = 500;
30003 +
30004 +                               ERROR("++ %s", "oops, connection got closed while we were reading from it");
30005 +                               return HANDLER_FINISHED;
30006 +                       }
30007 +
30008 +                       ERROR("%s", "conn-close after header-read");
30009 +                               
30010 +                       break;
30011 +               default:
30012 +                       ERROR("++ %s", "oops, something went wrong while reading");
30013 +                       return HANDLER_ERROR;
30014 +               }
30015 +       case PROXY_STATE_READ_RESPONSE_BODY:
30016 +               /* if we do everything right, we won't get call for this state-anymore */
30017 +
30018 +               ERROR("%s", "PROXY_STATE_READ_RESPONSE_BODY");
30019 +               
30020 +               break;
30021 +       }
30022 +
30023 +       return HANDLER_GO_ON;
30024 +}
30025 +
30026 +proxy_backend *proxy_get_backend(server *srv, connection *con, plugin_data *p) {
30027 +       size_t i;
30028 +
30029 +       for (i = 0; i < p->conf.backends->used; i++) {
30030 +               proxy_backend *backend = p->conf.backends->ptr[i];
30031 +
30032 +               return backend;
30033 +       }
30034 +
30035 +       return NULL;
30036 +}
30037 +
30038 +/**
30039 + * choose a available address from the address-pool
30040 + *
30041 + * the backend has different balancers 
30042 + */
30043 +proxy_address *proxy_backend_balance(server *srv, connection *con, proxy_backend *backend) {
30044 +       size_t i;
30045 +       proxy_address_pool *address_pool = backend->address_pool;
30046 +       unsigned long last_max; /* for the HASH balancer */
30047 +       proxy_address *address = NULL, *cur_address = NULL;
30048 +       int active_addresses = 0, rand_ndx;
30049 +
30050 +       switch(backend->balancer) {
30051 +       case PROXY_BALANCE_HASH:
30052 +               /* hash balancing */
30053 +
30054 +               for (i = 0, last_max = ULONG_MAX; i < address_pool->used; i++) {
30055 +                       unsigned long cur_max;
30056 +
30057 +                       cur_address = address_pool->ptr[i];
30058 +
30059 +                       if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
30060 +
30061 +                       cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) +
30062 +                               generate_crc32c(CONST_BUF_LEN(cur_address->name)) + /* we can cache this */
30063 +                               generate_crc32c(CONST_BUF_LEN(con->uri.authority));
30064 +
30065 +                       TRACE("hash-election: %s - %s - %s: %ld", 
30066 +                                       con->uri.path->ptr,
30067 +                                       cur_address->name->ptr,
30068 +                                       con->uri.authority->ptr,
30069 +                                       cur_max);
30070 +
30071 +                       if (address == NULL || (cur_max > last_max)) {
30072 +                               last_max = cur_max;
30073 +
30074 +                               address = cur_address;
30075 +                       }
30076 +               }
30077 +
30078 +               break;
30079 +       case PROXY_BALANCE_FAIR:
30080 +               /* fair balancing */
30081 +
30082 +               for (i = 0; i < address_pool->used; i++) {
30083 +                       cur_address = address_pool->ptr[i];
30084 +
30085 +                       if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
30086 +
30087 +                       /* the address is up, use it */
30088 +
30089 +                       address = cur_address;
30090 +
30091 +                       break;
30092 +               }
30093 +
30094 +               break;
30095 +       case PROXY_BALANCE_RR:
30096 +               /* round robin */
30097 +
30098 +               /**
30099 +                * instead of real RoundRobin we just do a RandomSelect
30100 +                *
30101 +                * it is state-less and has the same distribution
30102 +                */
30103 +
30104 +               active_addresses = 0;
30105 +               
30106 +               for (i = 0; i < address_pool->used; i++) {
30107 +                       cur_address = address_pool->ptr[i];
30108 +
30109 +                       if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
30110 +
30111 +                       active_addresses++;
30112 +               }
30113 +
30114 +               rand_ndx = (int) (1.0 * active_addresses * rand()/(RAND_MAX));
30115 +       
30116 +               active_addresses = 0;
30117 +               for (i = 0; i < address_pool->used; i++) {
30118 +                       cur_address = address_pool->ptr[i];
30119 +
30120 +                       if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
30121 +
30122 +                       address = cur_address;
30123 +
30124 +                       if (rand_ndx == active_addresses++) break;
30125 +               }
30126 +
30127 +               break;
30128 +       default:
30129 +               break;
30130 +       }
30131 +
30132 +       return address;
30133 +}
30134 +
30135 +static int mod_proxy_core_patch_connection(server *srv, connection *con, plugin_data *p) {
30136 +       size_t i, j;
30137 +       plugin_config *s = p->config_storage[0];
30138 +
30139 +       /* global defaults */
30140 +       PATCH_OPTION(balancer);
30141 +       PATCH_OPTION(debug);
30142 +       PATCH_OPTION(backends);
30143 +       PATCH_OPTION(backlog);
30144 +       PATCH_OPTION(protocol);
30145 +       PATCH_OPTION(request_rewrites);
30146 +       PATCH_OPTION(response_rewrites);
30147 +
30148 +       /* skip the first, the global context */
30149 +       for (i = 1; i < srv->config_context->used; i++) {
30150 +               data_config *dc = (data_config *)srv->config_context->data[i];
30151 +               s = p->config_storage[i];
30152 +
30153 +               /* condition didn't match */
30154 +               if (!config_check_cond(srv, con, dc)) continue;
30155 +
30156 +               /* merge config */
30157 +               for (j = 0; j < dc->value->used; j++) {
30158 +                       data_unset *du = dc->value->data[j];
30159 +
30160 +                       if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy-core.backends"))) {
30161 +                               PATCH_OPTION(backends);
30162 +                               PATCH_OPTION(backlog);
30163 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy-core.debug"))) {
30164 +                               PATCH_OPTION(debug);
30165 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy-core.balancer"))) {
30166 +                               PATCH_OPTION(balancer);
30167 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy-core.protocol"))) {
30168 +                               PATCH_OPTION(protocol);
30169 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_REWRITE_REQUEST))) {
30170 +                               PATCH_OPTION(request_rewrites);
30171 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_REWRITE_RESPONSE))) {
30172 +                               PATCH_OPTION(response_rewrites);
30173 +                       }
30174 +               }
30175 +       }
30176 +
30177 +       return 0;
30178 +}
30179 +
30180 +
30181 +SUBREQUEST_FUNC(mod_proxy_core_check_extension) {
30182 +       plugin_data *p = p_d;
30183 +       proxy_session *sess = con->plugin_ctx[p->id]; /* if this is the second round, sess is already prepared */
30184 +
30185 +       /* check if we have a matching conditional for this request */
30186 +
30187 +       if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
30188 +
30189 +       mod_proxy_core_patch_connection(srv, con, p);
30190 +
30191 +       if (p->conf.backends->used == 0) return HANDLER_GO_ON;
30192 +
30193 +       /* 
30194 +        * 0. build session
30195 +        * 1. get a proxy connection
30196 +        * 2. create the http-request header
30197 +        * 3. stream the content to the backend 
30198 +        * 4. wait for http-response header 
30199 +        * 5. decode the response + parse the response
30200 +        * 6. stream the response-content to the client 
30201 +        * 7. kill session
30202 +        * */
30203 +
30204 +       if (!sess) {
30205 +               /* a session lives for a single request */
30206 +               sess = proxy_session_init();
30207 +
30208 +               con->plugin_ctx[p->id] = sess;
30209 +               con->mode = p->id;
30210 +
30211 +               sess->remote_con = con;
30212 +       }
30213 +
30214 +       switch (sess->state) {
30215 +       case PROXY_STATE_CONNECTING:
30216 +               /* this connections is waited 10 seconds to connect to the backend
30217 +                * and didn't got a successful connection yet, sending timeout */
30218 +               if (srv->cur_ts - con->request_start > 10) {
30219 +                       con->http_status = 504; /* gateway timeout */
30220 +
30221 +                       if (sess->proxy_con) {
30222 +                               /* if we are waiting for a proxy-connection right now, close it */
30223 +                               proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
30224 +       
30225 +                               fdevent_event_del(srv->ev, sess->proxy_con->sock);
30226 +                               fdevent_unregister(srv->ev, sess->proxy_con->sock);
30227 +
30228 +                               proxy_connection_free(sess->proxy_con);
30229 +                       
30230 +                               sess->proxy_con = NULL;
30231 +                       }
30232 +                       
30233 +                       return HANDLER_FINISHED;
30234 +               }
30235 +       default:
30236 +               /* handle-request-timeout,  */
30237 +               if (srv->cur_ts - con->request_start > 60) {
30238 +                       TRACE("request runs longer than 60sec: current state: %d", sess->state);
30239 +               }
30240 +               break;
30241 +       }
30242 +
30243 +       /* if the WRITE fails from the start, restart the connection */
30244 +       while (1) {
30245 +               if (sess->proxy_con == NULL) {
30246 +                       proxy_address *address = NULL;
30247 +                       if (NULL == (sess->proxy_backend = proxy_get_backend(srv, con, p))) {
30248 +                               /* no connection pool for this location */
30249 +                               SEGFAULT();
30250 +                       }
30251 +
30252 +                       /**
30253 +                        * ask the balancer for the next address and
30254 +                        * check the connection pool if we have a connection open
30255 +                        * for that address
30256 +                        */
30257 +                       if (NULL == (address = proxy_backend_balance(srv, con, sess->proxy_backend))) {
30258 +                               /* we don't have any backends to connect to */
30259 +                               proxy_request *req;
30260 +
30261 +                               /* connection pool is full, queue the request for now */
30262 +                               req = proxy_request_init();
30263 +                               req->added_ts = srv->cur_ts;
30264 +                               req->con = con;
30265 +                               
30266 +                               TRACE("backlog: all backends are down, putting %s (%d) into the backlog", BUF_STR(con->uri.path), con->sock->fd);
30267 +                               proxy_backlog_push(p->conf.backlog, req);
30268 +
30269 +                               /* no, not really a event, 
30270 +                                * we just want to block the outer loop from stepping forward
30271 +                                *
30272 +                                * the trigger will bring this connection back into the game
30273 +                                * */
30274 +                               return HANDLER_WAIT_FOR_EVENT;
30275 +                       }
30276 +
30277 +                       if (PROXY_CONNECTIONPOOL_FULL == proxy_connection_pool_get_connection(
30278 +                                               sess->proxy_backend->pool, 
30279 +                                               address,
30280 +                                               &(sess->proxy_con))) {
30281 +                               proxy_request *req;
30282 +
30283 +                               /* connection pool is full, queue the request for now */
30284 +                               req = proxy_request_init();
30285 +                               req->added_ts = srv->cur_ts;
30286 +                               req->con = con;
30287 +                               
30288 +                               TRACE("backlog: the con-pool is full, putting %s (%d) into the backlog", con->uri.path->ptr, con->sock->fd);
30289 +                               proxy_backlog_push(p->conf.backlog, req);
30290 +
30291 +                               /* no, not really a event, 
30292 +                                * we just want to block the outer loop from stepping forward
30293 +                                *
30294 +                                * the trigger will bring this connection back into the game
30295 +                                * */
30296 +                               return HANDLER_WAIT_FOR_EVENT;
30297 +                       }
30298 +
30299 +                       /* a fresh connection, we need address for it */
30300 +                       if (sess->proxy_con->state == PROXY_CONNECTION_STATE_CONNECTING) {
30301 +                               sess->state = PROXY_STATE_UNSET;
30302 +                               sess->bytes_read = 0;
30303 +                       } else {
30304 +                               /* we are already connected */
30305 +                               sess->state = PROXY_STATE_CONNECTED;
30306 +                               
30307 +                               /* the connection was idling and using the fdevent_idle-handler 
30308 +                                * switch it back to the normal proxy-event-handler */
30309 +                               fdevent_event_del(srv->ev, sess->proxy_con->sock);
30310 +                               fdevent_unregister(srv->ev, sess->proxy_con->sock);
30311 +
30312 +                               fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
30313 +                               fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
30314 +                       }
30315 +               }
30316 +
30317 +               switch (proxy_state_engine(srv, con, p, sess)) {
30318 +               case HANDLER_WAIT_FOR_EVENT:
30319 +                       return HANDLER_WAIT_FOR_EVENT;
30320 +               case HANDLER_COMEBACK:
30321 +                       proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
30322 +       
30323 +                       fdevent_event_del(srv->ev, sess->proxy_con->sock);
30324 +                       fdevent_unregister(srv->ev, sess->proxy_con->sock);
30325 +
30326 +                       proxy_connection_free(sess->proxy_con);
30327 +
30328 +                       sess->proxy_con = NULL;
30329 +                       /* restart the connection to the backend */
30330 +                       TRACE("%s", "write failed, restarting request");
30331 +                       break;
30332 +               case HANDLER_GO_ON:
30333 +                       return HANDLER_GO_ON;
30334 +               default:
30335 +                       return HANDLER_ERROR;
30336 +               }
30337 +       }
30338 +
30339 +       /* should not be reached */
30340 +       return HANDLER_ERROR;
30341 +}
30342 +
30343 +/**
30344 + * end of the connection to the client
30345 + */
30346 +REQUESTDONE_FUNC(mod_proxy_connection_close_callback) {
30347 +       plugin_data *p = p_d;
30348 +       
30349 +       if (con->mode != p->id) return HANDLER_GO_ON;
30350 +
30351 +       return HANDLER_GO_ON;
30352 +}
30353 +
30354 +/**
30355 + * end of a request
30356 + */
30357 +CONNECTION_FUNC(mod_proxy_connection_reset) {
30358 +       plugin_data *p = p_d;
30359 +       proxy_session *sess = con->plugin_ctx[p->id]; 
30360 +
30361 +       if (con->mode != p->id) return HANDLER_GO_ON;
30362 +
30363 +       if (sess->proxy_con) {
30364 +               switch (sess->proxy_con->state) {
30365 +               case PROXY_CONNECTION_STATE_CONNECTED:
30366 +                       sess->proxy_con->state = PROXY_CONNECTION_STATE_IDLE;
30367 +
30368 +                       /* ignore events as the FD is idle, we might get a HUP as the remote connection might close */
30369 +                       fdevent_event_del(srv->ev, sess->proxy_con->sock);
30370 +                       fdevent_unregister(srv->ev, sess->proxy_con->sock);
30371 +
30372 +                       fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent_idle, sess->proxy_con);
30373 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
30374 +
30375 +                       break;
30376 +               case PROXY_CONNECTION_STATE_CLOSED:
30377 +                       proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
30378 +       
30379 +                       fdevent_event_del(srv->ev, sess->proxy_con->sock);
30380 +                       fdevent_unregister(srv->ev, sess->proxy_con->sock);
30381 +
30382 +                       proxy_connection_free(sess->proxy_con);
30383 +                       break;
30384 +               case PROXY_CONNECTION_STATE_IDLE:
30385 +                       TRACE("%s", "... connection is already back in the pool");
30386 +                       break;
30387 +               default:
30388 +                       ERROR("connection is in a unexpected state at close-time: %d", sess->proxy_con->state);
30389 +                       break;
30390 +               }
30391 +       } else {
30392 +               /* if we have the connection in the backlog, remove it */
30393 +               proxy_backlog_remove_connection(p->conf.backlog, con);
30394 +       }
30395 +       
30396 +
30397 +       proxy_session_free(sess);
30398 +
30399 +       con->plugin_ctx[p->id] = NULL;
30400 +       
30401 +       return HANDLER_GO_ON;
30402 +}
30403 +
30404 +
30405 +
30406 +/**
30407 + * cleanup dead connections once a second
30408 + *
30409 + * the idling event-handler can't cleanup connections itself and has to wait until the 
30410 + * trigger cleans up
30411 + */
30412 +handler_t mod_proxy_trigger_context(server *srv, plugin_config *p) {
30413 +       size_t i, j;
30414 +       proxy_request *req;
30415 +
30416 +       for (i = 0; i < p->backends->used; i++) {
30417 +               proxy_backend *backend = p->backends->ptr[i];
30418 +               proxy_connection_pool *pool = backend->pool;
30419 +               proxy_address_pool *address_pool = backend->address_pool;
30420 +
30421 +               for (j = 0; j < pool->used; ) {
30422 +                       proxy_connection *proxy_con = pool->ptr[j];
30423 +
30424 +                       /* remove-con is removing the current con and moves the good connections to the left
30425 +                        * no need to increment i */
30426 +                       if (proxy_con->state == PROXY_CONNECTION_STATE_CLOSED) {
30427 +                               proxy_connection_pool_remove_connection(backend->pool, proxy_con);
30428 +       
30429 +                               fdevent_event_del(srv->ev, proxy_con->sock);
30430 +                               fdevent_unregister(srv->ev, proxy_con->sock);
30431 +
30432 +                               proxy_connection_free(proxy_con);
30433 +                       } else {
30434 +                               j++;
30435 +                       }
30436 +               }
30437 +
30438 +               /* active the disabled addresses again */
30439 +               for (j = 0; j < address_pool->used; j++) {
30440 +                       proxy_address *address = address_pool->ptr[j];
30441 +
30442 +                       if (address->state != PROXY_ADDRESS_STATE_DISABLED) continue;
30443 +
30444 +                       if (srv->cur_ts > address->disabled_until) {
30445 +                               address->disabled_until = 0;
30446 +                               address->state = PROXY_ADDRESS_STATE_ACTIVE;
30447 +                       }
30448 +               }
30449 +       }
30450 +
30451 +       /* wake up the connections from the backlog */
30452 +       while ((req = proxy_backlog_shift(p->backlog))) {
30453 +               connection *con = req->con;
30454 +
30455 +               joblist_append(srv, con);
30456 +
30457 +               proxy_request_free(req);
30458 +       }
30459 +       
30460 +       return HANDLER_GO_ON;
30461 +}
30462 +
30463 +TRIGGER_FUNC(mod_proxy_trigger) {
30464 +       plugin_data *p = p_d;
30465 +       size_t i;
30466 +       
30467 +       for (i = 0; i < srv->config_context->used; i++) {
30468 +               mod_proxy_trigger_context(srv, p->config_storage[i]);
30469 +       }
30470 +
30471 +       return HANDLER_GO_ON;
30472 +}
30473 +
30474 +int mod_proxy_core_plugin_init(plugin *p) {
30475 +       p->version      = LIGHTTPD_VERSION_ID;
30476 +       p->name         = buffer_init_string("mod_proxy_core");
30477 +
30478 +       p->init         = mod_proxy_core_init;
30479 +       p->cleanup      = mod_proxy_core_free;
30480 +       p->set_defaults = mod_proxy_core_set_defaults;
30481 +       p->handle_uri_clean        = mod_proxy_core_check_extension;
30482 +       p->handle_subrequest_start = mod_proxy_core_check_extension;
30483 +       p->handle_subrequest       = mod_proxy_core_check_extension;
30484 +       p->connection_reset        = mod_proxy_connection_reset;
30485 +       p->handle_connection_close = mod_proxy_connection_close_callback;
30486 +       p->handle_trigger          = mod_proxy_trigger;
30487 +
30488 +       p->data         = NULL;
30489 +
30490 +       return 0;
30491 +}
30492 --- ../lighttpd-1.4.11/src/mod_proxy_core.h     1970-01-01 03:00:00.000000000 +0300
30493 +++ lighttpd-1.4.12/src/mod_proxy_core.h        2006-07-18 13:03:40.000000000 +0300
30494 @@ -0,0 +1,18 @@
30495 +#ifndef _MOD_PROXY_CORE_H_
30496 +#define _MOD_PROXY_CORE_H_
30497 +
30498 +#include "buffer.h"
30499 +#include "base.h"
30500 +
30501 +#define PROXY_BACKEND_CONNECT_PARAMS \
30502 +       (server *srv, connection *con, void *p_d)
30503 +
30504 +#define PROXY_BACKEND_CONNECT_RETVAL handler_t
30505 +
30506 +#define PROXY_BACKEND_CONNECT(name) \
30507 +       PROXY_BACKEND_CONNECT_RETVAL name PROXY_BACKEND_CONNECT_PARAMS
30508 +
30509 +#define PROXY_BACKEND_CONNECT_PTR(name) \
30510 +       PROXY_BACKEND_CONNECT_RETVAL (* name)PROXY_BACKEND_CONNECT_PARAMS
30511 +
30512 +#endif
30513 --- ../lighttpd-1.4.11/src/mod_proxy_core_address.c     1970-01-01 03:00:00.000000000 +0300
30514 +++ lighttpd-1.4.12/src/mod_proxy_core_address.c        2006-07-18 13:03:40.000000000 +0300
30515 @@ -0,0 +1,85 @@
30516 +#include <stdlib.h>
30517 +#include <string.h>
30518 +
30519 +#include "log.h"
30520 +#include "sys-socket.h"
30521 +#include "mod_proxy_core_address.h"
30522 +
30523 +proxy_address *proxy_address_init(void) {
30524 +       proxy_address *address;
30525 +
30526 +       address = calloc(1, sizeof(*address));
30527 +
30528 +       address->name = buffer_init();
30529 +
30530 +       return address;
30531 +}
30532 +
30533 +void proxy_address_free(proxy_address *address) {
30534 +       if (!address) return;
30535 +
30536 +       buffer_free(address->name);
30537 +
30538 +       free(address);
30539 +}
30540 +
30541 +
30542 +proxy_address_pool *proxy_address_pool_init(void) {
30543 +       proxy_address_pool *address_pool;
30544 +
30545 +       address_pool = calloc(1, sizeof(*address_pool));
30546 +
30547 +       return address_pool;
30548 +}
30549 +
30550 +void proxy_address_pool_free(proxy_address_pool *address_pool) {
30551 +       if (!address_pool) return;
30552 +
30553 +       FOREACH(address_pool, element, proxy_address_free(element))
30554 +
30555 +       free(address_pool);
30556 +}
30557 +
30558 +void proxy_address_pool_add(proxy_address_pool *address_pool, proxy_address *address) {
30559 +       ARRAY_STATIC_PREPARE_APPEND(address_pool);
30560 +       
30561 +       address_pool->ptr[address_pool->used++] = address;
30562 +}
30563 +
30564 +int  proxy_address_pool_add_string(proxy_address_pool *address_pool, buffer *name) {
30565 +       struct addrinfo *res = NULL, pref, *cur;
30566 +       int ret;
30567 +
30568 +       pref.ai_flags = 0;
30569 +       pref.ai_family = PF_UNSPEC;
30570 +       pref.ai_socktype = SOCK_STREAM;
30571 +       pref.ai_protocol = 0;
30572 +       pref.ai_addrlen = 0;
30573 +       pref.ai_addr = NULL;
30574 +       pref.ai_canonname = NULL;
30575 +       pref.ai_next = NULL;
30576 +
30577 +       if (0 != (ret = getaddrinfo(name->ptr, "80", &pref, &res))) {
30578 +               ERROR("getaddrinfo failed: %s", gai_strerror(ret));
30579 +
30580 +               return -1;
30581 +       }
30582 +
30583 +       for (cur = res; cur; cur = cur->ai_next) {
30584 +               proxy_address *a = proxy_address_init();
30585 +
30586 +               memcpy(&(a->addr), cur->ai_addr, cur->ai_addrlen);
30587 +
30588 +               a->state = PROXY_ADDRESS_STATE_ACTIVE;
30589 +
30590 +               buffer_copy_string(a->name, inet_ntoa(a->addr.ipv4.sin_addr));
30591 +
30592 +               proxy_address_pool_add(address_pool, a);
30593 +       }
30594 +
30595 +       freeaddrinfo(res);
30596 +
30597 +       return 0;
30598 +}
30599 +
30600 +
30601 --- ../lighttpd-1.4.11/src/mod_proxy_core_address.h     1970-01-01 03:00:00.000000000 +0300
30602 +++ lighttpd-1.4.12/src/mod_proxy_core_address.h        2006-07-18 13:03:40.000000000 +0300
30603 @@ -0,0 +1,33 @@
30604 +#ifndef _MOD_PROXY_CORE_ADDRESS_H_
30605 +#define _MOD_PROXY_CORE_ADDRESS_H_
30606 +
30607 +#include <time.h>
30608 +#include "buffer.h"
30609 +#include "sys-socket.h"
30610 +#include "array-static.h"
30611 +
30612 +typedef enum {
30613 +       PROXY_ADDRESS_STATE_UNSET,
30614 +       PROXY_ADDRESS_STATE_ACTIVE,
30615 +       PROXY_ADDRESS_STATE_DISABLED,
30616 +} proxy_address_state_t;
30617 +
30618 +typedef struct {
30619 +       sock_addr addr;
30620 +
30621 +       buffer *name; /* a inet_ntoa() prepresentation of the address */
30622 +
30623 +       time_t last_used;
30624 +       time_t disabled_until;
30625 +
30626 +       proxy_address_state_t state;
30627 +} proxy_address;
30628 +
30629 +ARRAY_STATIC_DEF(proxy_address_pool, proxy_address, );
30630 +
30631 +proxy_address_pool *proxy_address_pool_init(void); 
30632 +void proxy_address_pool_free(proxy_address_pool *address_pool); 
30633 +void proxy_address_pool_add(proxy_address_pool *address_pool, proxy_address *address);
30634 +int proxy_address_pool_add_string(proxy_address_pool *address_pool, buffer *address);
30635 +
30636 +#endif
30637 --- ../lighttpd-1.4.11/src/mod_proxy_core_backend.c     1970-01-01 03:00:00.000000000 +0300
30638 +++ lighttpd-1.4.12/src/mod_proxy_core_backend.c        2006-07-18 13:03:40.000000000 +0300
30639 @@ -0,0 +1,45 @@
30640 +#include <stdlib.h>
30641 +
30642 +#include "mod_proxy_core_backend.h"
30643 +#include "mod_proxy_core_pool.h"
30644 +#include "mod_proxy_core_address.h"
30645 +
30646 +proxy_backend *proxy_backend_init(void) {
30647 +       proxy_backend *backend;
30648 +
30649 +       backend = calloc(1, sizeof(*backend));
30650 +       backend->pool = proxy_connection_pool_init();
30651 +       backend->address_pool = proxy_address_pool_init();
30652 +       backend->balancer = PROXY_BALANCE_RR;
30653 +
30654 +       return backend;
30655 +}
30656 +
30657 +void proxy_backend_free(proxy_backend *backend) {
30658 +       if (!backend) return;
30659 +
30660 +       proxy_address_pool_free(backend->address_pool);
30661 +       proxy_connection_pool_free(backend->pool);
30662 +       
30663 +       free(backend);
30664 +}
30665 +
30666 +proxy_backends *proxy_backends_init(void) {
30667 +       proxy_backends *backends;
30668 +
30669 +       backends = calloc(1, sizeof(*backends));
30670 +
30671 +       return backends;
30672 +}
30673 +
30674 +void proxy_backends_free(proxy_backends *backends) {
30675 +       FOREACH(backends, element, proxy_backend_free(element))
30676 +
30677 +       free(backends);
30678 +}
30679 +
30680 +void proxy_backends_add(proxy_backends *backends, proxy_backend *backend) {
30681 +       ARRAY_STATIC_PREPARE_APPEND(backends);
30682 +
30683 +       backends->ptr[backends->used++] = backend;
30684 +}
30685 --- ../lighttpd-1.4.11/src/mod_proxy_core_backend.h     1970-01-01 03:00:00.000000000 +0300
30686 +++ lighttpd-1.4.12/src/mod_proxy_core_backend.h        2006-07-18 13:03:40.000000000 +0300
30687 @@ -0,0 +1,54 @@
30688 +#ifndef _MOD_PROXY_CORE_BACKEND_H_
30689 +#define _MOD_PROXY_CORE_BACKEND_H_
30690 +
30691 +#include "array-static.h"
30692 +#include "buffer.h"
30693 +#include "mod_proxy_core_address.h"
30694 +#include "mod_proxy_core_pool.h"
30695 +#include "sys-socket.h"
30696 +
30697 +/**
30698 + * a single DNS name might explode to several IP addresses 
30699 + * 
30700 + * url: 
30701 + * - http://foo.bar/suburl/
30702 + * - https://foo.bar/suburl/
30703 + * - unix:/tmp/socket
30704 + * - tcp://foobar:1025/
30705 + *
30706 + * backend:
30707 + * - scgi
30708 + * - http
30709 + * - fastcgi
30710 + *
30711 + * request-url-rewrite
30712 + * response-url-rewrite
30713 + */ 
30714 +typedef enum {
30715 +       PROXY_BALANCE_UNSET,
30716 +       PROXY_BALANCE_FAIR,
30717 +       PROXY_BALANCE_HASH,
30718 +       PROXY_BALANCE_RR
30719 +} proxy_balance_t;
30720 +
30721 +typedef struct {
30722 +       buffer *url;
30723 +
30724 +       proxy_connection_pool *pool;  /* pool of active connections */
30725 +       int use_keepalive;
30726 +
30727 +       proxy_address_pool *address_pool; /* possible destination-addresses, disabling is done here */
30728 +       proxy_balance_t balancer; /* how to choose a address from the address-pool */
30729 +} proxy_backend;
30730 +
30731 +ARRAY_STATIC_DEF(proxy_backends, proxy_backend, );
30732 +
30733 +proxy_backend *proxy_backend_init(void);
30734 +void proxy_backend_free(proxy_backend *backend);
30735 +
30736 +proxy_backends *proxy_backends_init(void);
30737 +void proxy_backends_free(proxy_backends *backends);
30738 +void proxy_backends_add(proxy_backends *backends, proxy_backend *backend);
30739 +
30740 +#endif
30741 +
30742 --- ../lighttpd-1.4.11/src/mod_proxy_core_backlog.c     1970-01-01 03:00:00.000000000 +0300
30743 +++ lighttpd-1.4.12/src/mod_proxy_core_backlog.c        2006-07-18 13:03:40.000000000 +0300
30744 @@ -0,0 +1,109 @@
30745 +#include <stdlib.h>
30746 +
30747 +#include "mod_proxy_core_backlog.h"
30748 +#include "array-static.h"
30749 +
30750 +proxy_backlog *proxy_backlog_init(void) {
30751 +       STRUCT_INIT(proxy_backlog, backlog);
30752 +
30753 +       return backlog;
30754 +}
30755 +
30756 +void proxy_backlog_free(proxy_backlog *backlog) {
30757 +       if (!backlog) return;
30758 +
30759 +       free(backlog);
30760 +}
30761 +
30762 +int proxy_backlog_push(proxy_backlog *backlog, proxy_request *req) {
30763 +       /* first entry */
30764 +       if (NULL == backlog->first) {
30765 +               backlog->first = backlog->last = req;
30766 +       } else {
30767 +               backlog->last->next = req;
30768 +               backlog->last = req;
30769 +       }
30770 +       backlog->length++;
30771 +
30772 +       return 0;
30773 +}
30774 +
30775 +/**
30776 + * remove the first element from the backlog
30777 + */
30778 +proxy_request *proxy_backlog_shift(proxy_backlog *backlog) {
30779 +       proxy_request *req = NULL;
30780 +
30781 +       if (!backlog->first) return req;
30782 +
30783 +       backlog->length--;
30784 +
30785 +       req = backlog->first;
30786 +
30787 +       backlog->first = req->next;
30788 +
30789 +       /* the backlog is empty */
30790 +       if (backlog->first == NULL) backlog->last = NULL;
30791 +
30792 +       return req;
30793 +}
30794 +
30795 +int proxy_backlog_remove_connection(proxy_backlog *backlog, void *con) {
30796 +       proxy_request *req = NULL;
30797 +
30798 +       if (!backlog->first) return -1;
30799 +       if (!con) return -1;
30800 +
30801 +       /* the first element is what we look for */
30802 +       if (backlog->first->con == con) {
30803 +               req = backlog->first;
30804 +               
30805 +               backlog->first = req->next;
30806 +               if (backlog->first == NULL) backlog->last = NULL;
30807 +
30808 +               backlog->length--;
30809 +               
30810 +               proxy_request_free(req);
30811 +
30812 +               return 0;
30813 +       }
30814 +
30815 +
30816 +       for (req = backlog->first; req && req->next; req = req->next) {
30817 +               proxy_request *cur;
30818 +
30819 +               if (req->next->con != con) continue;
30820 +
30821 +               backlog->length--;
30822 +               /* the next node is our searched connection */
30823 +
30824 +               cur = req->next;
30825 +               req->next = cur->next;
30826 +
30827 +               /* the next node is the last one, make the current the new last */
30828 +               if (cur == backlog->last) {
30829 +                       backlog->last = req;
30830 +               }
30831 +               cur->next = NULL;
30832 +
30833 +               proxy_request_free(req);
30834 +
30835 +               return 0;
30836 +       }
30837 +
30838 +       return -1;
30839 +}
30840 +
30841 +proxy_request *proxy_request_init(void) {
30842 +       STRUCT_INIT(proxy_request, request);
30843 +
30844 +       return request;
30845 +}
30846 +
30847 +void proxy_request_free(proxy_request *request) {
30848 +       if (!request) return;
30849 +
30850 +       free(request);
30851 +}
30852 +
30853 +
30854 --- ../lighttpd-1.4.11/src/mod_proxy_core_backlog.h     1970-01-01 03:00:00.000000000 +0300
30855 +++ lighttpd-1.4.12/src/mod_proxy_core_backlog.h        2006-07-18 13:03:40.000000000 +0300
30856 @@ -0,0 +1,56 @@
30857 +#ifndef _MOD_PROXY_CORE_BACKLOG_H_
30858 +#define _MOD_PROXY_CORE_BACKLOG_H_
30859 +
30860 +#include <sys/types.h>
30861 +#include <sys/time.h>
30862 +
30863 +typedef struct _proxy_request {
30864 +       void *con; /* a pointer to the client-connection, (type: connection) */
30865 +
30866 +       time_t added_ts; /* when was the entry added (for timeout handling) */
30867 +
30868 +       struct _proxy_request *next;
30869 +} proxy_request;
30870 +
30871 +/**
30872 + * a we can't get a connection from the pool, queue the request in the
30873 + * request queue (FIFO)
30874 + *
30875 + * - the queue is infinite
30876 + * - entries are removed after a timeout (status 504)
30877 + */
30878 +typedef struct {
30879 +       proxy_request *first; /* pull() does q->first = q->first->next */
30880 +       proxy_request *last; /* push() does q->last = r */
30881 +
30882 +       size_t length;
30883 +} proxy_backlog;
30884 +
30885 +proxy_backlog *proxy_backlog_init(void);
30886 +void proxy_backlog_free(proxy_backlog *backlog);
30887 +
30888 +/**
30889 + * append a request to the end
30890 + * 
30891 + * @return 0 in success, -1 if full
30892 + */ 
30893 +int proxy_backlog_push(proxy_backlog *backlog, proxy_request *req);
30894 +
30895 +/**
30896 + * remove the first request from the backlog
30897 + *
30898 + * @return NULL if backlog is empty, the request otherwise
30899 + */
30900 +proxy_request *proxy_backlog_shift(proxy_backlog *backlog);
30901 +/**
30902 + * remove the request with the connection 'con' from the backlog
30903 + *
30904 + * @return -1 if not found, 0 otherwise
30905 + */
30906 +int proxy_backlog_remove_connection(proxy_backlog *backlog, void *con);
30907 +
30908 +proxy_request *proxy_request_init(void);
30909 +void proxy_request_free(proxy_request *req);
30910 +
30911 +#endif
30912 +
30913 --- ../lighttpd-1.4.11/src/mod_proxy_core_pool.c        1970-01-01 03:00:00.000000000 +0300
30914 +++ lighttpd-1.4.12/src/mod_proxy_core_pool.c   2006-07-18 13:03:40.000000000 +0300
30915 @@ -0,0 +1,127 @@
30916 +
30917 +#include <stdlib.h>
30918 +
30919 +#include "array-static.h"
30920 +#include "sys-files.h"
30921 +#include "log.h"
30922 +#include "mod_proxy_core_pool.h"
30923 +
30924 +proxy_connection * proxy_connection_init(void) {
30925 +       proxy_connection *con;
30926 +
30927 +       con = calloc(1, sizeof(*con));
30928 +
30929 +       con->sock = iosocket_init();
30930 +
30931 +       return con;
30932 +}
30933 +
30934 +void proxy_connection_free(proxy_connection *con) {
30935 +       if (!con) return;
30936 +
30937 +       iosocket_free(con->sock);
30938 +
30939 +       free(con);
30940 +}
30941 +
30942 +proxy_connection_pool *proxy_connection_pool_init(void) {
30943 +       proxy_connection_pool *pool;
30944 +
30945 +       pool = calloc(1, sizeof(*pool));
30946 +
30947 +               /* default: max parallel connections to the backend
30948 +        * 
30949 +        * this should match max-procs if we manage the procs ourself
30950 +                */
30951 +
30952 +       pool->max_size = 8;
30953 +
30954 +       return pool;
30955 +}
30956 +
30957 +void proxy_connection_pool_free(proxy_connection_pool *pool) {
30958 +       size_t i;
30959 +
30960 +       if (!pool) return;
30961 +
30962 +       for (i = 0; i < pool->used; i++) {
30963 +               proxy_connection_free(pool->ptr[i]);
30964 +       }
30965 +
30966 +       if (pool->size) free(pool->ptr);
30967 +
30968 +       free(pool);
30969 +}
30970 +
30971 +void proxy_connection_pool_add_connection(proxy_connection_pool *pool, proxy_connection *c) {
30972 +       ARRAY_STATIC_PREPARE_APPEND(pool);
30973 +
30974 +       pool->ptr[pool->used++] = c;
30975 +}
30976 +/**
30977 + * remove the connection from the pool
30978 + *
30979 + * usually called on conn-shutdown
30980 + */
30981 +int proxy_connection_pool_remove_connection(proxy_connection_pool *pool, proxy_connection *c) {
30982 +       size_t i;
30983 +
30984 +       if (pool->used == 0) return -1; /* empty */
30985 +
30986 +       for (i = 0; i < pool->used; i++) {
30987 +               if (pool->ptr[i] == c) {
30988 +                       break;
30989 +               }
30990 +       }
30991 +
30992 +       if (i == pool->used) return -1; /* not found */
30993 +
30994 +       /**
30995 +        * move all elements one to the left
30996 +        *
30997 +        * if the last element is going to be removed, skip the loop
30998 +        */
30999 +       for (; i < pool->used - 1; i++) {
31000 +               pool->ptr[i] = pool->ptr[i + 1];
31001 +       }
31002 +
31003 +       pool->used--;
31004 +
31005 +       return 0;
31006 +}
31007 +
31008 +proxy_connection_pool_t proxy_connection_pool_get_connection(proxy_connection_pool *pool, proxy_address *address, proxy_connection **rcon) {
31009 +       proxy_connection *proxy_con = NULL;
31010 +       size_t i;
31011 +
31012 +       /* search for a idling proxy connection with the given address */
31013 +       for (i = 0; i < pool->used; i++) {
31014 +               proxy_con = pool->ptr[i];
31015 +
31016 +               if (proxy_con->address == address &&
31017 +                   proxy_con->state == PROXY_CONNECTION_STATE_IDLE) {
31018 +                       break;
31019 +               }
31020 +       }
31021 +
31022 +       if (i == pool->used) {
31023 +               /* no idling connection found */
31024 +
31025 +               if (pool->used == pool->max_size) return PROXY_CONNECTIONPOOL_FULL;
31026 +               
31027 +               proxy_con = proxy_connection_init();
31028 +
31029 +               proxy_con->state = PROXY_CONNECTION_STATE_CONNECTING;
31030 +               proxy_con->address = address;
31031 +
31032 +               proxy_connection_pool_add_connection(pool, proxy_con);
31033 +       } else {
31034 +               proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
31035 +       }
31036 +
31037 +       *rcon = proxy_con;
31038 +
31039 +       return PROXY_CONNECTIONPOOL_GOT_CONNECTION;
31040 +}
31041 +
31042 +
31043 --- ../lighttpd-1.4.11/src/mod_proxy_core_pool.h        1970-01-01 03:00:00.000000000 +0300
31044 +++ lighttpd-1.4.12/src/mod_proxy_core_pool.h   2006-07-18 13:03:40.000000000 +0300
31045 @@ -0,0 +1,52 @@
31046 +#ifndef _MOD_PROXY_CORE_POOL_H_
31047 +#define _MOD_PROXY_CORE_POOL_H_
31048 +
31049 +#include <sys/time.h>
31050 +
31051 +#include "iosocket.h"
31052 +#include "array-static.h"
31053 +#include "mod_proxy_core_address.h"
31054 +
31055 +typedef enum {
31056 +       PROXY_CONNECTION_STATE_UNSET,
31057 +       PROXY_CONNECTION_STATE_CONNECTING,
31058 +       PROXY_CONNECTION_STATE_CONNECTED,
31059 +       PROXY_CONNECTION_STATE_IDLE,
31060 +       PROXY_CONNECTION_STATE_CLOSED,
31061 +} proxy_connection_state_t;
31062 +
31063 +/**
31064 + * a connection to a proxy backend
31065 + * 
31066 + * the connection is independent of the incoming request to allow keep-alive
31067 + */
31068 +typedef struct { 
31069 +       iosocket *sock;
31070 +
31071 +       time_t last_read; /* timeout handling for keep-alive connections */
31072 +       time_t last_write;
31073 +
31074 +       proxy_address *address; /* the struct sock_addr for the sock */
31075 +
31076 +       proxy_connection_state_t state;
31077 +} proxy_connection;
31078 +
31079 +ARRAY_STATIC_DEF(proxy_connection_pool, proxy_connection, size_t max_size;);
31080 +
31081 +typedef enum {
31082 +       PROXY_CONNECTIONPOOL_UNSET,
31083 +       PROXY_CONNECTIONPOOL_FULL,
31084 +       PROXY_CONNECTIONPOOL_GOT_CONNECTION,
31085 +} proxy_connection_pool_t;
31086 +
31087 +proxy_connection_pool *proxy_connection_pool_init(void); 
31088 +void proxy_connection_pool_free(proxy_connection_pool *pool); 
31089 +
31090 +proxy_connection_pool_t proxy_connection_pool_get_connection(proxy_connection_pool *pool, proxy_address *address, proxy_connection **rcon);
31091 +int proxy_connection_pool_remove_connection(proxy_connection_pool *pool, proxy_connection *c);
31092 +
31093 +proxy_connection * proxy_connection_init(void);
31094 +void proxy_connection_free(proxy_connection *pool);
31095 +
31096 +#endif
31097 +
31098 --- ../lighttpd-1.4.11/src/mod_proxy_core_rewrites.c    1970-01-01 03:00:00.000000000 +0300
31099 +++ lighttpd-1.4.12/src/mod_proxy_core_rewrites.c       2006-07-18 17:34:32.000000000 +0300
31100 @@ -0,0 +1,64 @@
31101 +#include <stdlib.h>
31102 +#include <string.h>
31103 +
31104 +#include "mod_proxy_core_rewrites.h"
31105 +#include "log.h"
31106 +
31107 +proxy_rewrite *proxy_rewrite_init(void) {
31108 +       STRUCT_INIT(proxy_rewrite, rewrite);
31109 +
31110 +       rewrite->header = buffer_init();
31111 +       rewrite->match = buffer_init();
31112 +       rewrite->replace = buffer_init();
31113 +
31114 +       return rewrite;
31115 +
31116 +}
31117 +void proxy_rewrite_free(proxy_rewrite *rewrite) {
31118 +       if (!rewrite) return;
31119 +
31120 +       if (rewrite->regex) pcre_free(rewrite->regex);
31121 +
31122 +       buffer_free(rewrite->header);
31123 +       buffer_free(rewrite->match);
31124 +       buffer_free(rewrite->replace);
31125 +
31126 +       free(rewrite);
31127 +}
31128 +
31129 +int proxy_rewrite_set_regex(proxy_rewrite *rewrite, buffer *regex) {
31130 +       const char *errptr;
31131 +       int erroff;
31132 +
31133 +       if (NULL == (rewrite->regex = pcre_compile(BUF_STR(regex),
31134 +                 0, &errptr, &erroff, NULL))) {
31135 +               
31136 +               TRACE("regex compilation for %s failed at %s", BUF_STR(regex), errptr);
31137 +
31138 +               return -1;
31139 +       }
31140 +
31141 +       return 0;
31142 +}
31143 +
31144 +
31145 +proxy_rewrites *proxy_rewrites_init(void) {
31146 +       STRUCT_INIT(proxy_rewrites, rewrites);
31147 +
31148 +       return rewrites;
31149 +}
31150 +
31151 +void proxy_rewrites_add(proxy_rewrites *rewrites, proxy_rewrite *rewrite) {
31152 +       ARRAY_STATIC_PREPARE_APPEND(rewrites);
31153 +
31154 +       rewrites->ptr[rewrites->used++] = rewrite;
31155 +}
31156 +
31157 +void proxy_rewrites_free(proxy_rewrites *rewrites) {
31158 +       if (!rewrites) return;
31159 +
31160 +       free(rewrites);
31161 +}
31162 +
31163 +
31164 +
31165 --- ../lighttpd-1.4.11/src/mod_proxy_core_rewrites.h    1970-01-01 03:00:00.000000000 +0300
31166 +++ lighttpd-1.4.12/src/mod_proxy_core_rewrites.h       2006-07-18 17:34:32.000000000 +0300
31167 @@ -0,0 +1,28 @@
31168 +#ifndef _MOD_PROXY_CORE_REWRITES_H_
31169 +#define _MOD_PROXY_CORE_REWRITES_H_
31170 +
31171 +#include <pcre.h>
31172 +#include "array-static.h"
31173 +#include "buffer.h"
31174 +
31175 +typedef struct {
31176 +       buffer *header;
31177 +
31178 +       pcre *regex; /* regex compiled from the <match> */
31179 +
31180 +       buffer *match;
31181 +       buffer *replace;
31182 +} proxy_rewrite;
31183 +
31184 +ARRAY_STATIC_DEF(proxy_rewrites, proxy_rewrite,);
31185 +
31186 +proxy_rewrite *proxy_rewrite_init(void);
31187 +void proxy_rewrite_free(proxy_rewrite *rewrite);
31188 +int proxy_rewrite_set_regex(proxy_rewrite *rewrite, buffer *regex);
31189 +
31190 +proxy_rewrites *proxy_rewrites_init(void);
31191 +void proxy_rewrites_add(proxy_rewrites *rewrites, proxy_rewrite *rewrite);
31192 +void proxy_rewrites_free(proxy_rewrites *rewrites);
31193 +
31194 +#endif
31195 +
31196 --- ../lighttpd-1.4.11/src/mod_redirect.c       2006-02-08 15:38:06.000000000 +0200
31197 +++ lighttpd-1.4.12/src/mod_redirect.c  2006-07-16 00:26:04.000000000 +0300
31198 @@ -22,35 +22,35 @@
31199         PLUGIN_DATA;
31200         buffer *match_buf;
31201         buffer *location;
31202 -       
31203 +
31204         plugin_config **config_storage;
31205 -       
31206 -       plugin_config conf; 
31207 +
31208 +       plugin_config conf;
31209  } plugin_data;
31210  
31211  INIT_FUNC(mod_redirect_init) {
31212         plugin_data *p;
31213 -       
31214 +
31215         p = calloc(1, sizeof(*p));
31216 -       
31217 +
31218         p->match_buf = buffer_init();
31219         p->location = buffer_init();
31220 -       
31221 +
31222         return p;
31223  }
31224  
31225  FREE_FUNC(mod_redirect_free) {
31226         plugin_data *p = p_d;
31227 -       
31228 +
31229         if (!p) return HANDLER_GO_ON;
31230  
31231         if (p->config_storage) {
31232                 size_t i;
31233                 for (i = 0; i < srv->config_context->used; i++) {
31234                         plugin_config *s = p->config_storage[i];
31235 -                       
31236 +
31237                         pcre_keyvalue_buffer_free(s->redirect);
31238 -                       
31239 +
31240                         free(s);
31241                 }
31242                 free(p->config_storage);
31243 @@ -59,9 +59,9 @@
31244  
31245         buffer_free(p->match_buf);
31246         buffer_free(p->location);
31247 -       
31248 +
31249         free(p);
31250 -       
31251 +
31252         return HANDLER_GO_ON;
31253  }
31254  
31255 @@ -69,195 +69,137 @@
31256         plugin_data *p = p_d;
31257         data_unset *du;
31258         size_t i = 0;
31259 -       
31260 -       config_values_t cv[] = { 
31261 +
31262 +       config_values_t cv[] = {
31263                 { "url.redirect",               NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
31264                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
31265         };
31266 -       
31267 +
31268         if (!p) return HANDLER_ERROR;
31269 -       
31270 +
31271         /* 0 */
31272         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
31273 -       
31274 +
31275         for (i = 0; i < srv->config_context->used; i++) {
31276                 plugin_config *s;
31277                 size_t j;
31278                 array *ca;
31279                 data_array *da = (data_array *)du;
31280 -               
31281 +
31282                 s = calloc(1, sizeof(plugin_config));
31283                 s->redirect   = pcre_keyvalue_buffer_init();
31284 -               
31285 +
31286                 cv[0].destination = s->redirect;
31287 -               
31288 +
31289                 p->config_storage[i] = s;
31290                 ca = ((data_config *)srv->config_context->data[i])->value;
31291 -       
31292 +
31293                 if (0 != config_insert_values_global(srv, ca, cv)) {
31294                         return HANDLER_ERROR;
31295                 }
31296 -               
31297 +
31298                 if (NULL == (du = array_get_element(ca, "url.redirect"))) {
31299                         /* no url.redirect defined */
31300                         continue;
31301                 }
31302 -               
31303 +
31304                 if (du->type != TYPE_ARRAY) {
31305 -                       log_error_write(srv, __FILE__, __LINE__, "sss", 
31306 +                       log_error_write(srv, __FILE__, __LINE__, "sss",
31307                                         "unexpected type for key: ", "url.redirect", "array of strings");
31308 -                       
31309 +
31310                         return HANDLER_ERROR;
31311                 }
31312 -               
31313 +
31314                 da = (data_array *)du;
31315 -                               
31316 +
31317                 for (j = 0; j < da->value->used; j++) {
31318                         if (da->value->data[j]->type != TYPE_STRING) {
31319 -                               log_error_write(srv, __FILE__, __LINE__, "sssbs", 
31320 -                                               "unexpected type for key: ", 
31321 -                                               "url.redirect", 
31322 +                               log_error_write(srv, __FILE__, __LINE__, "sssbs",
31323 +                                               "unexpected type for key: ",
31324 +                                               "url.redirect",
31325                                                 "[", da->value->data[j]->key, "](string)");
31326 -                               
31327 +
31328                                 return HANDLER_ERROR;
31329                         }
31330 -                               
31331 -                       if (0 != pcre_keyvalue_buffer_append(s->redirect, 
31332 +
31333 +                       if (0 != pcre_keyvalue_buffer_append(s->redirect,
31334                                                              ((data_string *)(da->value->data[j]))->key->ptr,
31335                                                              ((data_string *)(da->value->data[j]))->value->ptr)) {
31336 -                                       
31337 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
31338 +
31339 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
31340                                                 "pcre-compile failed for", da->value->data[j]->key);
31341                         }
31342                 }
31343         }
31344 -       
31345 +
31346         return HANDLER_GO_ON;
31347  }
31348  #ifdef HAVE_PCRE_H
31349  static int mod_redirect_patch_connection(server *srv, connection *con, plugin_data *p) {
31350         size_t i, j;
31351         plugin_config *s = p->config_storage[0];
31352 -       
31353 +
31354         p->conf.redirect = s->redirect;
31355 -       
31356 +
31357         /* skip the first, the global context */
31358         for (i = 1; i < srv->config_context->used; i++) {
31359                 data_config *dc = (data_config *)srv->config_context->data[i];
31360                 s = p->config_storage[i];
31361 -               
31362 +
31363                 /* condition didn't match */
31364                 if (!config_check_cond(srv, con, dc)) continue;
31365 -               
31366 +
31367                 /* merge config */
31368                 for (j = 0; j < dc->value->used; j++) {
31369                         data_unset *du = dc->value->data[j];
31370 -                       
31371 +
31372                         if (0 == strcmp(du->key->ptr, "url.redirect")) {
31373                                 p->conf.redirect = s->redirect;
31374                                 p->conf.context = dc;
31375                         }
31376                 }
31377         }
31378 -       
31379 +
31380         return 0;
31381  }
31382  #endif
31383  static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_data) {
31384  #ifdef HAVE_PCRE_H
31385         plugin_data *p = p_data;
31386 -       size_t i;
31387 +       int i;
31388  
31389 -       /* 
31390 +       /*
31391          * REWRITE URL
31392 -        * 
31393 +        *
31394          * e.g. redirect /base/ to /index.php?section=base
31395 -        * 
31396 +        *
31397          */
31398 -       
31399 +
31400         mod_redirect_patch_connection(srv, con, p);
31401 -       
31402 +
31403         buffer_copy_string_buffer(p->match_buf, con->request.uri);
31404 -       
31405 -       for (i = 0; i < p->conf.redirect->used; i++) {
31406 -               pcre *match;
31407 -               pcre_extra *extra;
31408 -               const char *pattern;
31409 -               size_t pattern_len;
31410 -               int n;
31411 -               pcre_keyvalue *kv = p->conf.redirect->kv[i];
31412 -# define N 10
31413 -               int ovec[N * 3];
31414 -               
31415 -               match       = kv->key;
31416 -               extra       = kv->key_extra;
31417 -               pattern     = kv->value->ptr;
31418 -               pattern_len = kv->value->used - 1;
31419 -               
31420 -               if ((n = pcre_exec(match, extra, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
31421 -                       if (n != PCRE_ERROR_NOMATCH) {
31422 -                               log_error_write(srv, __FILE__, __LINE__, "sd",
31423 -                                               "execution error while matching: ", n);
31424 -                               return HANDLER_ERROR;
31425 -                       }
31426 -               } else {
31427 -                       const char **list;
31428 -                       size_t start, end;
31429 -                       size_t k;
31430 -                       
31431 -                       /* it matched */
31432 -                       pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list);
31433 -                       
31434 -                       /* search for $[0-9] */
31435 -                       
31436 -                       buffer_reset(p->location);
31437 -                       
31438 -                       start = 0; end = pattern_len;
31439 -                       for (k = 0; k < pattern_len; k++) {
31440 -                               if ((pattern[k] == '$' || pattern[k] == '%') &&
31441 -                                   isdigit((unsigned char)pattern[k + 1])) {
31442 -                                       /* got one */
31443 -                                       
31444 -                                       size_t num = pattern[k + 1] - '0';
31445 -                                       
31446 -                                       end = k;
31447 -                                       
31448 -                                       buffer_append_string_len(p->location, pattern + start, end - start);
31449 -                                       
31450 -                                       if (pattern[k] == '$') {
31451 -                                               /* n is always > 0 */
31452 -                                               if (num < (size_t)n) {
31453 -                                                       buffer_append_string(p->location, list[num]);
31454 -                                               }
31455 -                                       } else {
31456 -                                               config_append_cond_match_buffer(con, p->conf.context, p->location, num);
31457 -                                       }
31458 -                                       
31459 -                                       k++;
31460 -                                       start = k + 1;
31461 -                               } 
31462 -                       }
31463 -                       
31464 -                       buffer_append_string_len(p->location, pattern + start, pattern_len - start);
31465 -                       
31466 -                       pcre_free(list);
31467 -                       
31468 -                       response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location));
31469 -                       
31470 -                       con->http_status = 301;
31471 -                       con->file_finished = 1;
31472 -                       
31473 -                       return HANDLER_FINISHED;
31474 -               }
31475 +       i = config_exec_pcre_keyvalue_buffer(con, p->conf.redirect, p->conf.context, p->match_buf, p->location);
31476 +
31477 +       if (i >= 0) {
31478 +               response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location));
31479 +
31480 +               con->http_status = 301;
31481 +               con->file_finished = 1;
31482 +
31483 +               return HANDLER_FINISHED;
31484 +       }
31485 +       else if (i != PCRE_ERROR_NOMATCH) {
31486 +               log_error_write(srv, __FILE__, __LINE__, "s",
31487 +                               "execution error while matching", i);
31488         }
31489  #undef N
31490 -               
31491 +
31492  #else
31493         UNUSED(srv);
31494         UNUSED(con);
31495         UNUSED(p_data);
31496  #endif
31497 -       
31498 +
31499         return HANDLER_GO_ON;
31500  }
31501  
31502 @@ -265,13 +207,13 @@
31503  int mod_redirect_plugin_init(plugin *p) {
31504         p->version     = LIGHTTPD_VERSION_ID;
31505         p->name        = buffer_init_string("redirect");
31506 -       
31507 +
31508         p->init        = mod_redirect_init;
31509         p->handle_uri_clean  = mod_redirect_uri_handler;
31510         p->set_defaults  = mod_redirect_set_defaults;
31511         p->cleanup     = mod_redirect_free;
31512 -       
31513 +
31514         p->data        = NULL;
31515 -       
31516 +
31517         return 0;
31518  }
31519 --- ../lighttpd-1.4.11/src/mod_rewrite.c        2005-09-29 20:59:10.000000000 +0300
31520 +++ lighttpd-1.4.12/src/mod_rewrite.c   2006-07-16 00:26:03.000000000 +0300
31521 @@ -13,24 +13,8 @@
31522  #endif
31523  
31524  typedef struct {
31525 -#ifdef HAVE_PCRE_H
31526 -       pcre *key;
31527 -#endif
31528 -       
31529 -       buffer *value;
31530 -       
31531 -       int once;
31532 -} rewrite_rule;
31533 -
31534 -typedef struct {
31535 -       rewrite_rule **ptr;
31536 -       
31537 -       size_t used;
31538 -       size_t size;
31539 -} rewrite_rule_buffer;
31540 -
31541 -typedef struct {
31542 -       rewrite_rule_buffer *rewrite;
31543 +       pcre_keyvalue_buffer *rewrite;
31544 +       buffer *once;
31545         data_config *context; /* to which apply me */
31546  } plugin_config;
31547  
31548 @@ -42,20 +26,20 @@
31549  typedef struct {
31550         PLUGIN_DATA;
31551         buffer *match_buf;
31552 -       
31553 +
31554         plugin_config **config_storage;
31555 -       
31556 -       plugin_config conf; 
31557 +
31558 +       plugin_config conf;
31559  } plugin_data;
31560  
31561  static handler_ctx * handler_ctx_init() {
31562         handler_ctx * hctx;
31563 -       
31564 +
31565         hctx = calloc(1, sizeof(*hctx));
31566 -       
31567 +
31568         hctx->state = REWRITE_STATE_UNSET;
31569         hctx->loops = 0;
31570 -       
31571 +
31572         return hctx;
31573  }
31574  
31575 @@ -63,207 +47,136 @@
31576         free(hctx);
31577  }
31578  
31579 -rewrite_rule_buffer *rewrite_rule_buffer_init(void) {
31580 -       rewrite_rule_buffer *kvb;
31581 -       
31582 -       kvb = calloc(1, sizeof(*kvb));
31583 -       
31584 -       return kvb;
31585 -}
31586 -
31587 -int rewrite_rule_buffer_append(rewrite_rule_buffer *kvb, buffer *key, buffer *value, int once) {
31588 -#ifdef HAVE_PCRE_H
31589 -       size_t i;
31590 -       const char *errptr;
31591 -       int erroff;
31592 -       
31593 -       if (!key) return -1;
31594 -
31595 -       if (kvb->size == 0) {
31596 -               kvb->size = 4;
31597 -               kvb->used = 0;
31598 -               
31599 -               kvb->ptr = malloc(kvb->size * sizeof(*kvb->ptr));
31600 -               
31601 -               for(i = 0; i < kvb->size; i++) {
31602 -                       kvb->ptr[i] = calloc(1, sizeof(**kvb->ptr));
31603 -               }
31604 -       } else if (kvb->used == kvb->size) {
31605 -               kvb->size += 4;
31606 -               
31607 -               kvb->ptr = realloc(kvb->ptr, kvb->size * sizeof(*kvb->ptr));
31608 -               
31609 -               for(i = kvb->used; i < kvb->size; i++) {
31610 -                       kvb->ptr[i] = calloc(1, sizeof(**kvb->ptr));
31611 -               }
31612 -       }
31613 -       
31614 -       if (NULL == (kvb->ptr[kvb->used]->key = pcre_compile(key->ptr,
31615 -                                                           0, &errptr, &erroff, NULL))) {
31616 -               
31617 -               return -1;
31618 -       }
31619 -       
31620 -       kvb->ptr[kvb->used]->value = buffer_init();
31621 -       buffer_copy_string_buffer(kvb->ptr[kvb->used]->value, value);
31622 -       kvb->ptr[kvb->used]->once = once;
31623 -       
31624 -       kvb->used++;
31625 -       
31626 -       return 0;
31627 -#else
31628 -       UNUSED(kvb);
31629 -       UNUSED(value);
31630 -       UNUSED(once);
31631 -       UNUSED(key);
31632 -
31633 -       return -1;
31634 -#endif
31635 -}
31636 -
31637 -void rewrite_rule_buffer_free(rewrite_rule_buffer *kvb) {
31638 -#ifdef HAVE_PCRE_H
31639 -       size_t i;
31640 -
31641 -       for (i = 0; i < kvb->size; i++) {
31642 -               if (kvb->ptr[i]->key) pcre_free(kvb->ptr[i]->key);
31643 -               if (kvb->ptr[i]->value) buffer_free(kvb->ptr[i]->value);
31644 -               free(kvb->ptr[i]);
31645 -       }
31646 -       
31647 -       if (kvb->ptr) free(kvb->ptr);
31648 -#endif
31649 -       
31650 -       free(kvb);
31651 -}
31652 -
31653  
31654  INIT_FUNC(mod_rewrite_init) {
31655         plugin_data *p;
31656 -       
31657 +
31658         p = calloc(1, sizeof(*p));
31659 -       
31660 +
31661         p->match_buf = buffer_init();
31662 -       
31663 +
31664         return p;
31665  }
31666  
31667  FREE_FUNC(mod_rewrite_free) {
31668         plugin_data *p = p_d;
31669 -       
31670 +
31671         UNUSED(srv);
31672  
31673         if (!p) return HANDLER_GO_ON;
31674 -       
31675 +
31676         buffer_free(p->match_buf);
31677         if (p->config_storage) {
31678                 size_t i;
31679                 for (i = 0; i < srv->config_context->used; i++) {
31680                         plugin_config *s = p->config_storage[i];
31681 -                       rewrite_rule_buffer_free(s->rewrite);
31682 -                       
31683 +                       pcre_keyvalue_buffer_free(s->rewrite);
31684 +                       buffer_free(s->once);
31685 +
31686                         free(s);
31687                 }
31688                 free(p->config_storage);
31689         }
31690 -       
31691 +
31692         free(p);
31693 -       
31694 +
31695         return HANDLER_GO_ON;
31696  }
31697  
31698  static int parse_config_entry(server *srv, plugin_config *s, array *ca, const char *option, int once) {
31699         data_unset *du;
31700 -       
31701 +
31702         if (NULL != (du = array_get_element(ca, option))) {
31703                 data_array *da = (data_array *)du;
31704                 size_t j;
31705 -               
31706 +
31707                 if (du->type != TYPE_ARRAY) {
31708 -                       log_error_write(srv, __FILE__, __LINE__, "sss", 
31709 +                       log_error_write(srv, __FILE__, __LINE__, "sss",
31710                                         "unexpected type for key: ", option, "array of strings");
31711 -                       
31712 +
31713                         return HANDLER_ERROR;
31714                 }
31715 -               
31716 +
31717                 da = (data_array *)du;
31718 -               
31719 +
31720                 for (j = 0; j < da->value->used; j++) {
31721                         if (da->value->data[j]->type != TYPE_STRING) {
31722 -                               log_error_write(srv, __FILE__, __LINE__, "sssbs", 
31723 -                                               "unexpected type for key: ", 
31724 -                                               option, 
31725 +                               log_error_write(srv, __FILE__, __LINE__, "sssbs",
31726 +                                               "unexpected type for key: ",
31727 +                                               option,
31728                                                 "[", da->value->data[j]->key, "](string)");
31729 -                               
31730 +
31731                                 return HANDLER_ERROR;
31732                         }
31733 -                       
31734 -                       if (0 != rewrite_rule_buffer_append(s->rewrite, 
31735 -                                                           ((data_string *)(da->value->data[j]))->key,
31736 -                                                           ((data_string *)(da->value->data[j]))->value,
31737 -                                                           once)) {
31738 +
31739 +                       if (0 != pcre_keyvalue_buffer_append(s->rewrite,
31740 +                                                           ((data_string *)(da->value->data[j]))->key->ptr,
31741 +                                                           ((data_string *)(da->value->data[j]))->value->ptr)) {
31742  #ifdef HAVE_PCRE_H
31743 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
31744 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
31745                                                 "pcre-compile failed for", da->value->data[j]->key);
31746  #else
31747 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
31748 +                               log_error_write(srv, __FILE__, __LINE__, "s",
31749                                                 "pcre support is missing, please install libpcre and the headers");
31750  #endif
31751                         }
31752 +
31753 +                       if (once) {
31754 +                               buffer_append_string_len(s->once, CONST_STR_LEN("1"));
31755 +                       } else {
31756 +                               buffer_append_string_len(s->once, CONST_STR_LEN("0"));
31757 +                       }
31758                 }
31759         }
31760 -       
31761 +
31762         return 0;
31763  }
31764  
31765  SETDEFAULTS_FUNC(mod_rewrite_set_defaults) {
31766         plugin_data *p = p_d;
31767         size_t i = 0;
31768 -       
31769 -       config_values_t cv[] = { 
31770 +
31771 +       config_values_t cv[] = {
31772                 { "url.rewrite-repeat",        NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
31773                 { "url.rewrite-once",          NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
31774 -               
31775 -               /* old names, still supported 
31776 -                * 
31777 +
31778 +               /* old names, still supported
31779 +                *
31780                  * url.rewrite remapped to url.rewrite-once
31781                  * url.rewrite-final    is url.rewrite-once
31782 -                * 
31783 +                *
31784                  */
31785                 { "url.rewrite",               NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
31786                 { "url.rewrite-final",         NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
31787                 { NULL,                        NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
31788         };
31789 -       
31790 +
31791         if (!p) return HANDLER_ERROR;
31792 -       
31793 +
31794         /* 0 */
31795         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
31796 -       
31797 +
31798         for (i = 0; i < srv->config_context->used; i++) {
31799                 plugin_config *s;
31800                 array *ca;
31801 -               
31802 +
31803                 s = calloc(1, sizeof(plugin_config));
31804 -               s->rewrite   = rewrite_rule_buffer_init();
31805 -               
31806 -               cv[0].destination = s->rewrite;
31807 -               cv[1].destination = s->rewrite;
31808 -               cv[2].destination = s->rewrite;
31809 -               
31810 +               s->rewrite   = pcre_keyvalue_buffer_init();
31811 +               s->once      = buffer_init();
31812 +
31813                 p->config_storage[i] = s;
31814                 ca = ((data_config *)srv->config_context->data[i])->value;
31815 -       
31816 +
31817                 if (0 != config_insert_values_global(srv, ca, cv)) {
31818                         return HANDLER_ERROR;
31819                 }
31820 -               
31821 +
31822                 parse_config_entry(srv, s, ca, "url.rewrite-once",   1);
31823                 parse_config_entry(srv, s, ca, "url.rewrite-final",  1);
31824                 parse_config_entry(srv, s, ca, "url.rewrite",        1);
31825                 parse_config_entry(srv, s, ca, "url.rewrite-repeat", 0);
31826         }
31827 -       
31828 +
31829         return HANDLER_GO_ON;
31830  }
31831  #ifdef HAVE_PCRE_H
31832 @@ -271,157 +184,107 @@
31833         size_t i, j;
31834         plugin_config *s = p->config_storage[0];
31835         p->conf.rewrite = s->rewrite;
31836 -       
31837 +       p->conf.once    = s->once;
31838 +
31839         /* skip the first, the global context */
31840         for (i = 1; i < srv->config_context->used; i++) {
31841                 data_config *dc = (data_config *)srv->config_context->data[i];
31842                 s = p->config_storage[i];
31843 -               
31844 +
31845                 if (COMP_HTTP_URL == dc->comp) continue;
31846 -               
31847 +
31848                 /* condition didn't match */
31849                 if (!config_check_cond(srv, con, dc)) continue;
31850 -               
31851 +
31852                 /* merge config */
31853                 for (j = 0; j < dc->value->used; j++) {
31854                         data_unset *du = dc->value->data[j];
31855 -                       
31856 +
31857                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite"))) {
31858                                 p->conf.rewrite = s->rewrite;
31859 +                               p->conf.once    = s->once;
31860                                 p->conf.context = dc;
31861                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-once"))) {
31862                                 p->conf.rewrite = s->rewrite;
31863 +                               p->conf.once    = s->once;
31864                                 p->conf.context = dc;
31865                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-repeat"))) {
31866                                 p->conf.rewrite = s->rewrite;
31867 +                               p->conf.once    = s->once;
31868                                 p->conf.context = dc;
31869                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-final"))) {
31870                                 p->conf.rewrite = s->rewrite;
31871 +                               p->conf.once    = s->once;
31872                                 p->conf.context = dc;
31873                         }
31874                 }
31875         }
31876 -       
31877 +
31878         return 0;
31879  }
31880  #endif
31881  URIHANDLER_FUNC(mod_rewrite_con_reset) {
31882         plugin_data *p = p_d;
31883 -       
31884 +
31885         UNUSED(srv);
31886 -       
31887 +
31888         if (con->plugin_ctx[p->id]) {
31889                 handler_ctx_free(con->plugin_ctx[p->id]);
31890                 con->plugin_ctx[p->id] = NULL;
31891         }
31892 -       
31893 +
31894         return HANDLER_GO_ON;
31895  }
31896  
31897  URIHANDLER_FUNC(mod_rewrite_uri_handler) {
31898  #ifdef HAVE_PCRE_H
31899         plugin_data *p = p_d;
31900 -       size_t i;
31901 +       int i;
31902         handler_ctx *hctx;
31903  
31904 -       /* 
31905 +       /*
31906          * REWRITE URL
31907 -        * 
31908 +        *
31909          * e.g. rewrite /base/ to /index.php?section=base
31910 -        * 
31911 +        *
31912          */
31913 -       
31914 +
31915         if (con->plugin_ctx[p->id]) {
31916                 hctx = con->plugin_ctx[p->id];
31917 -               
31918 +
31919                 if (hctx->loops++ > 100) {
31920 -                       log_error_write(srv, __FILE__, __LINE__,  "s",  
31921 +                       log_error_write(srv, __FILE__, __LINE__,  "s",
31922                                         "ENDLESS LOOP IN rewrite-rule DETECTED ... aborting request, perhaps you want to use url.rewrite-once instead of url.rewrite-repeat");
31923 -                       
31924 +
31925                         return HANDLER_ERROR;
31926                 }
31927 -               
31928 +
31929                 if (hctx->state == REWRITE_STATE_FINISHED) return HANDLER_GO_ON;
31930         }
31931 -       
31932 +
31933         mod_rewrite_patch_connection(srv, con, p);
31934  
31935         if (!p->conf.rewrite) return HANDLER_GO_ON;
31936 -       
31937 +
31938         buffer_copy_string_buffer(p->match_buf, con->request.uri);
31939 -       
31940 -       for (i = 0; i < p->conf.rewrite->used; i++) {
31941 -               pcre *match;
31942 -               const char *pattern;
31943 -               size_t pattern_len;
31944 -               int n;
31945 -               rewrite_rule *rule = p->conf.rewrite->ptr[i];
31946 -# define N 10
31947 -               int ovec[N * 3];
31948 -               
31949 -               match       = rule->key;
31950 -               pattern     = rule->value->ptr;
31951 -               pattern_len = rule->value->used - 1;
31952 -               
31953 -               if ((n = pcre_exec(match, NULL, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
31954 -                       if (n != PCRE_ERROR_NOMATCH) {
31955 -                               log_error_write(srv, __FILE__, __LINE__, "sd",
31956 -                                               "execution error while matching: ", n);
31957 -                               return HANDLER_ERROR;
31958 -                       }
31959 -               } else {
31960 -                       const char **list;
31961 -                       size_t start, end;
31962 -                       size_t k;
31963 -                       
31964 -                       /* it matched */
31965 -                       pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list);
31966 -                       
31967 -                       /* search for $[0-9] */
31968 -                       
31969 -                       buffer_reset(con->request.uri);
31970 -                       
31971 -                       start = 0; end = pattern_len;
31972 -                       for (k = 0; k < pattern_len; k++) {
31973 -                               if ((pattern[k] == '$' || pattern[k] == '%') &&
31974 -                                   isdigit((unsigned char)pattern[k + 1])) {
31975 -                                       /* got one */
31976 -                                       
31977 -                                       size_t num = pattern[k + 1] - '0';
31978 -                                       
31979 -                                       end = k;
31980 -                                       
31981 -                                       buffer_append_string_len(con->request.uri, pattern + start, end - start);
31982 -                                       
31983 -                                       if (pattern[k] == '$') {
31984 -                                               /* n is always > 0 */
31985 -                                               if (num < (size_t)n) {
31986 -                                                       buffer_append_string(con->request.uri, list[num]);
31987 -                                               }
31988 -                                       } else {
31989 -                                               config_append_cond_match_buffer(con, p->conf.context, con->request.uri, num);
31990 -                                       }
31991 -                                       
31992 -                                       k++;
31993 -                                       start = k + 1;
31994 -                               } 
31995 -                       }
31996 -                       
31997 -                       buffer_append_string_len(con->request.uri, pattern + start, pattern_len - start);
31998 -                       
31999 -                       pcre_free(list);
32000 -                       
32001 -                       hctx = handler_ctx_init();
32002 -                               
32003 -                       con->plugin_ctx[p->id] = hctx;
32004 -                       
32005 -                       if (rule->once) hctx->state = REWRITE_STATE_FINISHED;
32006 -                       
32007 -                       return HANDLER_COMEBACK;
32008 -               }
32009 +       i = config_exec_pcre_keyvalue_buffer(con, p->conf.rewrite, p->conf.context, p->match_buf, con->request.uri);
32010 +
32011 +       if (i >= 0) {
32012 +               hctx = handler_ctx_init();
32013 +
32014 +               con->plugin_ctx[p->id] = hctx;
32015 +
32016 +               if (p->conf.once->ptr[i] == '1')
32017 +                       hctx->state = REWRITE_STATE_FINISHED;
32018 +
32019 +               return HANDLER_COMEBACK;
32020 +       }
32021 +       else if (i != PCRE_ERROR_NOMATCH) {
32022 +               log_error_write(srv, __FILE__, __LINE__, "s",
32023 +                               "execution error while matching", i);
32024         }
32025  #undef N
32026 -               
32027 +
32028  #else
32029         UNUSED(srv);
32030         UNUSED(con);
32031 @@ -434,17 +297,17 @@
32032  int mod_rewrite_plugin_init(plugin *p) {
32033         p->version     = LIGHTTPD_VERSION_ID;
32034         p->name        = buffer_init_string("rewrite");
32035 -       
32036 +
32037         p->init        = mod_rewrite_init;
32038         /* it has to stay _raw as we are matching on uri + querystring
32039          */
32040 -       
32041 +
32042         p->handle_uri_raw = mod_rewrite_uri_handler;
32043         p->set_defaults = mod_rewrite_set_defaults;
32044         p->cleanup     = mod_rewrite_free;
32045         p->connection_reset = mod_rewrite_con_reset;
32046 -       
32047 +
32048         p->data        = NULL;
32049 -       
32050 +
32051         return 0;
32052  }
32053 --- ../lighttpd-1.4.11/src/mod_rrdtool.c        2005-08-22 01:52:24.000000000 +0300
32054 +++ lighttpd-1.4.12/src/mod_rrdtool.c   2006-07-18 13:03:40.000000000 +0300
32055 @@ -5,7 +5,6 @@
32056  #include <stdlib.h>
32057  #include <stdio.h>
32058  #include <string.h>
32059 -#include <unistd.h>
32060  #include <errno.h>
32061  #include <time.h>
32062  
32063 @@ -20,10 +19,14 @@
32064  /* no need for waitpid if we don't have fork */
32065  #include <sys/wait.h>
32066  #endif
32067 +
32068 +#include "sys-files.h"
32069 +#include "sys-process.h"
32070 +
32071  typedef struct {
32072         buffer *path_rrdtool_bin;
32073         buffer *path_rrd;
32074 -       
32075 +
32076         double requests, *requests_ptr;
32077         double bytes_written, *bytes_written_ptr;
32078         double bytes_read, *bytes_read_ptr;
32079 @@ -31,84 +34,84 @@
32080  
32081  typedef struct {
32082         PLUGIN_DATA;
32083 -       
32084 +
32085         buffer *cmd;
32086         buffer *resp;
32087 -       
32088 +
32089         int read_fd, write_fd;
32090         pid_t rrdtool_pid;
32091 -       
32092 +
32093         int rrdtool_running;
32094 -       
32095 +
32096         plugin_config **config_storage;
32097         plugin_config conf;
32098  } plugin_data;
32099  
32100  INIT_FUNC(mod_rrd_init) {
32101         plugin_data *p;
32102 -       
32103 +
32104         p = calloc(1, sizeof(*p));
32105 -       
32106 +
32107         p->resp = buffer_init();
32108         p->cmd = buffer_init();
32109 -       
32110 +
32111         return p;
32112  }
32113  
32114  FREE_FUNC(mod_rrd_free) {
32115         plugin_data *p = p_d;
32116         size_t i;
32117 -       
32118 +
32119         if (!p) return HANDLER_GO_ON;
32120 -       
32121 +
32122         if (p->config_storage) {
32123                 for (i = 0; i < srv->config_context->used; i++) {
32124                         plugin_config *s = p->config_storage[i];
32125 -                       
32126 +
32127                         buffer_free(s->path_rrdtool_bin);
32128                         buffer_free(s->path_rrd);
32129 -                       
32130 +
32131                         free(s);
32132                 }
32133         }
32134         buffer_free(p->cmd);
32135         buffer_free(p->resp);
32136 -       
32137 +
32138         free(p->config_storage);
32139 -       
32140 +
32141         if (p->rrdtool_pid) {
32142                 int status;
32143                 close(p->read_fd);
32144                 close(p->write_fd);
32145 -#ifdef HAVE_FORK       
32146 +#ifdef HAVE_FORK
32147                 /* collect status */
32148                 waitpid(p->rrdtool_pid, &status, 0);
32149  #endif
32150         }
32151 -       
32152 +
32153         free(p);
32154 -       
32155 +
32156         return HANDLER_GO_ON;
32157  }
32158  
32159  int mod_rrd_create_pipe(server *srv, plugin_data *p) {
32160         pid_t pid;
32161 -       
32162 +
32163         int to_rrdtool_fds[2];
32164         int from_rrdtool_fds[2];
32165 -#ifdef HAVE_FORK       
32166 +#ifdef HAVE_FORK
32167         if (pipe(to_rrdtool_fds)) {
32168 -               log_error_write(srv, __FILE__, __LINE__, "ss", 
32169 +               log_error_write(srv, __FILE__, __LINE__, "ss",
32170                                 "pipe failed: ", strerror(errno));
32171                 return -1;
32172         }
32173 -       
32174 +
32175         if (pipe(from_rrdtool_fds)) {
32176 -               log_error_write(srv, __FILE__, __LINE__, "ss", 
32177 +               log_error_write(srv, __FILE__, __LINE__, "ss",
32178                                 "pipe failed: ", strerror(errno));
32179                 return -1;
32180         }
32181 -       
32182 +
32183         /* fork, execve */
32184         switch (pid = fork()) {
32185         case 0: {
32186 @@ -117,33 +120,28 @@
32187                 int argc;
32188                 int i = 0;
32189                 char *dash = "-";
32190 -               
32191 +
32192                 /* move stdout to from_rrdtool_fd[1] */
32193                 close(STDOUT_FILENO);
32194                 dup2(from_rrdtool_fds[1], STDOUT_FILENO);
32195                 close(from_rrdtool_fds[1]);
32196                 /* not needed */
32197                 close(from_rrdtool_fds[0]);
32198 -               
32199 +
32200                 /* move the stdin to to_rrdtool_fd[0] */
32201                 close(STDIN_FILENO);
32202                 dup2(to_rrdtool_fds[0], STDIN_FILENO);
32203                 close(to_rrdtool_fds[0]);
32204                 /* not needed */
32205                 close(to_rrdtool_fds[1]);
32206 -               
32207 +
32208                 close(STDERR_FILENO);
32209 -               
32210 -               if (srv->errorlog_mode == ERRORLOG_FILE) {
32211 -                       dup2(srv->errorlog_fd, STDERR_FILENO);
32212 -                       close(srv->errorlog_fd);
32213 -               }
32214 -               
32215 +
32216                 /* set up args */
32217                 argc = 3;
32218                 args = malloc(sizeof(*args) * argc);
32219                 i = 0;
32220 -               
32221 +
32222                 args[i++] = p->conf.path_rrdtool_bin->ptr;
32223                 args[i++] = dash;
32224                 args[i++] = NULL;
32225 @@ -152,12 +150,12 @@
32226                 for (i = 3; i < 256; i++) {
32227                         close(i);
32228                 }
32229 -               
32230 +
32231                 /* exec the cgi */
32232                 execv(args[0], args);
32233 -               
32234 +
32235                 log_error_write(srv, __FILE__, __LINE__, "sss", "spawing rrdtool failed: ", strerror(errno), args[0]);
32236 -               
32237 +
32238                 /* */
32239                 SEGFAULT();
32240                 break;
32241 @@ -168,19 +166,19 @@
32242                 break;
32243         default: {
32244                 /* father */
32245 -               
32246 +
32247                 close(from_rrdtool_fds[1]);
32248                 close(to_rrdtool_fds[0]);
32249 -               
32250 +
32251                 /* register PID and wait for them asyncronously */
32252                 p->write_fd = to_rrdtool_fds[1];
32253                 p->read_fd = from_rrdtool_fds[0];
32254                 p->rrdtool_pid = pid;
32255 -               
32256 +
32257                 break;
32258         }
32259         }
32260 -       
32261 +
32262         return 0;
32263  #else
32264         return -1;
32265 @@ -189,19 +187,19 @@
32266  
32267  static int mod_rrdtool_create_rrd(server *srv, plugin_data *p, plugin_config *s) {
32268         struct stat st;
32269 -       
32270 +
32271         /* check if DB already exists */
32272         if (0 == stat(s->path_rrd->ptr, &st)) {
32273                 /* check if it is plain file */
32274                 if (!S_ISREG(st.st_mode)) {
32275 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
32276 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
32277                                         "not a regular file:", s->path_rrd);
32278                         return HANDLER_ERROR;
32279                 }
32280         } else {
32281                 int r ;
32282                 /* create a new one */
32283 -               
32284 +
32285                 BUFFER_COPY_STRING_CONST(p->cmd, "create ");
32286                 buffer_append_string_buffer(p->cmd, s->path_rrd);
32287                 buffer_append_string(p->cmd, " --step 60 ");
32288 @@ -220,158 +218,155 @@
32289                 buffer_append_string(p->cmd, "RRA:MIN:0.5:6:700 ");
32290                 buffer_append_string(p->cmd, "RRA:MIN:0.5:24:775 ");
32291                 buffer_append_string(p->cmd, "RRA:MIN:0.5:288:797\n");
32292 -               
32293 +
32294                 if (-1 == (r = write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
32295 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
32296 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
32297                                 "rrdtool-write: failed", strerror(errno));
32298 -                       
32299 +
32300                         return HANDLER_ERROR;
32301                 }
32302 -               
32303 +
32304                 buffer_prepare_copy(p->resp, 4096);
32305                 if (-1 == (r = read(p->read_fd, p->resp->ptr, p->resp->size))) {
32306 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
32307 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
32308                                 "rrdtool-read: failed", strerror(errno));
32309 -                       
32310 +
32311                         return HANDLER_ERROR;
32312                 }
32313 -               
32314 +
32315                 p->resp->used = r;
32316 -               
32317 +
32318                 if (p->resp->ptr[0] != 'O' ||
32319                     p->resp->ptr[1] != 'K') {
32320 -                       log_error_write(srv, __FILE__, __LINE__, "sbb", 
32321 +                       log_error_write(srv, __FILE__, __LINE__, "sbb",
32322                                 "rrdtool-response:", p->cmd, p->resp);
32323 -                       
32324 +
32325                         return HANDLER_ERROR;
32326                 }
32327         }
32328 -       
32329 +
32330         return HANDLER_GO_ON;
32331  }
32332  
32333 -#define PATCH(x) \
32334 -       p->conf.x = s->x;
32335  static int mod_rrd_patch_connection(server *srv, connection *con, plugin_data *p) {
32336         size_t i, j;
32337         plugin_config *s = p->config_storage[0];
32338 -       
32339 -       PATCH(path_rrdtool_bin);
32340 -       PATCH(path_rrd);
32341 -       
32342 +
32343 +       PATCH_OPTION(path_rrdtool_bin);
32344 +       PATCH_OPTION(path_rrd);
32345 +
32346         p->conf.bytes_written_ptr = &(s->bytes_written);
32347         p->conf.bytes_read_ptr = &(s->bytes_read);
32348         p->conf.requests_ptr = &(s->requests);
32349 -       
32350 +
32351         /* skip the first, the global context */
32352         for (i = 1; i < srv->config_context->used; i++) {
32353                 data_config *dc = (data_config *)srv->config_context->data[i];
32354                 s = p->config_storage[i];
32355 -               
32356 +
32357                 /* condition didn't match */
32358                 if (!config_check_cond(srv, con, dc)) continue;
32359 -               
32360 +
32361                 /* merge config */
32362                 for (j = 0; j < dc->value->used; j++) {
32363                         data_unset *du = dc->value->data[j];
32364 -                       
32365 +
32366                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("rrdtool.db-name"))) {
32367 -                               PATCH(path_rrd);
32368 +                               PATCH_OPTION(path_rrd);
32369                                 /* get pointers to double values */
32370 -                               
32371 +
32372                                 p->conf.bytes_written_ptr = &(s->bytes_written);
32373                                 p->conf.bytes_read_ptr = &(s->bytes_read);
32374                                 p->conf.requests_ptr = &(s->requests);
32375                         }
32376                 }
32377         }
32378 -       
32379 +
32380         return 0;
32381  }
32382 -#undef PATCH
32383  
32384  SETDEFAULTS_FUNC(mod_rrd_set_defaults) {
32385         plugin_data *p = p_d;
32386         size_t i;
32387 -       
32388 -       config_values_t cv[] = { 
32389 +
32390 +       config_values_t cv[] = {
32391                 { "rrdtool.binary",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
32392                 { "rrdtool.db-name",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
32393                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
32394         };
32395 -       
32396 +
32397         if (!p) return HANDLER_ERROR;
32398 -       
32399 +
32400         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
32401 -       
32402 +
32403         for (i = 0; i < srv->config_context->used; i++) {
32404                 plugin_config *s;
32405 -               
32406 +
32407                 s = calloc(1, sizeof(plugin_config));
32408                 s->path_rrdtool_bin = buffer_init();
32409                 s->path_rrd = buffer_init();
32410                 s->requests = 0;
32411                 s->bytes_written = 0;
32412                 s->bytes_read = 0;
32413 -               
32414 +
32415                 cv[0].destination = s->path_rrdtool_bin;
32416                 cv[1].destination = s->path_rrd;
32417 -               
32418 +
32419                 p->config_storage[i] = s;
32420 -       
32421 +
32422                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
32423                         return HANDLER_ERROR;
32424                 }
32425 -               
32426 +
32427                 if (i > 0 && !buffer_is_empty(s->path_rrdtool_bin)) {
32428                         /* path_rrdtool_bin is a global option */
32429 -                       
32430 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
32431 +
32432 +                       log_error_write(srv, __FILE__, __LINE__, "s",
32433                                         "rrdtool.binary can only be set as a global option.");
32434 -                       
32435 +
32436                         return HANDLER_ERROR;
32437                 }
32438 -               
32439 +
32440         }
32441 -       
32442 +
32443         p->conf.path_rrdtool_bin = p->config_storage[0]->path_rrdtool_bin;
32444         p->rrdtool_running = 0;
32445 -       
32446 +
32447         /* check for dir */
32448 -       
32449 +
32450         if (buffer_is_empty(p->conf.path_rrdtool_bin)) {
32451 -               log_error_write(srv, __FILE__, __LINE__, "s", 
32452 +               log_error_write(srv, __FILE__, __LINE__, "s",
32453                                 "rrdtool.binary has to be set");
32454                 return HANDLER_ERROR;
32455         }
32456 -       
32457 +
32458         /* open the pipe to rrdtool */
32459         if (mod_rrd_create_pipe(srv, p)) {
32460                 return HANDLER_ERROR;
32461         }
32462 -       
32463 +
32464         p->rrdtool_running = 1;
32465 -               
32466 +
32467         return HANDLER_GO_ON;
32468  }
32469  
32470  TRIGGER_FUNC(mod_rrd_trigger) {
32471         plugin_data *p = p_d;
32472         size_t i;
32473 -       
32474 +
32475         if (!p->rrdtool_running) return HANDLER_GO_ON;
32476         if ((srv->cur_ts % 60) != 0) return HANDLER_GO_ON;
32477 -       
32478 +
32479         for (i = 0; i < srv->config_context->used; i++) {
32480                 plugin_config *s = p->config_storage[i];
32481                 int r;
32482 -               
32483 +
32484                 if (buffer_is_empty(s->path_rrd)) continue;
32485 -       
32486 +
32487                 /* write the data down every minute */
32488 -               
32489 +
32490                 if (HANDLER_GO_ON != mod_rrdtool_create_rrd(srv, p, s)) return HANDLER_ERROR;
32491 -               
32492 +
32493                 BUFFER_COPY_STRING_CONST(p->cmd, "update ");
32494                 buffer_append_string_buffer(p->cmd, s->path_rrd);
32495                 BUFFER_APPEND_STRING_CONST(p->cmd, " N:");
32496 @@ -381,69 +376,69 @@
32497                 BUFFER_APPEND_STRING_CONST(p->cmd, ":");
32498                 buffer_append_long(p->cmd, s->requests);
32499                 BUFFER_APPEND_STRING_CONST(p->cmd, "\n");
32500 -               
32501 +
32502                 if (-1 == (r = write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
32503                         p->rrdtool_running = 0;
32504 -                       
32505 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
32506 +
32507 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
32508                                         "rrdtool-write: failed", strerror(errno));
32509 -                       
32510 +
32511                         return HANDLER_ERROR;
32512                 }
32513 -               
32514 +
32515                 buffer_prepare_copy(p->resp, 4096);
32516                 if (-1 == (r = read(p->read_fd, p->resp->ptr, p->resp->size))) {
32517                         p->rrdtool_running = 0;
32518 -                       
32519 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
32520 +
32521 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
32522                                         "rrdtool-read: failed", strerror(errno));
32523 -                       
32524 +
32525                         return HANDLER_ERROR;
32526                 }
32527 -               
32528 +
32529                 p->resp->used = r;
32530 -               
32531 +
32532                 if (p->resp->ptr[0] != 'O' ||
32533                     p->resp->ptr[1] != 'K') {
32534                         p->rrdtool_running = 0;
32535 -                       
32536 -                       log_error_write(srv, __FILE__, __LINE__, "sbb", 
32537 +
32538 +                       log_error_write(srv, __FILE__, __LINE__, "sbb",
32539                                         "rrdtool-response:", p->cmd, p->resp);
32540 -                       
32541 +
32542                         return HANDLER_ERROR;
32543                 }
32544                 s->requests = 0;
32545                 s->bytes_written = 0;
32546                 s->bytes_read = 0;
32547         }
32548 -       
32549 +
32550         return HANDLER_GO_ON;
32551  }
32552  
32553  REQUESTDONE_FUNC(mod_rrd_account) {
32554         plugin_data *p = p_d;
32555 -       
32556 +
32557         mod_rrd_patch_connection(srv, con, p);
32558 -       
32559 +
32560         *(p->conf.requests_ptr)      += 1;
32561         *(p->conf.bytes_written_ptr) += con->bytes_written;
32562         *(p->conf.bytes_read_ptr)    += con->bytes_read;
32563 -       
32564 +
32565         return HANDLER_GO_ON;
32566  }
32567  
32568  int mod_rrdtool_plugin_init(plugin *p) {
32569         p->version     = LIGHTTPD_VERSION_ID;
32570         p->name        = buffer_init_string("rrd");
32571 -       
32572 +
32573         p->init        = mod_rrd_init;
32574         p->cleanup     = mod_rrd_free;
32575         p->set_defaults= mod_rrd_set_defaults;
32576 -       
32577 +
32578         p->handle_trigger      = mod_rrd_trigger;
32579         p->handle_request_done = mod_rrd_account;
32580 -       
32581 +
32582         p->data        = NULL;
32583 -       
32584 +
32585         return 0;
32586  }
32587 --- ../lighttpd-1.4.11/src/mod_scgi.c   2006-03-04 17:15:26.000000000 +0200
32588 +++ lighttpd-1.4.12/src/mod_scgi.c      2006-07-18 13:03:40.000000000 +0300
32589 @@ -1,5 +1,4 @@
32590  #include <sys/types.h>
32591 -#include <unistd.h>
32592  #include <errno.h>
32593  #include <fcntl.h>
32594  #include <string.h>
32595 @@ -18,6 +17,7 @@
32596  #include "connections.h"
32597  #include "response.h"
32598  #include "joblist.h"
32599 +#include "http_resp.h"
32600  
32601  #include "plugin.h"
32602  
32603 @@ -30,7 +30,9 @@
32604  #endif
32605  
32606  #include "sys-socket.h"
32607 -
32608 +#include "sys-files.h"
32609 +#include "sys-strings.h"
32610 +#include "sys-process.h"
32611  
32612  #ifndef UNIX_PATH_MAX
32613  # define UNIX_PATH_MAX 108
32614 @@ -46,30 +48,29 @@
32615  enum {EOL_UNSET, EOL_N, EOL_RN};
32616  
32617  /*
32618 - * 
32619 + *
32620   * TODO:
32621 - * 
32622 + *
32623   * - add timeout for a connect to a non-scgi process
32624   *   (use state_timestamp + state)
32625 - * 
32626 + *
32627   */
32628  
32629  typedef struct scgi_proc {
32630         size_t id; /* id will be between 1 and max_procs */
32631         buffer *socket; /* config.socket + "-" + id */
32632         unsigned port;  /* config.port + pno */
32633 -       
32634 -       pid_t pid;   /* PID of the spawned process (0 if not spawned locally) */
32635  
32636 +       pid_t pid;   /* PID of the spawned process (0 if not spawned locally) */
32637  
32638         size_t load; /* number of requests waiting on this process */
32639  
32640         time_t last_used; /* see idle_timeout */
32641         size_t requests;  /* see max_requests */
32642         struct scgi_proc *prev, *next; /* see first */
32643 -       
32644 +
32645         time_t disable_ts; /* replace by host->something */
32646 -       
32647 +
32648         int is_local;
32649  
32650         enum { PROC_STATE_UNSET,            /* init-phase */
32651 @@ -78,7 +79,7 @@
32652                         PROC_STATE_KILLED,  /* was killed as we don't have the load anymore */
32653                         PROC_STATE_DIED,    /* marked as dead, should be restarted */
32654                         PROC_STATE_DISABLED /* proc disabled as it resulted in an error */
32655 -       } state; 
32656 +       } state;
32657  } scgi_proc;
32658  
32659  typedef struct {
32660 @@ -86,20 +87,20 @@
32661          * sorted by lowest load
32662          *
32663          * whenever a job is done move it up in the list
32664 -        * until it is sorted, move it down as soon as the 
32665 +        * until it is sorted, move it down as soon as the
32666          * job is started
32667          */
32668 -       scgi_proc *first; 
32669 -       scgi_proc *unused_procs; 
32670 +       scgi_proc *first;
32671 +       scgi_proc *unused_procs;
32672  
32673 -       /* 
32674 +       /*
32675          * spawn at least min_procs, at max_procs.
32676          *
32677 -        * as soon as the load of the first entry 
32678 +        * as soon as the load of the first entry
32679          * is max_load_per_proc we spawn a new one
32680 -        * and add it to the first entry and give it 
32681 +        * and add it to the first entry and give it
32682          * the load
32683 -        * 
32684 +        *
32685          */
32686  
32687         unsigned short min_procs;
32688 @@ -111,44 +112,44 @@
32689  
32690         /*
32691          * kick the process from the list if it was not
32692 -        * used for idle_timeout until min_procs is 
32693 +        * used for idle_timeout until min_procs is
32694          * reached. this helps to get the processlist
32695          * small again we had a small peak load.
32696          *
32697          */
32698 -       
32699 +
32700         unsigned short idle_timeout;
32701 -       
32702 +
32703         /*
32704          * time after a disabled remote connection is tried to be re-enabled
32705 -        * 
32706 -        * 
32707 +        *
32708 +        *
32709          */
32710 -       
32711 +
32712         unsigned short disable_time;
32713  
32714         /*
32715          * same scgi processes get a little bit larger
32716 -        * than wanted. max_requests_per_proc kills a 
32717 +        * than wanted. max_requests_per_proc kills a
32718          * process after a number of handled requests.
32719          *
32720          */
32721         size_t max_requests_per_proc;
32722 -       
32723 +
32724  
32725         /* config */
32726  
32727 -       /* 
32728 -        * host:port 
32729 +       /*
32730 +        * host:port
32731          *
32732 -        * if host is one of the local IP adresses the 
32733 +        * if host is one of the local IP adresses the
32734          * whole connection is local
32735          *
32736          * if tcp/ip should be used host AND port have
32737 -        * to be specified 
32738 -        * 
32739 -        */ 
32740 -       buffer *host; 
32741 +        * to be specified
32742 +        *
32743 +        */
32744 +       buffer *host;
32745         unsigned short port;
32746  
32747         /*
32748 @@ -161,7 +162,7 @@
32749          */
32750         buffer *unixsocket;
32751  
32752 -       /* if socket is local we can start the scgi 
32753 +       /* if socket is local we can start the scgi
32754          * process ourself
32755          *
32756          * bin-path is the path to the binary
32757 @@ -169,19 +170,19 @@
32758          * check min_procs and max_procs for the number
32759          * of process to start-up
32760          */
32761 -       buffer *bin_path; 
32762 -       
32763 -       /* bin-path is set bin-environment is taken to 
32764 +       buffer *bin_path;
32765 +
32766 +       /* bin-path is set bin-environment is taken to
32767          * create the environement before starting the
32768          * FastCGI process
32769 -        * 
32770 +        *
32771          */
32772         array *bin_env;
32773 -       
32774 +
32775         array *bin_env_copy;
32776 -       
32777 +
32778         /*
32779 -        * docroot-translation between URL->phys and the 
32780 +        * docroot-translation between URL->phys and the
32781          * remote host
32782          *
32783          * reasons:
32784 @@ -192,7 +193,7 @@
32785         buffer *docroot;
32786  
32787         /*
32788 -        * check_local tell you if the phys file is stat()ed 
32789 +        * check_local tell you if the phys file is stat()ed
32790          * or not. FastCGI doesn't care if the service is
32791          * remote. If the web-server side doesn't contain
32792          * the scgi-files we should not stat() for them
32793 @@ -202,33 +203,33 @@
32794  
32795         /*
32796          * append PATH_INFO to SCRIPT_FILENAME
32797 -        * 
32798 +        *
32799          * php needs this if cgi.fix_pathinfo is provied
32800 -        * 
32801 +        *
32802          */
32803 -       
32804 +
32805         ssize_t load; /* replace by host->load */
32806  
32807         size_t max_id; /* corresponds most of the time to
32808         num_procs.
32809 -       
32810 +
32811         only if a process is killed max_id waits for the process itself
32812         to die and decrements its afterwards */
32813  } scgi_extension_host;
32814  
32815  /*
32816   * one extension can have multiple hosts assigned
32817 - * one host can spawn additional processes on the same 
32818 + * one host can spawn additional processes on the same
32819   *   socket (if we control it)
32820   *
32821   * ext -> host -> procs
32822   *    1:n     1:n
32823   *
32824 - * if the scgi process is remote that whole goes down 
32825 + * if the scgi process is remote that whole goes down
32826   * to
32827   *
32828   * ext -> host -> procs
32829 - *    1:n     1:1 
32830 + *    1:n     1:1
32831   *
32832   * in case of PHP and FCGI_CHILDREN we have again a procs
32833   * but we don't control it directly.
32834 @@ -239,7 +240,7 @@
32835         buffer *key; /* like .php */
32836  
32837         scgi_extension_host **hosts;
32838 -       
32839 +
32840         size_t used;
32841         size_t size;
32842  } scgi_extension;
32843 @@ -253,14 +254,14 @@
32844  
32845  
32846  typedef struct {
32847 -       scgi_exts *exts; 
32848 -       
32849 +       scgi_exts *exts;
32850 +
32851         int debug;
32852  } plugin_config;
32853  
32854  typedef struct {
32855         char **ptr;
32856 -       
32857 +
32858         size_t size;
32859         size_t used;
32860  } char_array;
32861 @@ -268,52 +269,51 @@
32862  /* generic plugin data, shared between all connections */
32863  typedef struct {
32864         PLUGIN_DATA;
32865 -       
32866 +
32867         buffer *scgi_env;
32868 -       
32869 +
32870         buffer *path;
32871 -       buffer *parse_response;
32872 -       
32873 +
32874 +       http_resp *resp;
32875 +
32876         plugin_config **config_storage;
32877 -       
32878 +
32879         plugin_config conf; /* this is only used as long as no handler_ctx is setup */
32880  } plugin_data;
32881  
32882  /* connection specific data */
32883 -typedef enum { FCGI_STATE_INIT, FCGI_STATE_CONNECT, FCGI_STATE_PREPARE_WRITE, 
32884 -               FCGI_STATE_WRITE, FCGI_STATE_READ 
32885 +typedef enum {
32886 +       SCGI_STATE_INIT,
32887 +       SCGI_STATE_CONNECT,
32888 +       SCGI_STATE_PREPARE_WRITE,
32889 +       SCGI_STATE_WRITE,
32890 +       SCGI_STATE_RESPONSE_HEADER,
32891 +       SCGI_STATE_RESPONSE_CONTENT,
32892 +       SCGI_STATE_ERROR
32893  } scgi_connection_state_t;
32894  
32895  typedef struct {
32896 -       buffer  *response; 
32897 -       size_t   response_len;
32898 -       int      response_type;
32899 -       int      response_padding;
32900 -       
32901         scgi_proc *proc;
32902         scgi_extension_host *host;
32903 -       
32904 +
32905         scgi_connection_state_t state;
32906         time_t   state_timestamp;
32907 -       
32908 +
32909         int      reconnects; /* number of reconnect attempts */
32910 -       
32911 -       read_buffer *rb;
32912 +
32913 +       chunkqueue *rb;
32914         chunkqueue *wb;
32915 -       
32916 -       buffer   *response_header;
32917 -       
32918 +
32919         int       delayed;   /* flag to mark that the connect() is delayed */
32920 -       
32921 +
32922         size_t    request_id;
32923 -       int       fd;        /* fd to the scgi process */
32924 -       int       fde_ndx;   /* index into the fd-event buffer */
32925 +       iosocket  *sock;        /* fd to the scgi process */
32926  
32927         pid_t     pid;
32928         int       got_proc;
32929 -       
32930 +
32931         plugin_config conf;
32932 -       
32933 +
32934         connection *remote_conn;  /* dumb pointer */
32935         plugin_data *plugin_data; /* dumb pointer */
32936  } handler_ctx;
32937 @@ -328,42 +328,30 @@
32938  
32939  static handler_ctx * handler_ctx_init() {
32940         handler_ctx * hctx;
32941 -       
32942 +
32943         hctx = calloc(1, sizeof(*hctx));
32944         assert(hctx);
32945 -       
32946 -       hctx->fde_ndx = -1;
32947 -       
32948 -       hctx->response = buffer_init();
32949 -       hctx->response_header = buffer_init();
32950 -       
32951 +
32952 +       hctx->sock = iosocket_init();;
32953 +
32954         hctx->request_id = 0;
32955 -       hctx->state = FCGI_STATE_INIT;
32956 +       hctx->state = SCGI_STATE_INIT;
32957         hctx->proc = NULL;
32958 -       
32959 -       hctx->response_len = 0;
32960 -       hctx->response_type = 0;
32961 -       hctx->response_padding = 0;
32962 -       hctx->fd = -1;
32963 -       
32964 +
32965         hctx->reconnects = 0;
32966  
32967         hctx->wb = chunkqueue_init();
32968 -       
32969 +       hctx->rb = chunkqueue_init();
32970 +
32971         return hctx;
32972  }
32973  
32974  static void handler_ctx_free(handler_ctx *hctx) {
32975 -       buffer_free(hctx->response);
32976 -       buffer_free(hctx->response_header);
32977 -
32978         chunkqueue_free(hctx->wb);
32979 -       
32980 -       if (hctx->rb) {
32981 -               if (hctx->rb->ptr) free(hctx->rb->ptr);
32982 -               free(hctx->rb);
32983 -       }
32984 -       
32985 +       chunkqueue_free(hctx->rb);
32986 +
32987 +       iosocket_free(hctx->sock);
32988 +
32989         free(hctx);
32990  }
32991  
32992 @@ -372,20 +360,20 @@
32993  
32994         f = calloc(1, sizeof(*f));
32995         f->socket = buffer_init();
32996 -       
32997 +
32998         f->prev = NULL;
32999         f->next = NULL;
33000 -       
33001 +
33002         return f;
33003  }
33004  
33005  void scgi_process_free(scgi_proc *f) {
33006         if (!f) return;
33007 -       
33008 +
33009         scgi_process_free(f->next);
33010 -       
33011 +
33012         buffer_free(f->socket);
33013 -       
33014 +
33015         free(f);
33016  }
33017  
33018 @@ -400,62 +388,62 @@
33019         f->bin_path = buffer_init();
33020         f->bin_env = array_init();
33021         f->bin_env_copy = array_init();
33022 -       
33023 +
33024         return f;
33025  }
33026  
33027  void scgi_host_free(scgi_extension_host *h) {
33028         if (!h) return;
33029 -       
33030 +
33031         buffer_free(h->host);
33032         buffer_free(h->unixsocket);
33033         buffer_free(h->docroot);
33034         buffer_free(h->bin_path);
33035         array_free(h->bin_env);
33036         array_free(h->bin_env_copy);
33037 -       
33038 +
33039         scgi_process_free(h->first);
33040         scgi_process_free(h->unused_procs);
33041 -       
33042 +
33043         free(h);
33044 -       
33045 +
33046  }
33047  
33048  scgi_exts *scgi_extensions_init() {
33049         scgi_exts *f;
33050  
33051         f = calloc(1, sizeof(*f));
33052 -       
33053 +
33054         return f;
33055  }
33056  
33057  void scgi_extensions_free(scgi_exts *f) {
33058         size_t i;
33059 -       
33060 +
33061         if (!f) return;
33062 -       
33063 +
33064         for (i = 0; i < f->used; i++) {
33065                 scgi_extension *fe;
33066                 size_t j;
33067 -               
33068 +
33069                 fe = f->exts[i];
33070 -               
33071 +
33072                 for (j = 0; j < fe->used; j++) {
33073                         scgi_extension_host *h;
33074 -                       
33075 +
33076                         h = fe->hosts[j];
33077 -                       
33078 +
33079                         scgi_host_free(h);
33080                 }
33081 -               
33082 +
33083                 buffer_free(fe->key);
33084                 free(fe->hosts);
33085 -               
33086 +
33087                 free(fe);
33088         }
33089 -       
33090 +
33091         free(f->exts);
33092 -       
33093 +
33094         free(f);
33095  }
33096  
33097 @@ -504,99 +492,103 @@
33098                 assert(fe->hosts);
33099         }
33100  
33101 -       fe->hosts[fe->used++] = fh; 
33102 +       fe->hosts[fe->used++] = fh;
33103  
33104         return 0;
33105 -       
33106 +
33107  }
33108  
33109  INIT_FUNC(mod_scgi_init) {
33110         plugin_data *p;
33111 -       
33112 +
33113         p = calloc(1, sizeof(*p));
33114 -       
33115 +
33116         p->scgi_env = buffer_init();
33117 -       
33118 +
33119         p->path = buffer_init();
33120 -       p->parse_response = buffer_init();
33121 -       
33122 +       p->resp = http_response_init();
33123 +
33124         return p;
33125  }
33126  
33127  
33128  FREE_FUNC(mod_scgi_free) {
33129         plugin_data *p = p_d;
33130 -       
33131 +
33132         UNUSED(srv);
33133  
33134         buffer_free(p->scgi_env);
33135         buffer_free(p->path);
33136 -       buffer_free(p->parse_response);
33137 -       
33138 +       http_response_free(p->resp);
33139 +
33140         if (p->config_storage) {
33141                 size_t i, j, n;
33142                 for (i = 0; i < srv->config_context->used; i++) {
33143                         plugin_config *s = p->config_storage[i];
33144                         scgi_exts *exts;
33145 -                       
33146 +
33147                         if (!s) continue;
33148 -                       
33149 +
33150                         exts = s->exts;
33151  
33152                         for (j = 0; j < exts->used; j++) {
33153                                 scgi_extension *ex;
33154 -                               
33155 +
33156                                 ex = exts->exts[j];
33157 -                               
33158 +
33159                                 for (n = 0; n < ex->used; n++) {
33160                                         scgi_proc *proc;
33161                                         scgi_extension_host *host;
33162 -                                       
33163 +
33164                                         host = ex->hosts[n];
33165 -                                       
33166 +
33167                                         for (proc = host->first; proc; proc = proc->next) {
33168 +#ifndef _WIN32
33169                                                 if (proc->pid != 0) kill(proc->pid, SIGTERM);
33170 -                                               
33171 -                                               if (proc->is_local && 
33172 +#endif
33173 +
33174 +                                               if (proc->is_local &&
33175                                                     !buffer_is_empty(proc->socket)) {
33176                                                         unlink(proc->socket->ptr);
33177                                                 }
33178                                         }
33179 -                                       
33180 +
33181                                         for (proc = host->unused_procs; proc; proc = proc->next) {
33182 +#ifndef _WIN32
33183                                                 if (proc->pid != 0) kill(proc->pid, SIGTERM);
33184 -                                               
33185 -                                               if (proc->is_local && 
33186 +#endif
33187 +
33188 +                                               if (proc->is_local &&
33189                                                     !buffer_is_empty(proc->socket)) {
33190                                                         unlink(proc->socket->ptr);
33191                                                 }
33192                                         }
33193                                 }
33194                         }
33195 -                       
33196 +
33197                         scgi_extensions_free(s->exts);
33198 -                       
33199 +
33200                         free(s);
33201                 }
33202                 free(p->config_storage);
33203         }
33204 -       
33205 +
33206         free(p);
33207 -       
33208 +
33209         return HANDLER_GO_ON;
33210  }
33211  
33212  static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
33213         char *dst;
33214 -       
33215 +
33216         if (!key || !val) return -1;
33217 -       
33218 +
33219         dst = malloc(key_len + val_len + 3);
33220         memcpy(dst, key, key_len);
33221         dst[key_len] = '=';
33222         /* add the \0 from the value */
33223         memcpy(dst + key_len + 1, val, val_len + 1);
33224 -       
33225 +
33226         if (env->size == 0) {
33227                 env->size = 16;
33228                 env->ptr = malloc(env->size * sizeof(*env->ptr));
33229 @@ -604,13 +596,13 @@
33230                 env->size += 16;
33231                 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
33232         }
33233 -       
33234 +
33235         env->ptr[env->used++] = dst;
33236 -       
33237 +
33238         return 0;
33239  }
33240  
33241 -static int scgi_spawn_connection(server *srv, 
33242 +static int scgi_spawn_connection(server *srv,
33243                                  plugin_data *p,
33244                                  scgi_extension_host *host,
33245                                  scgi_proc *proc) {
33246 @@ -622,31 +614,27 @@
33247  #endif
33248         struct sockaddr_in scgi_addr_in;
33249         struct sockaddr *scgi_addr;
33250 -       
33251 +
33252         socklen_t servlen;
33253 -       
33254 +
33255  #ifndef HAVE_FORK
33256         return -1;
33257  #endif
33258 -       
33259 +
33260         if (p->conf.debug) {
33261                 log_error_write(srv, __FILE__, __LINE__, "sdb",
33262                                 "new proc, socket:", proc->port, proc->socket);
33263         }
33264 -               
33265 +
33266         if (!buffer_is_empty(proc->socket)) {
33267                 memset(&scgi_addr, 0, sizeof(scgi_addr));
33268 -               
33269 +
33270  #ifdef HAVE_SYS_UN_H
33271                 scgi_addr_un.sun_family = AF_UNIX;
33272                 strcpy(scgi_addr_un.sun_path, proc->socket->ptr);
33273 -               
33274 -#ifdef SUN_LEN
33275 +
33276                 servlen = SUN_LEN(&scgi_addr_un);
33277 -#else
33278 -               /* stevens says: */
33279 -               servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family);
33280 -#endif
33281 +
33282                 socket_type = AF_UNIX;
33283                 scgi_addr = (struct sockaddr *) &scgi_addr_un;
33284  #else
33285 @@ -656,115 +644,115 @@
33286  #endif
33287         } else {
33288                 scgi_addr_in.sin_family = AF_INET;
33289 -               
33290 +
33291                 if (buffer_is_empty(host->host)) {
33292                         scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
33293                 } else {
33294                         struct hostent *he;
33295 -                       
33296 +
33297                         /* set a usefull default */
33298                         scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
33299 -                       
33300 -                       
33301 +
33302 +
33303                         if (NULL == (he = gethostbyname(host->host->ptr))) {
33304 -                               log_error_write(srv, __FILE__, __LINE__, 
33305 -                                               "sdb", "gethostbyname failed: ", 
33306 +                               log_error_write(srv, __FILE__, __LINE__,
33307 +                                               "sdb", "gethostbyname failed: ",
33308                                                 h_errno, host->host);
33309                                 return -1;
33310                         }
33311 -                       
33312 +
33313                         if (he->h_addrtype != AF_INET) {
33314                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
33315                                 return -1;
33316                         }
33317 -                       
33318 +
33319                         if (he->h_length != sizeof(struct in_addr)) {
33320                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
33321                                 return -1;
33322                         }
33323 -                       
33324 +
33325                         memcpy(&(scgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
33326 -                       
33327 +
33328                 }
33329                 scgi_addr_in.sin_port = htons(proc->port);
33330                 servlen = sizeof(scgi_addr_in);
33331 -               
33332 +
33333                 socket_type = AF_INET;
33334                 scgi_addr = (struct sockaddr *) &scgi_addr_in;
33335         }
33336 -       
33337 +
33338         if (-1 == (scgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
33339 -               log_error_write(srv, __FILE__, __LINE__, "ss", 
33340 +               log_error_write(srv, __FILE__, __LINE__, "ss",
33341                                 "failed:", strerror(errno));
33342                 return -1;
33343         }
33344 -       
33345 +
33346         if (-1 == connect(scgi_fd, scgi_addr, servlen)) {
33347                 /* server is not up, spawn in  */
33348                 pid_t child;
33349                 int val;
33350 -               
33351 +
33352                 if (!buffer_is_empty(proc->socket)) {
33353                         unlink(proc->socket->ptr);
33354                 }
33355 -               
33356 +
33357                 close(scgi_fd);
33358 -               
33359 +
33360                 /* reopen socket */
33361                 if (-1 == (scgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
33362 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
33363 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
33364                                 "socket failed:", strerror(errno));
33365                         return -1;
33366                 }
33367 -               
33368 +
33369                 val = 1;
33370                 if (setsockopt(scgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
33371 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
33372 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
33373                                         "socketsockopt failed:", strerror(errno));
33374                         return -1;
33375                 }
33376 -               
33377 +
33378                 /* create socket */
33379                 if (-1 == bind(scgi_fd, scgi_addr, servlen)) {
33380 -                       log_error_write(srv, __FILE__, __LINE__, "sbds", 
33381 -                               "bind failed for:", 
33382 -                               proc->socket, 
33383 -                               proc->port, 
33384 +                       log_error_write(srv, __FILE__, __LINE__, "sbds",
33385 +                               "bind failed for:",
33386 +                               proc->socket,
33387 +                               proc->port,
33388                                 strerror(errno));
33389                         return -1;
33390                 }
33391 -               
33392 +
33393                 if (-1 == listen(scgi_fd, 1024)) {
33394 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
33395 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
33396                                 "listen failed:", strerror(errno));
33397                         return -1;
33398                 }
33399 -               
33400 -#ifdef HAVE_FORK       
33401 +
33402 +#ifdef HAVE_FORK
33403                 switch ((child = fork())) {
33404                 case 0: {
33405                         buffer *b;
33406                         size_t i = 0;
33407                         int fd = 0;
33408                         char_array env;
33409 -                       
33410 -                       
33411 +
33412 +
33413                         /* create environment */
33414                         env.ptr = NULL;
33415                         env.size = 0;
33416                         env.used = 0;
33417 -                       
33418 +
33419                         /* we don't need the client socket */
33420                         for (fd = 3; fd < 256; fd++) {
33421                                 if (fd != 2 && fd != scgi_fd) close(fd);
33422                         }
33423 -                       
33424 +
33425                         /* build clean environment */
33426                         if (host->bin_env_copy->used) {
33427                                 for (i = 0; i < host->bin_env_copy->used; i++) {
33428                                         data_string *ds = (data_string *)host->bin_env_copy->data[i];
33429                                         char *ge;
33430 -                                       
33431 +
33432                                         if (NULL != (ge = getenv(ds->value->ptr))) {
33433                                                 env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge));
33434                                         }
33435 @@ -772,44 +760,44 @@
33436                         } else {
33437                                 for (i = 0; environ[i]; i++) {
33438                                         char *eq;
33439 -                                       
33440 +
33441                                         if (NULL != (eq = strchr(environ[i], '='))) {
33442                                                 env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));
33443                                         }
33444                                 }
33445                         }
33446 -                       
33447 +
33448                         /* create environment */
33449                         for (i = 0; i < host->bin_env->used; i++) {
33450                                 data_string *ds = (data_string *)host->bin_env->data[i];
33451 -                               
33452 +
33453                                 env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
33454                         }
33455 -                       
33456 +
33457                         for (i = 0; i < env.used; i++) {
33458                                 /* search for PHP_FCGI_CHILDREN */
33459                                 if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break;
33460                         }
33461 -                       
33462 +
33463                         /* not found, add a default */
33464                         if (i == env.used) {
33465                                 env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1"));
33466                         }
33467 -                       
33468 +
33469                         env.ptr[env.used] = NULL;
33470 -                       
33471 +
33472                         b = buffer_init();
33473                         buffer_copy_string(b, "exec ");
33474                         buffer_append_string_buffer(b, host->bin_path);
33475 -                       
33476 +
33477                         /* exec the cgi */
33478                         execle("/bin/sh", "sh", "-c", b->ptr, NULL, env.ptr);
33479 -                       
33480 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
33481 +
33482 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
33483                                         "execl failed for:", host->bin_path, strerror(errno));
33484 -                       
33485 +
33486                         exit(errno);
33487 -                       
33488 +
33489                         break;
33490                 }
33491                 case -1:
33492 @@ -817,32 +805,32 @@
33493                         break;
33494                 default:
33495                         /* father */
33496 -                       
33497 +
33498                         /* wait */
33499                         select(0, NULL, NULL, NULL, &tv);
33500 -                       
33501 +
33502                         switch (waitpid(child, &status, WNOHANG)) {
33503                         case 0:
33504                                 /* child still running after timeout, good */
33505                                 break;
33506                         case -1:
33507                                 /* no PID found ? should never happen */
33508 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
33509 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
33510                                                 "pid not found:", strerror(errno));
33511                                 return -1;
33512                         default:
33513                                 /* the child should not terminate at all */
33514                                 if (WIFEXITED(status)) {
33515 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
33516 -                                                       "child exited (is this a SCGI binary ?):", 
33517 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
33518 +                                                       "child exited (is this a SCGI binary ?):",
33519                                                         WEXITSTATUS(status));
33520                                 } else if (WIFSIGNALED(status)) {
33521 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
33522 -                                                       "child signaled:", 
33523 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
33524 +                                                       "child signaled:",
33525                                                         WTERMSIG(status));
33526                                 } else {
33527 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
33528 -                                                       "child died somehow:", 
33529 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
33530 +                                                       "child died somehow:",
33531                                                         status);
33532                                 }
33533                                 return -1;
33534 @@ -852,26 +840,26 @@
33535                         proc->pid = child;
33536                         proc->last_used = srv->cur_ts;
33537                         proc->is_local = 1;
33538 -                                               
33539 +
33540                         break;
33541                 }
33542  #endif
33543         } else {
33544                 proc->is_local = 0;
33545                 proc->pid = 0;
33546 -               
33547 +
33548                 if (p->conf.debug) {
33549                         log_error_write(srv, __FILE__, __LINE__, "sb",
33550                                         "(debug) socket is already used, won't spawn:",
33551                                         proc->socket);
33552                 }
33553         }
33554 -       
33555 +
33556         proc->state = PROC_STATE_RUNNING;
33557         host->active_procs++;
33558 -       
33559 +
33560         close(scgi_fd);
33561 -       
33562 +
33563         return 0;
33564  }
33565  
33566 @@ -880,89 +868,89 @@
33567         plugin_data *p = p_d;
33568         data_unset *du;
33569         size_t i = 0;
33570 -       
33571 -       config_values_t cv[] = { 
33572 +
33573 +       config_values_t cv[] = {
33574                 { "scgi.server",              NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
33575                 { "scgi.debug",               NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
33576                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
33577         };
33578 -       
33579 +
33580         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
33581 -       
33582 +
33583         for (i = 0; i < srv->config_context->used; i++) {
33584                 plugin_config *s;
33585                 array *ca;
33586 -               
33587 +
33588                 s = malloc(sizeof(plugin_config));
33589                 s->exts          = scgi_extensions_init();
33590                 s->debug         = 0;
33591 -               
33592 +
33593                 cv[0].destination = s->exts;
33594                 cv[1].destination = &(s->debug);
33595 -               
33596 +
33597                 p->config_storage[i] = s;
33598                 ca = ((data_config *)srv->config_context->data[i])->value;
33599 -       
33600 +
33601                 if (0 != config_insert_values_global(srv, ca, cv)) {
33602                         return HANDLER_ERROR;
33603                 }
33604 -               
33605 -               /* 
33606 +
33607 +               /*
33608                  * <key> = ( ... )
33609                  */
33610 -               
33611 +
33612                 if (NULL != (du = array_get_element(ca, "scgi.server"))) {
33613                         size_t j;
33614                         data_array *da = (data_array *)du;
33615 -                       
33616 +
33617                         if (du->type != TYPE_ARRAY) {
33618 -                               log_error_write(srv, __FILE__, __LINE__, "sss", 
33619 +                               log_error_write(srv, __FILE__, __LINE__, "sss",
33620                                                 "unexpected type for key: ", "scgi.server", "array of strings");
33621 -                               
33622 +
33623                                 return HANDLER_ERROR;
33624                         }
33625 -                       
33626 -                       
33627 -                       /* 
33628 -                        * scgi.server = ( "<ext>" => ( ... ), 
33629 +
33630 +
33631 +                       /*
33632 +                        * scgi.server = ( "<ext>" => ( ... ),
33633                          *                    "<ext>" => ( ... ) )
33634                          */
33635 -                       
33636 +
33637                         for (j = 0; j < da->value->used; j++) {
33638                                 size_t n;
33639                                 data_array *da_ext = (data_array *)da->value->data[j];
33640 -                               
33641 +
33642                                 if (da->value->data[j]->type != TYPE_ARRAY) {
33643 -                                       log_error_write(srv, __FILE__, __LINE__, "sssbs", 
33644 -                                                       "unexpected type for key: ", "scgi.server", 
33645 +                                       log_error_write(srv, __FILE__, __LINE__, "sssbs",
33646 +                                                       "unexpected type for key: ", "scgi.server",
33647                                                         "[", da->value->data[j]->key, "](string)");
33648 -                                       
33649 +
33650                                         return HANDLER_ERROR;
33651                                 }
33652 -                               
33653 -                               /* 
33654 -                                * da_ext->key == name of the extension 
33655 +
33656 +                               /*
33657 +                                * da_ext->key == name of the extension
33658                                  */
33659 -                               
33660 -                               /* 
33661 -                                * scgi.server = ( "<ext>" => 
33662 -                                *                     ( "<host>" => ( ... ), 
33663 +
33664 +                               /*
33665 +                                * scgi.server = ( "<ext>" =>
33666 +                                *                     ( "<host>" => ( ... ),
33667                                  *                       "<host>" => ( ... )
33668 -                                *                     ), 
33669 +                                *                     ),
33670                                  *                    "<ext>" => ... )
33671                                  */
33672 -                                       
33673 +
33674                                 for (n = 0; n < da_ext->value->used; n++) {
33675                                         data_array *da_host = (data_array *)da_ext->value->data[n];
33676 -                                       
33677 +
33678                                         scgi_extension_host *df;
33679 -                                       
33680 -                                       config_values_t fcv[] = { 
33681 +
33682 +                                       config_values_t fcv[] = {
33683                                                 { "host",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
33684                                                 { "docroot",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
33685                                                 { "socket",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
33686                                                 { "bin-path",          NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
33687 -                                               
33688 +
33689                                                 { "check-local",       NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 4 */
33690                                                 { "port",              NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 5 */
33691                                                 { "min-procs-not-working",         NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 7 this is broken for now */
33692 @@ -970,37 +958,37 @@
33693                                                 { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 8 */
33694                                                 { "idle-timeout",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 9 */
33695                                                 { "disable-time",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 10 */
33696 -                                               
33697 +
33698                                                 { "bin-environment",   NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },        /* 11 */
33699                                                 { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },     /* 12 */
33700 -                                               
33701 -                                               
33702 +
33703 +
33704                                                 { NULL,                NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
33705                                         };
33706 -                                       
33707 +
33708                                         if (da_host->type != TYPE_ARRAY) {
33709 -                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS", 
33710 -                                                               "unexpected type for key:", 
33711 -                                                               "scgi.server", 
33712 +                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS",
33713 +                                                               "unexpected type for key:",
33714 +                                                               "scgi.server",
33715                                                                 "[", da_host->key, "](string)");
33716 -                                               
33717 +
33718                                                 return HANDLER_ERROR;
33719                                         }
33720 -                                       
33721 +
33722                                         df = scgi_host_init();
33723 -                                       
33724 +
33725                                         df->check_local  = 1;
33726                                         df->min_procs    = 4;
33727                                         df->max_procs    = 4;
33728                                         df->max_load_per_proc = 1;
33729                                         df->idle_timeout = 60;
33730                                         df->disable_time = 60;
33731 -                                       
33732 +
33733                                         fcv[0].destination = df->host;
33734                                         fcv[1].destination = df->docroot;
33735                                         fcv[2].destination = df->unixsocket;
33736                                         fcv[3].destination = df->bin_path;
33737 -                                       
33738 +
33739                                         fcv[4].destination = &(df->check_local);
33740                                         fcv[5].destination = &(df->port);
33741                                         fcv[6].destination = &(df->min_procs);
33742 @@ -1008,47 +996,47 @@
33743                                         fcv[8].destination = &(df->max_load_per_proc);
33744                                         fcv[9].destination = &(df->idle_timeout);
33745                                         fcv[10].destination = &(df->disable_time);
33746 -                                       
33747 +
33748                                         fcv[11].destination = df->bin_env;
33749                                         fcv[12].destination = df->bin_env_copy;
33750 -                                       
33751 -                                       
33752 +
33753 +
33754                                         if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
33755                                                 return HANDLER_ERROR;
33756                                         }
33757 -                                                       
33758 -                                       if ((!buffer_is_empty(df->host) || df->port) && 
33759 +
33760 +                                       if ((!buffer_is_empty(df->host) || df->port) &&
33761                                             !buffer_is_empty(df->unixsocket)) {
33762 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
33763 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
33764                                                                 "either host+port or socket");
33765 -                                               
33766 +
33767                                                 return HANDLER_ERROR;
33768                                         }
33769 -                                       
33770 +
33771                                         if (!buffer_is_empty(df->unixsocket)) {
33772                                                 /* unix domain socket */
33773 -                                               
33774 +
33775                                                 if (df->unixsocket->used > UNIX_PATH_MAX - 2) {
33776 -                                                       log_error_write(srv, __FILE__, __LINE__, "s", 
33777 +                                                       log_error_write(srv, __FILE__, __LINE__, "s",
33778                                                                         "path of the unixdomain socket is too large");
33779                                                         return HANDLER_ERROR;
33780                                                 }
33781                                         } else {
33782                                                 /* tcp/ip */
33783 -                                               
33784 -                                               if (buffer_is_empty(df->host) && 
33785 +
33786 +                                               if (buffer_is_empty(df->host) &&
33787                                                     buffer_is_empty(df->bin_path)) {
33788 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbbbs", 
33789 -                                                                       "missing key (string):", 
33790 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbbbs",
33791 +                                                                       "missing key (string):",
33792                                                                         da->key,
33793                                                                         da_ext->key,
33794                                                                         da_host->key,
33795                                                                         "host");
33796 -                                                       
33797 +
33798                                                         return HANDLER_ERROR;
33799                                                 } else if (df->port == 0) {
33800 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbbbs", 
33801 -                                                                       "missing key (short):", 
33802 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbbbs",
33803 +                                                                       "missing key (short):",
33804                                                                         da->key,
33805                                                                         da_ext->key,
33806                                                                         da_host->key,
33807 @@ -1056,14 +1044,14 @@
33808                                                         return HANDLER_ERROR;
33809                                                 }
33810                                         }
33811 -                                               
33812 -                                       if (!buffer_is_empty(df->bin_path)) { 
33813 +
33814 +                                       if (!buffer_is_empty(df->bin_path)) {
33815                                                 /* a local socket + self spawning */
33816                                                 size_t pno;
33817 -                                               
33818 +
33819                                                 if (df->min_procs > df->max_procs) df->max_procs = df->min_procs;
33820                                                 if (df->max_load_per_proc < 1) df->max_load_per_proc = 0;
33821 -                                               
33822 +
33823                                                 if (s->debug) {
33824                                                         log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
33825                                                                         "--- scgi spawning local",
33826 @@ -1073,7 +1061,7 @@
33827                                                                         "\n\tmin-procs:", df->min_procs,
33828                                                                         "\n\tmax-procs:", df->max_procs);
33829                                                 }
33830 -                                               
33831 +
33832                                                 for (pno = 0; pno < df->min_procs; pno++) {
33833                                                         scgi_proc *proc;
33834  
33835 @@ -1088,7 +1076,7 @@
33836                                                                 buffer_append_string(proc->socket, "-");
33837                                                                 buffer_append_long(proc->socket, pno);
33838                                                         }
33839 -                                                       
33840 +
33841                                                         if (s->debug) {
33842                                                                 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
33843                                                                                 "--- scgi spawning",
33844 @@ -1096,53 +1084,53 @@
33845                                                                                 "\n\tsocket", df->unixsocket,
33846                                                                                 "\n\tcurrent:", pno, "/", df->min_procs);
33847                                                         }
33848 -                                                       
33849 +
33850                                                         if (scgi_spawn_connection(srv, p, df, proc)) {
33851                                                                 log_error_write(srv, __FILE__, __LINE__, "s",
33852                                                                                 "[ERROR]: spawning fcgi failed.");
33853                                                                 return HANDLER_ERROR;
33854                                                         }
33855 -                                                       
33856 +
33857                                                         proc->next = df->first;
33858                                                         if (df->first)  df->first->prev = proc;
33859 -                                                       
33860 +
33861                                                         df->first = proc;
33862                                                 }
33863                                         } else {
33864                                                 scgi_proc *fp;
33865 -                                               
33866 +
33867                                                 fp = scgi_process_init();
33868                                                 fp->id = df->num_procs++;
33869                                                 df->max_id++;
33870                                                 df->active_procs++;
33871                                                 fp->state = PROC_STATE_RUNNING;
33872 -                                               
33873 +
33874                                                 if (buffer_is_empty(df->unixsocket)) {
33875                                                         fp->port = df->port;
33876                                                 } else {
33877                                                         buffer_copy_string_buffer(fp->socket, df->unixsocket);
33878                                                 }
33879 -                                               
33880 +
33881                                                 df->first = fp;
33882 -                                               
33883 +
33884                                                 df->min_procs = 1;
33885                                                 df->max_procs = 1;
33886                                         }
33887 -                                       
33888 +
33889                                         /* if extension already exists, take it */
33890                                         scgi_extension_insert(s->exts, da_ext->key, df);
33891                                 }
33892                         }
33893                 }
33894         }
33895 -       
33896 +
33897         return HANDLER_GO_ON;
33898  }
33899  
33900  static int scgi_set_state(server *srv, handler_ctx *hctx, scgi_connection_state_t state) {
33901         hctx->state = state;
33902         hctx->state_timestamp = srv->cur_ts;
33903 -       
33904 +
33905         return 0;
33906  }
33907  
33908 @@ -1150,35 +1138,35 @@
33909  void scgi_connection_cleanup(server *srv, handler_ctx *hctx) {
33910         plugin_data *p;
33911         connection  *con;
33912 -       
33913 +
33914         if (NULL == hctx) return;
33915 -       
33916 +
33917         p    = hctx->plugin_data;
33918         con  = hctx->remote_conn;
33919 -       
33920 +
33921         if (con->mode != p->id) {
33922 -               WP();
33923                 return;
33924         }
33925 -       
33926 -       if (hctx->fd != -1) {
33927 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
33928 -               fdevent_unregister(srv->ev, hctx->fd);
33929 -               close(hctx->fd);
33930 +
33931 +       if (hctx->sock->fd != -1) {
33932 +               fdevent_event_del(srv->ev, hctx->sock);
33933 +               fdevent_unregister(srv->ev, hctx->sock);
33934 +               closesocket(hctx->sock->fd);
33935 +               hctx->sock->fd = -1;
33936                 srv->cur_fds--;
33937         }
33938 -       
33939 +
33940         if (hctx->host && hctx->proc) {
33941                 hctx->host->load--;
33942 -               
33943 +
33944                 if (hctx->got_proc) {
33945                         /* after the connect the process gets a load */
33946                         hctx->proc->load--;
33947 -                       
33948 +
33949                         if (p->conf.debug) {
33950                                 log_error_write(srv, __FILE__, __LINE__, "sddb",
33951 -                                               "release proc:", 
33952 -                                               hctx->fd,
33953 +                                               "release proc:",
33954 +                                               hctx->sock->fd,
33955                                                 hctx->proc->pid, hctx->proc->socket);
33956                         }
33957                 }
33958 @@ -1186,87 +1174,87 @@
33959                 scgi_proclist_sort_down(srv, hctx->host, hctx->proc);
33960         }
33961  
33962 -       
33963 +
33964         handler_ctx_free(hctx);
33965 -       con->plugin_ctx[p->id] = NULL;  
33966 +       con->plugin_ctx[p->id] = NULL;
33967  }
33968  
33969  static int scgi_reconnect(server *srv, handler_ctx *hctx) {
33970         plugin_data *p    = hctx->plugin_data;
33971 -       
33972 -       /* child died 
33973 -        * 
33974 -        * 1. 
33975 -        * 
33976 +
33977 +       /* child died
33978 +        *
33979 +        * 1.
33980 +        *
33981          * connect was ok, connection was accepted
33982          * but the php accept loop checks after the accept if it should die or not.
33983 -        * 
33984 -        * if yes we can only detect it at a write() 
33985 -        * 
33986 +        *
33987 +        * if yes we can only detect it at a write()
33988 +        *
33989          * next step is resetting this attemp and setup a connection again
33990 -        * 
33991 +        *
33992          * if we have more then 5 reconnects for the same request, die
33993 -        * 
33994 -        * 2. 
33995 -        * 
33996 +        *
33997 +        * 2.
33998 +        *
33999          * we have a connection but the child died by some other reason
34000 -        * 
34001 +        *
34002          */
34003 -       
34004 -       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
34005 -       fdevent_unregister(srv->ev, hctx->fd);
34006 -       close(hctx->fd);
34007 +
34008 +       fdevent_event_del(srv->ev, hctx->sock);
34009 +       fdevent_unregister(srv->ev, hctx->sock);
34010 +       closesocket(hctx->sock->fd);
34011         srv->cur_fds--;
34012 -       
34013 -       scgi_set_state(srv, hctx, FCGI_STATE_INIT);
34014 -       
34015 +
34016 +       scgi_set_state(srv, hctx, SCGI_STATE_INIT);
34017 +
34018         hctx->request_id = 0;
34019         hctx->reconnects++;
34020 -       
34021 +
34022         if (p->conf.debug) {
34023                 log_error_write(srv, __FILE__, __LINE__, "sddb",
34024 -                               "release proc:", 
34025 -                               hctx->fd,
34026 +                               "release proc:",
34027 +                               hctx->sock->fd,
34028                                 hctx->proc->pid, hctx->proc->socket);
34029         }
34030 -       
34031 +
34032         hctx->proc->load--;
34033         scgi_proclist_sort_down(srv, hctx->host, hctx->proc);
34034 -       
34035 +
34036         return 0;
34037  }
34038  
34039  
34040  static handler_t scgi_connection_reset(server *srv, connection *con, void *p_d) {
34041         plugin_data *p = p_d;
34042 -       
34043 +
34044         scgi_connection_cleanup(srv, con->plugin_ctx[p->id]);
34045 -       
34046 +
34047         return HANDLER_GO_ON;
34048  }
34049  
34050  
34051  static int scgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
34052         size_t len;
34053 -       
34054 +
34055         if (!key || !val) return -1;
34056 -       
34057 +
34058         len = key_len + val_len + 2;
34059 -       
34060 +
34061         buffer_prepare_append(env, len);
34062  
34063 -       /* include the NUL */   
34064 +       /* include the NUL */
34065         memcpy(env->ptr + env->used, key, key_len + 1);
34066         env->used += key_len + 1;
34067         memcpy(env->ptr + env->used, val, val_len + 1);
34068         env->used += val_len + 1;
34069 -       
34070 +
34071         return 0;
34072  }
34073  
34074  
34075  /**
34076 - * 
34077 + *
34078   * returns
34079   *   -1 error
34080   *    0 connected
34081 @@ -1280,24 +1268,21 @@
34082         struct sockaddr_un scgi_addr_un;
34083  #endif
34084         socklen_t servlen;
34085 -       
34086 +
34087         scgi_extension_host *host = hctx->host;
34088         scgi_proc *proc   = hctx->proc;
34089 -       int scgi_fd       = hctx->fd;
34090 -       
34091 +       int scgi_fd       = hctx->sock->fd;
34092 +
34093         memset(&scgi_addr, 0, sizeof(scgi_addr));
34094 -       
34095 +
34096         if (!buffer_is_empty(proc->socket)) {
34097  #ifdef HAVE_SYS_UN_H
34098                 /* use the unix domain socket */
34099                 scgi_addr_un.sun_family = AF_UNIX;
34100                 strcpy(scgi_addr_un.sun_path, proc->socket->ptr);
34101 -#ifdef SUN_LEN
34102 +               
34103                 servlen = SUN_LEN(&scgi_addr_un);
34104 -#else
34105 -               /* stevens says: */
34106 -               servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family);
34107 -#endif
34108 +
34109                 scgi_addr = (struct sockaddr *) &scgi_addr_un;
34110  #else
34111                 return -1;
34112 @@ -1305,105 +1290,105 @@
34113         } else {
34114                 scgi_addr_in.sin_family = AF_INET;
34115                 if (0 == inet_aton(host->host->ptr, &(scgi_addr_in.sin_addr))) {
34116 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
34117 -                                       "converting IP-adress failed for", host->host, 
34118 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
34119 +                                       "converting IP-adress failed for", host->host,
34120                                         "\nBe sure to specify an IP address here");
34121 -                       
34122 +
34123                         return -1;
34124                 }
34125                 scgi_addr_in.sin_port = htons(proc->port);
34126                 servlen = sizeof(scgi_addr_in);
34127 -               
34128 +
34129                 scgi_addr = (struct sockaddr *) &scgi_addr_in;
34130         }
34131 -       
34132 +
34133         if (-1 == connect(scgi_fd, scgi_addr, servlen)) {
34134 -               if (errno == EINPROGRESS || 
34135 +               if (errno == EINPROGRESS ||
34136                     errno == EALREADY ||
34137                     errno == EINTR) {
34138                         if (hctx->conf.debug) {
34139 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
34140 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
34141                                                 "connect delayed, will continue later:", scgi_fd);
34142                         }
34143 -                       
34144 +
34145                         return 1;
34146                 } else {
34147 -                       log_error_write(srv, __FILE__, __LINE__, "sdsddb", 
34148 -                                       "connect failed:", scgi_fd, 
34149 +                       log_error_write(srv, __FILE__, __LINE__, "sdsddb",
34150 +                                       "connect failed:", scgi_fd,
34151                                         strerror(errno), errno,
34152                                         proc->port, proc->socket);
34153  
34154                         if (errno == EAGAIN) {
34155                                 /* this is Linux only */
34156 -                               
34157 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
34158 +
34159 +                               log_error_write(srv, __FILE__, __LINE__, "s",
34160                                                 "If this happend on Linux: You have been run out of local ports. "
34161                                                 "Check the manual, section Performance how to handle this.");
34162 -                       } 
34163 -                       
34164 +                       }
34165 +
34166                         return -1;
34167                 }
34168         }
34169         if (hctx->conf.debug > 1) {
34170 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
34171 +               log_error_write(srv, __FILE__, __LINE__, "sd",
34172                                 "connect succeeded: ", scgi_fd);
34173         }
34174  
34175  
34176 -       
34177 +
34178         return 0;
34179  }
34180  
34181  static int scgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
34182         size_t i;
34183 -       
34184 +
34185         for (i = 0; i < con->request.headers->used; i++) {
34186                 data_string *ds;
34187 -               
34188 +
34189                 ds = (data_string *)con->request.headers->data[i];
34190 -               
34191 +
34192                 if (ds->value->used && ds->key->used) {
34193                         size_t j;
34194                         buffer_reset(srv->tmp_buf);
34195 -                       
34196 +
34197                         if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
34198                                 BUFFER_COPY_STRING_CONST(srv->tmp_buf, "HTTP_");
34199                                 srv->tmp_buf->used--;
34200                         }
34201 -                       
34202 +
34203                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
34204                         for (j = 0; j < ds->key->used - 1; j++) {
34205 -                               srv->tmp_buf->ptr[srv->tmp_buf->used++] = 
34206 -                                       light_isalpha(ds->key->ptr[j]) ? 
34207 +                               srv->tmp_buf->ptr[srv->tmp_buf->used++] =
34208 +                                       light_isalpha(ds->key->ptr[j]) ?
34209                                         ds->key->ptr[j] & ~32 : '_';
34210                         }
34211                         srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
34212 -                       
34213 +
34214                         scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
34215                 }
34216         }
34217 -       
34218 +
34219         for (i = 0; i < con->environment->used; i++) {
34220                 data_string *ds;
34221 -               
34222 +
34223                 ds = (data_string *)con->environment->data[i];
34224 -               
34225 +
34226                 if (ds->value->used && ds->key->used) {
34227                         size_t j;
34228                         buffer_reset(srv->tmp_buf);
34229 -                       
34230 +
34231                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
34232                         for (j = 0; j < ds->key->used - 1; j++) {
34233 -                               srv->tmp_buf->ptr[srv->tmp_buf->used++] = 
34234 -                                       isalpha((unsigned char)ds->key->ptr[j]) ? 
34235 +                               srv->tmp_buf->ptr[srv->tmp_buf->used++] =
34236 +                                       isalpha((unsigned char)ds->key->ptr[j]) ?
34237                                         toupper((unsigned char)ds->key->ptr[j]) : '_';
34238                         }
34239                         srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
34240 -                       
34241 +
34242                         scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
34243                 }
34244         }
34245 -       
34246 +
34247         return 0;
34248  }
34249  
34250 @@ -1415,20 +1400,20 @@
34251         char b2[INET6_ADDRSTRLEN + 1];
34252  #endif
34253         buffer *b;
34254 -       
34255 +
34256         plugin_data *p    = hctx->plugin_data;
34257         scgi_extension_host *host= hctx->host;
34258  
34259         connection *con   = hctx->remote_conn;
34260         server_socket *srv_sock = con->srv_socket;
34261 -       
34262 +
34263         sock_addr our_addr;
34264         socklen_t our_addr_len;
34265 -       
34266 +
34267         buffer_prepare_copy(p->scgi_env, 1024);
34268  
34269         /* CGI-SPEC 6.1.2, FastCGI spec 6.3 and SCGI spec */
34270 -               
34271 +
34272         /* request.content_length < SSIZE_MAX, see request.c */
34273         ltostr(buf, con->request.content_length);
34274         scgi_env_add(p->scgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
34275 @@ -1436,13 +1421,13 @@
34276  
34277  
34278         scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
34279 -       
34280 +
34281         if (con->server_name->used) {
34282                 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
34283         } else {
34284  #ifdef HAVE_IPV6
34285 -               s = inet_ntop(srv_sock->addr.plain.sa_family, 
34286 -                             srv_sock->addr.plain.sa_family == AF_INET6 ? 
34287 +               s = inet_ntop(srv_sock->addr.plain.sa_family,
34288 +                             srv_sock->addr.plain.sa_family == AF_INET6 ?
34289                               (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
34290                               (const void *) &(srv_sock->addr.ipv4.sin_addr),
34291                               b2, sizeof(b2)-1);
34292 @@ -1451,47 +1436,47 @@
34293  #endif
34294                 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
34295         }
34296 -       
34297 +
34298         scgi_env_add(p->scgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
34299 -       
34300 -       ltostr(buf, 
34301 +
34302 +       ltostr(buf,
34303  #ifdef HAVE_IPV6
34304                ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
34305  #else
34306                ntohs(srv_sock->addr.ipv4.sin_port)
34307  #endif
34308                );
34309 -       
34310 +
34311         scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
34312 -       
34313 +
34314         /* get the server-side of the connection to the client */
34315         our_addr_len = sizeof(our_addr);
34316 -       
34317 -       if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
34318 +
34319 +       if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
34320                 s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
34321         } else {
34322                 s = inet_ntop_cache_get_ip(srv, &(our_addr));
34323         }
34324         scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
34325 -       
34326 -       ltostr(buf, 
34327 +
34328 +       ltostr(buf,
34329  #ifdef HAVE_IPV6
34330                ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
34331  #else
34332                ntohs(con->dst_addr.ipv4.sin_port)
34333  #endif
34334                );
34335 -       
34336 +
34337         scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
34338 -       
34339 +
34340         s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
34341         scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
34342 -       
34343 +
34344         if (!buffer_is_empty(con->authed_user)) {
34345                 scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_USER"),
34346                              CONST_BUF_LEN(con->authed_user));
34347         }
34348 -       
34349 +
34350  
34351         /*
34352          * SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to
34353 @@ -1500,12 +1485,12 @@
34354          */
34355  
34356         scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
34357 -               
34358 +
34359         if (!buffer_is_empty(con->request.pathinfo)) {
34360                 scgi_env_add(p->scgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
34361 -               
34362 +
34363                 /* PATH_TRANSLATED is only defined if PATH_INFO is set */
34364 -               
34365 +
34366                 if (!buffer_is_empty(host->docroot)) {
34367                         buffer_copy_string_buffer(p->path, host->docroot);
34368                 } else {
34369 @@ -1526,19 +1511,19 @@
34370          */
34371  
34372         if (!buffer_is_empty(host->docroot)) {
34373 -               /* 
34374 -                * rewrite SCRIPT_FILENAME 
34375 -                * 
34376 +               /*
34377 +                * rewrite SCRIPT_FILENAME
34378 +                *
34379                  */
34380 -               
34381 +
34382                 buffer_copy_string_buffer(p->path, host->docroot);
34383                 buffer_append_string_buffer(p->path, con->uri.path);
34384 -               
34385 +
34386                 scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
34387                 scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot));
34388         } else {
34389                 buffer_copy_string_buffer(p->path, con->physical.path);
34390 -               
34391 +
34392                 scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
34393                 scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
34394         }
34395 @@ -1551,30 +1536,30 @@
34396         } else {
34397                 scgi_env_add(p->scgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
34398         }
34399 -       
34400 +
34401         s = get_http_method_name(con->request.http_method);
34402         scgi_env_add(p->scgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
34403         scgi_env_add(p->scgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
34404         s = get_http_version_name(con->request.http_version);
34405         scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
34406 -       
34407 +
34408  #ifdef USE_OPENSSL
34409         if (srv_sock->is_ssl) {
34410                 scgi_env_add(p->scgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
34411         }
34412  #endif
34413 -       
34414 +
34415         scgi_env_add_request_headers(srv, con, p);
34416  
34417         b = chunkqueue_get_append_buffer(hctx->wb);
34418 -       
34419 +
34420         buffer_append_long(b, p->scgi_env->used);
34421         buffer_append_string_len(b, CONST_STR_LEN(":"));
34422         buffer_append_string_len(b, (const char *)p->scgi_env->ptr, p->scgi_env->used);
34423         buffer_append_string_len(b, CONST_STR_LEN(","));
34424  
34425         hctx->wb->bytes_in += b->used - 1;
34426 -       
34427 +
34428         if (con->request.content_length) {
34429                 chunkqueue *req_cq = con->request_content_queue;
34430                 chunk *req_c;
34431 @@ -1587,7 +1572,7 @@
34432  
34433                         /* we announce toWrite octects
34434                          * now take all the request_content chunk that we need to fill this request
34435 -                        * */   
34436 +                        * */
34437  
34438                         switch (req_c->type) {
34439                         case FILE_CHUNK:
34440 @@ -1615,293 +1600,170 @@
34441  
34442                                 req_c->offset += weHave;
34443                                 req_cq->bytes_out += weHave;
34444 -                               
34445 +
34446                                 hctx->wb->bytes_in += weHave;
34447  
34448                                 break;
34449                         default:
34450                                 break;
34451                         }
34452 -                       
34453 +
34454                         offset += weHave;
34455                 }
34456         }
34457 -       
34458 +
34459  #if 0
34460         for (i = 0; i < hctx->write_buffer->used; i++) {
34461                 fprintf(stderr, "%02x ", hctx->write_buffer->ptr[i]);
34462                 if ((i+1) % 16 == 0) {
34463                         size_t j;
34464                         for (j = i-15; j <= i; j++) {
34465 -                               fprintf(stderr, "%c", 
34466 +                               fprintf(stderr, "%c",
34467                                         isprint((unsigned char)hctx->write_buffer->ptr[j]) ? hctx->write_buffer->ptr[j] : '.');
34468                         }
34469                         fprintf(stderr, "\n");
34470                 }
34471         }
34472  #endif
34473 -       
34474 -       return 0;
34475 -}
34476  
34477 -static int scgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in, int eol) {
34478 -       char *ns;
34479 -       const char *s;
34480 -       int line = 0;
34481 -       
34482 -       UNUSED(srv);
34483 -       
34484 -       buffer_copy_string_buffer(p->parse_response, in);
34485 -       
34486 -       for (s = p->parse_response->ptr; 
34487 -            NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n'))); 
34488 -            s = ns + (eol == EOL_RN ? 2 : 1), line++) {
34489 -               const char *key, *value;
34490 -               int key_len;
34491 -               data_string *ds;
34492 -               
34493 -               ns[0] = '\0';
34494 -               
34495 -               if (line == 0 && 
34496 -                   0 == strncmp(s, "HTTP/1.", 7)) {
34497 -                       /* non-parsed header ... we parse them anyway */
34498 -                       
34499 -                       if ((s[7] == '1' ||
34500 -                            s[7] == '0') &&
34501 -                           s[8] == ' ') {
34502 -                               int status;
34503 -                               /* after the space should be a status code for us */
34504 -                               
34505 -                               status = strtol(s+9, NULL, 10);
34506 -                               
34507 -                               if (con->http_status >= 100 &&
34508 -                                   con->http_status < 1000) {
34509 -                                       /* we expected 3 digits and didn't got them */
34510 -                                       con->parsed_response |= HTTP_STATUS;
34511 -                                       con->http_status = status;
34512 -                               }
34513 -                       }
34514 -               } else {
34515 -               
34516 -                       key = s;
34517 -                       if (NULL == (value = strchr(s, ':'))) {
34518 -                               /* we expect: "<key>: <value>\r\n" */
34519 -                               continue;
34520 -                       }
34521 -                       
34522 -                       key_len = value - key;
34523 -                       value += 1;
34524 -                       
34525 -                       /* skip LWS */
34526 -                       while (*value == ' ' || *value == '\t') value++;
34527 -                       
34528 -                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
34529 -                               ds = data_response_init();
34530 -                       }
34531 -                       buffer_copy_string_len(ds->key, key, key_len);
34532 -                       buffer_copy_string(ds->value, value);
34533 -                       
34534 -                       array_insert_unique(con->response.headers, (data_unset *)ds);
34535 -                       
34536 -                       switch(key_len) {
34537 -                       case 4:
34538 -                               if (0 == strncasecmp(key, "Date", key_len)) {
34539 -                                       con->parsed_response |= HTTP_DATE;
34540 -                               }
34541 -                               break;
34542 -                       case 6:
34543 -                               if (0 == strncasecmp(key, "Status", key_len)) {
34544 -                                       con->http_status = strtol(value, NULL, 10);
34545 -                                       con->parsed_response |= HTTP_STATUS;
34546 -                               }
34547 -                               break;
34548 -                       case 8:
34549 -                               if (0 == strncasecmp(key, "Location", key_len)) {
34550 -                                       con->parsed_response |= HTTP_LOCATION;
34551 -                               }
34552 -                               break;
34553 -                       case 10:
34554 -                               if (0 == strncasecmp(key, "Connection", key_len)) {
34555 -                                       con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
34556 -                                       con->parsed_response |= HTTP_CONNECTION;
34557 -                               }
34558 -                               break;
34559 -                       case 14:
34560 -                               if (0 == strncasecmp(key, "Content-Length", key_len)) {
34561 -                                       con->response.content_length = strtol(value, NULL, 10);
34562 -                                       con->parsed_response |= HTTP_CONTENT_LENGTH;
34563 -                               }
34564 -                               break;
34565 -                       default:
34566 -                               break;
34567 -                       }
34568 -               }
34569 -       }
34570 -       
34571 -       /* CGI/1.1 rev 03 - 7.2.1.2 */
34572 -       if ((con->parsed_response & HTTP_LOCATION) &&
34573 -           !(con->parsed_response & HTTP_STATUS)) {
34574 -               con->http_status = 302;
34575 -       }
34576 -       
34577         return 0;
34578  }
34579  
34580 -
34581  static int scgi_demux_response(server *srv, handler_ctx *hctx) {
34582         plugin_data *p    = hctx->plugin_data;
34583         connection  *con  = hctx->remote_conn;
34584 -       
34585 -       while(1) {
34586 -               int n;
34587 -               
34588 -               buffer_prepare_copy(hctx->response, 1024);
34589 -               if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {
34590 -                       if (errno == EAGAIN || errno == EINTR) {
34591 -                               /* would block, wait for signal */
34592 -                               return 0;
34593 -                       }
34594 -                       /* error */
34595 -                       log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd);
34596 -                       return -1;
34597 -               }
34598 -               
34599 -               if (n == 0) {
34600 -                       /* read finished */
34601 -                       
34602 -                       con->file_finished = 1;
34603 -                       
34604 -                       /* send final chunk */
34605 -                       http_chunk_append_mem(srv, con, NULL, 0);
34606 -                       joblist_append(srv, con);
34607 -                       
34608 +       chunk *c;
34609 +
34610 +       switch(srv->network_backend_read(srv, con, hctx->sock, hctx->rb)) {
34611 +       case NETWORK_STATUS_SUCCESS:
34612 +               /* we got content */
34613 +               break;
34614 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
34615 +               /* the ioctl will return WAIT_FOR_EVENT on a read */
34616 +               if (0 == con->file_started) return -1;
34617 +       case NETWORK_STATUS_CONNECTION_CLOSE:
34618 +               /* we are done, get out of here */
34619 +               con->file_finished = 1;
34620 +
34621 +               /* close the chunk-queue with a empty chunk */
34622 +
34623 +               return 1;
34624 +       default:
34625 +               /* oops */
34626 +               return -1;
34627 +       }
34628 +
34629 +       /* looks like we got some content
34630 +       *
34631 +       * split off the header from the incoming stream
34632 +       */
34633 +
34634 +       if (hctx->state == SCGI_STATE_RESPONSE_HEADER) {
34635 +               size_t i;
34636 +               int have_content_length = 0;
34637 +
34638 +               http_response_reset(p->resp);
34639 +
34640 +               /* the response header is not fully received yet,
34641 +               *
34642 +               * extract the http-response header from the rb-cq
34643 +               */
34644 +               switch (http_response_parse_cq(hctx->rb, p->resp)) {
34645 +               case PARSE_ERROR:
34646 +                       /* parsing failed */
34647 +
34648 +                       con->http_status = 502; /* Bad Gateway */
34649                         return 1;
34650 -               }
34651 -               
34652 -               hctx->response->ptr[n] = '\0';
34653 -               hctx->response->used = n+1;
34654 -               
34655 -               /* split header from body */
34656 -               
34657 -               if (con->file_started == 0) {
34658 -                       char *c;
34659 -                       int in_header = 0;
34660 -                       int header_end = 0;
34661 -                       int cp, eol = EOL_UNSET;
34662 -                       size_t used = 0;
34663 -                       
34664 -                       buffer_append_string_buffer(hctx->response_header, hctx->response);
34665 -                       
34666 -                       /* nph (non-parsed headers) */
34667 -                       if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;
34668 -                       
34669 -                       /* search for the \r\n\r\n or \n\n in the string */
34670 -                       for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) {
34671 -                               if (*c == ':') in_header = 1;
34672 -                               else if (*c == '\n') {
34673 -                                       if (in_header == 0) {
34674 -                                               /* got a response without a response header */
34675 -                                               
34676 -                                               c = NULL;
34677 -                                               header_end = 1;
34678 -                                               break;
34679 -                                       }
34680 -                                       
34681 -                                       if (eol == EOL_UNSET) eol = EOL_N;
34682 -                                       
34683 -                                       if (*(c+1) == '\n') {
34684 -                                               header_end = 1;
34685 -                                               break;
34686 -                                       }
34687 -                                       
34688 -                               } else if (used > 1 && *c == '\r' && *(c+1) == '\n') {
34689 -                                       if (in_header == 0) {
34690 -                                               /* got a response without a response header */
34691 -                                               
34692 -                                               c = NULL;
34693 -                                               header_end = 1;
34694 -                                               break;
34695 -                                       }
34696 -                                       
34697 -                                       if (eol == EOL_UNSET) eol = EOL_RN;
34698 -                                       
34699 -                                       if (used > 3 &&
34700 -                                           *(c+2) == '\r' && 
34701 -                                           *(c+3) == '\n') {
34702 -                                               header_end = 1;
34703 -                                               break;
34704 -                                       }
34705 -                                       
34706 -                                       /* skip the \n */
34707 -                                       c++;
34708 -                                       cp++;
34709 -                                       used--;
34710 +               case PARSE_NEED_MORE:
34711 +                       return 0;
34712 +               case PARSE_SUCCESS:
34713 +                       con->http_status = p->resp->status;
34714 +
34715 +                       chunkqueue_remove_finished_chunks(hctx->rb);
34716 +
34717 +                       /* copy the http-headers */
34718 +                       for (i = 0; i < p->resp->headers->used; i++) {
34719 +                               const char *ign[] = { "Status", "Connection", NULL };
34720 +                               size_t j;
34721 +                               data_string *ds;
34722 +
34723 +                               data_string *header = (data_string *)p->resp->headers->data[i];
34724 +
34725 +                               /* some headers are ignored by default */
34726 +                               for (j = 0; ign[j]; j++) {
34727 +                                       if (0 == strcasecmp(ign[j], header->key->ptr)) break;
34728                                 }
34729 -                       }
34730 -                       
34731 -                       if (header_end) {
34732 -                               if (c == NULL) {
34733 -                                       /* no header, but a body */
34734 -                                       
34735 -                                       if (con->request.http_version == HTTP_VERSION_1_1) {
34736 -                                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
34737 -                                       }
34738 -                                       
34739 -                                       http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
34740 -                                       joblist_append(srv, con);
34741 -                               } else {
34742 -                                       size_t hlen = c - hctx->response_header->ptr + (eol == EOL_RN ? 4 : 2);
34743 -                                       size_t blen = hctx->response_header->used - hlen - 1;
34744 -                               
34745 -                                       /* a small hack: terminate after at the second \r */
34746 -                                       hctx->response_header->used = hlen + 1 - (eol == EOL_RN ? 2 : 1);
34747 -                                       hctx->response_header->ptr[hlen - (eol == EOL_RN ? 2 : 1)] = '\0';
34748 -                               
34749 -                                       /* parse the response header */
34750 -                                       scgi_response_parse(srv, con, p, hctx->response_header, eol);
34751 -                                       
34752 -                                       /* enable chunked-transfer-encoding */
34753 -                                       if (con->request.http_version == HTTP_VERSION_1_1 &&
34754 -                                           !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
34755 -                                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
34756 -                                       }
34757 -                                       
34758 -                                       if ((hctx->response->used != hlen) && blen > 0) {
34759 -                                               http_chunk_append_mem(srv, con, c + (eol == EOL_RN ? 4: 2), blen + 1);
34760 -                                               joblist_append(srv, con);
34761 -                                       }
34762 +                               if (ign[j]) continue;
34763 +
34764 +                               if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
34765 +                                       /* CGI/1.1 rev 03 - 7.2.1.2 */
34766 +                                       if (con->http_status == 0) con->http_status = 302;
34767 +                               } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
34768 +                                       have_content_length = 1;
34769                                 }
34770                                 
34771 -                               con->file_started = 1;
34772 +                               if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
34773 +                                       ds = data_response_init();
34774 +                               }
34775 +                               buffer_copy_string_buffer(ds->key, header->key);
34776 +                               buffer_copy_string_buffer(ds->value, header->value);
34777 +
34778 +                               array_insert_unique(con->response.headers, (data_unset *)ds);
34779                         }
34780 -               } else {
34781 -                       http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
34782 -                       joblist_append(srv, con);
34783 +
34784 +                       con->file_started = 1;
34785 +
34786 +                       if (con->request.http_version == HTTP_VERSION_1_1 &&
34787 +                           !have_content_length) {
34788 +                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
34789 +                       }
34790 +
34791 +                       hctx->state = SCGI_STATE_RESPONSE_CONTENT;
34792 +                       break;
34793                 }
34794 -               
34795 -#if 0          
34796 -               log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr);
34797 -#endif
34798         }
34799 -       
34800 +
34801 +       /* FIXME: pass the response-header to the other plugins to
34802 +       * setup the filter-queue
34803 +       *
34804 +       * - use next-queue instead of con->write_queue
34805 +       */
34806 +
34807 +       assert(hctx->state == SCGI_STATE_RESPONSE_CONTENT);
34808 +
34809 +       /* FIXME: if we have a content-length or chunked-encoding
34810 +       * handle it.
34811 +       *
34812 +       * for now we wait for EOF on the socket */
34813 +
34814 +       /* copy the content to the next cq */
34815 +       for (c = hctx->rb->first; c; c = c->next) {
34816 +               http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
34817 +
34818 +               c->offset = c->mem->used - 1;
34819 +       }
34820 +
34821 +       chunkqueue_remove_finished_chunks(hctx->rb);
34822 +       joblist_append(srv, con);
34823 +
34824         return 0;
34825  }
34826  
34827  
34828  int scgi_proclist_sort_up(server *srv, scgi_extension_host *host, scgi_proc *proc) {
34829         scgi_proc *p;
34830 -       
34831 +
34832         UNUSED(srv);
34833 -       
34834 -       /* we have been the smallest of the current list 
34835 -        * and we want to insert the node sorted as soon 
34836 +
34837 +       /* we have been the smallest of the current list
34838 +        * and we want to insert the node sorted as soon
34839          * possible
34840          *
34841 -        * 1 0 0 0 1 1 1 
34842 -        * |      ^ 
34843 +        * 1 0 0 0 1 1 1
34844 +        * |      ^
34845          * |      |
34846          * +------+
34847 -        * 
34848 +        *
34849          */
34850  
34851         /* nothing to sort, only one element */
34852 @@ -1909,9 +1771,9 @@
34853  
34854         for (p = proc; p->next && p->next->load < proc->load; p = p->next);
34855  
34856 -       /* no need to move something 
34857 +       /* no need to move something
34858          *
34859 -        * 1 2 2 2 3 3 3 
34860 +        * 1 2 2 2 3 3 3
34861          * ^
34862          * |
34863          * +
34864 @@ -1930,16 +1792,16 @@
34865  
34866         if (proc->prev) proc->prev->next = proc->next;
34867         if (proc->next) proc->next->prev = proc->prev;
34868 -       
34869 +
34870         /* proc should be right of p */
34871 -       
34872 +
34873         proc->next = p->next;
34874         proc->prev = p;
34875         if (p->next) p->next->prev = proc;
34876         p->next = proc;
34877  #if 0
34878         for(p = host->first; p; p = p->next) {
34879 -               log_error_write(srv, __FILE__, __LINE__, "dd", 
34880 +               log_error_write(srv, __FILE__, __LINE__, "dd",
34881                                 p->pid, p->load);
34882         }
34883  #else
34884 @@ -1951,21 +1813,21 @@
34885  
34886  int scgi_proclist_sort_down(server *srv, scgi_extension_host *host, scgi_proc *proc) {
34887         scgi_proc *p;
34888 -       
34889 +
34890         UNUSED(srv);
34891 -       
34892 -       /* we have been the smallest of the current list 
34893 -        * and we want to insert the node sorted as soon 
34894 +
34895 +       /* we have been the smallest of the current list
34896 +        * and we want to insert the node sorted as soon
34897          * possible
34898          *
34899 -        *  0 0 0 0 1 0 1 
34900 +        *  0 0 0 0 1 0 1
34901          * ^          |
34902          * |          |
34903          * +----------+
34904          *
34905          *
34906          * the basic is idea is:
34907 -        * - the last active scgi process should be still 
34908 +        * - the last active scgi process should be still
34909          *   in ram and is not swapped out yet
34910          * - processes that are not reused will be killed
34911          *   after some time by the trigger-handler
34912 @@ -1975,7 +1837,7 @@
34913          *   ice-cold processes are propably unused since more
34914          *   than 'unused-timeout', are swaped out and won't be
34915          *   reused in the next seconds anyway.
34916 -        * 
34917 +        *
34918          */
34919  
34920         /* nothing to sort, only one element */
34921 @@ -1984,16 +1846,16 @@
34922         for (p = host->first; p != proc && p->load < proc->load; p = p->next);
34923  
34924  
34925 -       /* no need to move something 
34926 +       /* no need to move something
34927          *
34928 -        * 1 2 2 2 3 3 3 
34929 +        * 1 2 2 2 3 3 3
34930          * ^
34931          * |
34932          * +
34933          *
34934          */
34935         if (p == proc) return 0;
34936 -       
34937 +
34938         /* we have to move left. If we are already the first element
34939          * we are done */
34940         if (host->first == proc) return 0;
34941 @@ -2009,9 +1871,9 @@
34942         p->prev = proc;
34943  
34944         if (proc->prev == NULL) host->first = proc;
34945 -#if 0  
34946 +#if 0
34947         for(p = host->first; p; p = p->next) {
34948 -               log_error_write(srv, __FILE__, __LINE__, "dd", 
34949 +               log_error_write(srv, __FILE__, __LINE__, "dd",
34950                                 p->pid, p->load);
34951         }
34952  #else
34953 @@ -2023,41 +1885,42 @@
34954  
34955  static int scgi_restart_dead_procs(server *srv, plugin_data *p, scgi_extension_host *host) {
34956         scgi_proc *proc;
34957 -       
34958 +
34959         for (proc = host->first; proc; proc = proc->next) {
34960                 if (p->conf.debug) {
34961 -                       log_error_write(srv, __FILE__, __LINE__,  "sbdbdddd", 
34962 -                                       "proc:", 
34963 -                                       host->host, proc->port, 
34964 +                       log_error_write(srv, __FILE__, __LINE__,  "sbdbdddd",
34965 +                                       "proc:",
34966 +                                       host->host, proc->port,
34967                                         proc->socket,
34968                                         proc->state,
34969                                         proc->is_local,
34970                                         proc->load,
34971                                         proc->pid);
34972                 }
34973 -               
34974 +
34975                 if (0 == proc->is_local) {
34976 -                       /* 
34977 -                        * external servers might get disabled 
34978 -                        * 
34979 -                        * enable the server again, perhaps it is back again 
34980 +                       /*
34981 +                        * external servers might get disabled
34982 +                        *
34983 +                        * enable the server again, perhaps it is back again
34984                          */
34985 -                       
34986 +
34987                         if ((proc->state == PROC_STATE_DISABLED) &&
34988                             (srv->cur_ts - proc->disable_ts > host->disable_time)) {
34989                                 proc->state = PROC_STATE_RUNNING;
34990                                 host->active_procs++;
34991 -                               
34992 -                               log_error_write(srv, __FILE__, __LINE__,  "sbdb", 
34993 -                                               "fcgi-server re-enabled:", 
34994 -                                               host->host, host->port, 
34995 +
34996 +                               log_error_write(srv, __FILE__, __LINE__,  "sbdb",
34997 +                                               "fcgi-server re-enabled:",
34998 +                                               host->host, host->port,
34999                                                 host->unixsocket);
35000                         }
35001                 } else {
35002                         /* the child should not terminate at all */
35003                         int status;
35004 -                       
35005 +
35006                         if (proc->state == PROC_STATE_DIED_WAIT_FOR_PID) {
35007 +#ifndef _WIN32
35008                                 switch(waitpid(proc->pid, &status, WNOHANG)) {
35009                                 case 0:
35010                                         /* child is still alive */
35011 @@ -2067,33 +1930,34 @@
35012                                 default:
35013                                         if (WIFEXITED(status)) {
35014  #if 0
35015 -                                               log_error_write(srv, __FILE__, __LINE__, "sdsd", 
35016 +                                               log_error_write(srv, __FILE__, __LINE__, "sdsd",
35017                                                                 "child exited, pid:", proc->pid,
35018                                                                 "status:", WEXITSTATUS(status));
35019  #endif
35020                                         } else if (WIFSIGNALED(status)) {
35021 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
35022 -                                                               "child signaled:", 
35023 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
35024 +                                                               "child signaled:",
35025                                                                 WTERMSIG(status));
35026                                         } else {
35027 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
35028 -                                                               "child died somehow:", 
35029 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
35030 +                                                               "child died somehow:",
35031                                                                 status);
35032                                         }
35033 -                                       
35034 +
35035                                         proc->state = PROC_STATE_DIED;
35036                                         break;
35037                                 }
35038 +#endif
35039                         }
35040 -                       
35041 -                       /* 
35042 +
35043 +                       /*
35044                          * local servers might died, but we restart them
35045 -                        * 
35046 +                        *
35047                          */
35048                         if (proc->state == PROC_STATE_DIED &&
35049                             proc->load == 0) {
35050                                 /* restart the child */
35051 -                               
35052 +
35053                                 if (p->conf.debug) {
35054                                         log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
35055                                                         "--- scgi spawning",
35056 @@ -2101,18 +1965,18 @@
35057                                                         "\n\tsocket", host->unixsocket,
35058                                                         "\n\tcurrent:", 1, "/", host->min_procs);
35059                                 }
35060 -                               
35061 +
35062                                 if (scgi_spawn_connection(srv, p, host, proc)) {
35063                                         log_error_write(srv, __FILE__, __LINE__, "s",
35064                                                         "ERROR: spawning fcgi failed.");
35065                                         return HANDLER_ERROR;
35066                                 }
35067 -                               
35068 +
35069                                 scgi_proclist_sort_down(srv, host, proc);
35070                         }
35071                 }
35072         }
35073 -       
35074 +
35075         return 0;
35076  }
35077  
35078 @@ -2121,13 +1985,13 @@
35079         plugin_data *p    = hctx->plugin_data;
35080         scgi_extension_host *host= hctx->host;
35081         connection *con   = hctx->remote_conn;
35082 -       
35083 +
35084         int ret;
35085  
35086 -       /* sanity check */      
35087 +       /* sanity check */
35088         if (!host ||
35089             ((!host->host->used || !host->port) && !host->unixsocket->used)) {
35090 -               log_error_write(srv, __FILE__, __LINE__, "sxddd", 
35091 +               log_error_write(srv, __FILE__, __LINE__, "sxddd",
35092                                 "write-req: error",
35093                                 host,
35094                                 host->host->used,
35095 @@ -2135,259 +1999,260 @@
35096                                 host->unixsocket->used);
35097                 return HANDLER_ERROR;
35098         }
35099 -       
35100 +
35101  
35102         switch(hctx->state) {
35103 -       case FCGI_STATE_INIT:
35104 +       case SCGI_STATE_INIT:
35105                 ret = host->unixsocket->used ? AF_UNIX : AF_INET;
35106 -               
35107 -               if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
35108 +
35109 +               if (-1 == (hctx->sock->fd = socket(ret, SOCK_STREAM, 0))) {
35110                         if (errno == EMFILE ||
35111                             errno == EINTR) {
35112 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
35113 -                                               "wait for fd at connection:", con->fd);
35114 -                               
35115 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
35116 +                                               "wait for fd at connection:", con->sock->fd);
35117 +
35118                                 return HANDLER_WAIT_FOR_FD;
35119                         }
35120 -                       
35121 -                       log_error_write(srv, __FILE__, __LINE__, "ssdd", 
35122 +
35123 +                       log_error_write(srv, __FILE__, __LINE__, "ssdd",
35124                                         "socket failed:", strerror(errno), srv->cur_fds, srv->max_fds);
35125                         return HANDLER_ERROR;
35126                 }
35127 -               hctx->fde_ndx = -1;
35128 -               
35129 +               hctx->sock->fde_ndx = -1;
35130 +
35131                 srv->cur_fds++;
35132 -               
35133 -               fdevent_register(srv->ev, hctx->fd, scgi_handle_fdevent, hctx);
35134 -               
35135 -               if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
35136 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
35137 +
35138 +               fdevent_register(srv->ev, hctx->sock, scgi_handle_fdevent, hctx);
35139 +
35140 +               if (-1 == fdevent_fcntl_set(srv->ev, hctx->sock)) {
35141 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
35142                                         "fcntl failed: ", strerror(errno));
35143 -                       
35144 +
35145                         return HANDLER_ERROR;
35146                 }
35147 -               
35148 +
35149                 /* fall through */
35150 -       case FCGI_STATE_CONNECT:
35151 -               if (hctx->state == FCGI_STATE_INIT) {
35152 -                       for (hctx->proc = hctx->host->first; 
35153 -                            hctx->proc && hctx->proc->state != PROC_STATE_RUNNING; 
35154 +       case SCGI_STATE_CONNECT:
35155 +               if (hctx->state == SCGI_STATE_INIT) {
35156 +                       for (hctx->proc = hctx->host->first;
35157 +                            hctx->proc && hctx->proc->state != PROC_STATE_RUNNING;
35158                              hctx->proc = hctx->proc->next);
35159 -                       
35160 +
35161                         /* all childs are dead */
35162                         if (hctx->proc == NULL) {
35163 -                               hctx->fde_ndx = -1;
35164 -                               
35165 +                               hctx->sock->fde_ndx = -1;
35166 +
35167                                 return HANDLER_ERROR;
35168                         }
35169 -                       
35170 +
35171                         if (hctx->proc->is_local) {
35172                                 hctx->pid = hctx->proc->pid;
35173                         }
35174 -                       
35175 +
35176                         switch (scgi_establish_connection(srv, hctx)) {
35177                         case 1:
35178 -                               scgi_set_state(srv, hctx, FCGI_STATE_CONNECT);
35179 -                               
35180 +                               scgi_set_state(srv, hctx, SCGI_STATE_CONNECT);
35181 +
35182                                 /* connection is in progress, wait for an event and call getsockopt() below */
35183 -                               
35184 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
35185 -                               
35186 +
35187 +                               fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
35188 +
35189                                 return HANDLER_WAIT_FOR_EVENT;
35190                         case -1:
35191                                 /* if ECONNREFUSED choose another connection -> FIXME */
35192 -                               hctx->fde_ndx = -1;
35193 -                               
35194 +                               hctx->sock->fde_ndx = -1;
35195 +
35196                                 return HANDLER_ERROR;
35197                         default:
35198                                 /* everything is ok, go on */
35199                                 break;
35200                         }
35201  
35202 -                       
35203 +
35204                 } else {
35205                         int socket_error;
35206                         socklen_t socket_error_len = sizeof(socket_error);
35207 -                       
35208 +
35209                         /* try to finish the connect() */
35210 -                       if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
35211 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
35212 +                       if (0 != getsockopt(hctx->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
35213 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
35214                                                 "getsockopt failed:", strerror(errno));
35215 -                               
35216 +
35217                                 return HANDLER_ERROR;
35218                         }
35219                         if (socket_error != 0) {
35220                                 if (!hctx->proc->is_local || p->conf.debug) {
35221                                         /* local procs get restarted */
35222 -                                       
35223 +
35224                                         log_error_write(srv, __FILE__, __LINE__, "ss",
35225 -                                                       "establishing connection failed:", strerror(socket_error), 
35226 +                                                       "establishing connection failed:", strerror(socket_error),
35227                                                         "port:", hctx->proc->port);
35228                                 }
35229 -                               
35230 +
35231                                 return HANDLER_ERROR;
35232                         }
35233                 }
35234 -               
35235 +
35236                 /* ok, we have the connection */
35237 -               
35238 +
35239                 hctx->proc->load++;
35240                 hctx->proc->last_used = srv->cur_ts;
35241                 hctx->got_proc = 1;
35242 -               
35243 +
35244                 if (p->conf.debug) {
35245                         log_error_write(srv, __FILE__, __LINE__, "sddbdd",
35246 -                                       "got proc:", 
35247 -                                       hctx->fd,
35248 -                                       hctx->proc->pid, 
35249 -                                       hctx->proc->socket, 
35250 +                                       "got proc:",
35251 +                                       hctx->sock->fd,
35252 +                                       hctx->proc->pid,
35253 +                                       hctx->proc->socket,
35254                                         hctx->proc->port,
35255                                         hctx->proc->load);
35256                 }
35257  
35258                 /* move the proc-list entry down the list */
35259                 scgi_proclist_sort_up(srv, hctx->host, hctx->proc);
35260 -               
35261 -               scgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
35262 +
35263 +               scgi_set_state(srv, hctx, SCGI_STATE_PREPARE_WRITE);
35264                 /* fall through */
35265 -       case FCGI_STATE_PREPARE_WRITE:
35266 +       case SCGI_STATE_PREPARE_WRITE:
35267                 scgi_create_env(srv, hctx);
35268 -               
35269 -               scgi_set_state(srv, hctx, FCGI_STATE_WRITE);
35270 -               
35271 +
35272 +               scgi_set_state(srv, hctx, SCGI_STATE_WRITE);
35273 +
35274                 /* fall through */
35275 -       case FCGI_STATE_WRITE:
35276 -               ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); 
35277 +       case SCGI_STATE_WRITE:
35278 +               ret = srv->network_backend_write(srv, con, hctx->sock, hctx->wb);
35279  
35280                 chunkqueue_remove_finished_chunks(hctx->wb);
35281 -       
35282 +
35283                 if (-1 == ret) {
35284                         if (errno == ENOTCONN) {
35285 -                               /* the connection got dropped after accept() 
35286 -                                * 
35287 -                                * this is most of the time a PHP which dies 
35288 +                               /* the connection got dropped after accept()
35289 +                                *
35290 +                                * this is most of the time a PHP which dies
35291                                  * after PHP_FCGI_MAX_REQUESTS
35292 -                                * 
35293 -                                */ 
35294 +                                *
35295 +                                */
35296                                 if (hctx->wb->bytes_out == 0 &&
35297                                     hctx->reconnects < 5) {
35298 -                                       usleep(10000); /* take away the load of the webserver 
35299 -                                                       * to let the php a chance to restart 
35300 +#ifndef _WIN32
35301 +                                       usleep(10000); /* take away the load of the webserver
35302 +                                                       * to let the php a chance to restart
35303                                                         */
35304 -                                       
35305 +#endif
35306                                         scgi_reconnect(srv, hctx);
35307 -                               
35308 +
35309                                         return HANDLER_WAIT_FOR_FD;
35310                                 }
35311 -                               
35312 +
35313                                 /* not reconnected ... why
35314 -                                * 
35315 +                                *
35316                                  * far@#lighttpd report this for FreeBSD
35317 -                                * 
35318 +                                *
35319                                  */
35320 -                               
35321 -                               log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
35322 +
35323 +                               log_error_write(srv, __FILE__, __LINE__, "ssosd",
35324                                                 "[REPORT ME] connection was dropped after accept(). reconnect() denied:",
35325                                                 "write-offset:", hctx->wb->bytes_out,
35326                                                 "reconnect attempts:", hctx->reconnects);
35327 -                               
35328 +
35329                                 return HANDLER_ERROR;
35330                         }
35331 -                       
35332 +
35333                         if ((errno != EAGAIN) &&
35334                             (errno != EINTR)) {
35335 -                               
35336 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", 
35337 +
35338 +                               log_error_write(srv, __FILE__, __LINE__, "ssd",
35339                                                 "write failed:", strerror(errno), errno);
35340 -                               
35341 +
35342                                 return HANDLER_ERROR;
35343                         } else {
35344 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
35345 -                               
35346 +                               fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
35347 +
35348                                 return HANDLER_WAIT_FOR_EVENT;
35349                         }
35350                 }
35351 -               
35352 +
35353                 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
35354                         /* we don't need the out event anymore */
35355 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
35356 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
35357 -                       scgi_set_state(srv, hctx, FCGI_STATE_READ);
35358 +                       fdevent_event_del(srv->ev, hctx->sock);
35359 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
35360 +                       scgi_set_state(srv, hctx, SCGI_STATE_RESPONSE_HEADER);
35361                 } else {
35362 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
35363 -                       
35364 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
35365 +
35366                         return HANDLER_WAIT_FOR_EVENT;
35367                 }
35368 -               
35369 +
35370                 break;
35371 -       case FCGI_STATE_READ:
35372 +       case SCGI_STATE_RESPONSE_HEADER:
35373                 /* waiting for a response */
35374                 break;
35375         default:
35376                 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
35377                 return HANDLER_ERROR;
35378         }
35379 -       
35380 +
35381         return HANDLER_WAIT_FOR_EVENT;
35382  }
35383  
35384  SUBREQUEST_FUNC(mod_scgi_handle_subrequest) {
35385         plugin_data *p = p_d;
35386 -       
35387 +
35388         handler_ctx *hctx = con->plugin_ctx[p->id];
35389         scgi_proc *proc;
35390         scgi_extension_host *host;
35391 -       
35392 +
35393         if (NULL == hctx) return HANDLER_GO_ON;
35394 -       
35395 +
35396         /* not my job */
35397         if (con->mode != p->id) return HANDLER_GO_ON;
35398 -       
35399 +
35400         /* ok, create the request */
35401         switch(scgi_write_request(srv, hctx)) {
35402         case HANDLER_ERROR:
35403                 proc = hctx->proc;
35404                 host = hctx->host;
35405 -               
35406 -               if (proc && 
35407 +
35408 +               if (proc &&
35409                     0 == proc->is_local &&
35410                     proc->state != PROC_STATE_DISABLED) {
35411                         /* only disable remote servers as we don't manage them*/
35412 -                       
35413 -                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", "fcgi-server disabled:", 
35414 +
35415 +                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", "fcgi-server disabled:",
35416                                         host->host,
35417                                         proc->port,
35418                                         proc->socket);
35419 -                       
35420 +
35421                         /* disable this server */
35422                         proc->disable_ts = srv->cur_ts;
35423                         proc->state = PROC_STATE_DISABLED;
35424                         host->active_procs--;
35425                 }
35426 -               
35427 -               if (hctx->state == FCGI_STATE_INIT ||
35428 -                   hctx->state == FCGI_STATE_CONNECT) {
35429 -                       /* connect() or getsockopt() failed, 
35430 -                        * restart the request-handling 
35431 +
35432 +               if (hctx->state == SCGI_STATE_INIT ||
35433 +                   hctx->state == SCGI_STATE_CONNECT) {
35434 +                       /* connect() or getsockopt() failed,
35435 +                        * restart the request-handling
35436                          */
35437                         if (proc && proc->is_local) {
35438  
35439                                 if (p->conf.debug) {
35440 -                                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", "connect() to scgi failed, restarting the request-handling:", 
35441 +                                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", "connect() to scgi failed, restarting the request-handling:",
35442                                                         host->host,
35443                                                         proc->port,
35444                                                         proc->socket);
35445                                 }
35446  
35447 -                               /* 
35448 +                               /*
35449                                  * several hctx might reference the same proc
35450 -                                * 
35451 +                                *
35452                                  * Only one of them should mark the proc as dead all the other
35453                                  * ones should just take a new one.
35454 -                                * 
35455 +                                *
35456                                  * If a new proc was started with the old struct this might lead
35457                                  * the mark a perfect proc as dead otherwise
35458 -                                * 
35459 +                                *
35460                                  */
35461                                 if (proc->state == PROC_STATE_RUNNING &&
35462                                     hctx->pid == proc->pid) {
35463 @@ -2395,25 +2260,25 @@
35464                                 }
35465                         }
35466                         scgi_restart_dead_procs(srv, p, host);
35467 -                       
35468 +
35469                         scgi_connection_cleanup(srv, hctx);
35470 -                       
35471 +
35472                         buffer_reset(con->physical.path);
35473                         con->mode = DIRECT;
35474                         joblist_append(srv, con);
35475 -                       
35476 -                       /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop 
35477 -                        * and hope that the childs will be restarted 
35478 -                        * 
35479 +
35480 +                       /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
35481 +                        * and hope that the childs will be restarted
35482 +                        *
35483                          */
35484                         return HANDLER_WAIT_FOR_FD;
35485                 } else {
35486                         scgi_connection_cleanup(srv, hctx);
35487 -                       
35488 +
35489                         buffer_reset(con->physical.path);
35490                         con->mode = DIRECT;
35491                         con->http_status = 503;
35492 -                       
35493 +
35494                         return HANDLER_FINISHED;
35495                 }
35496         case HANDLER_WAIT_FOR_EVENT:
35497 @@ -2433,23 +2298,23 @@
35498  static handler_t scgi_connection_close(server *srv, handler_ctx *hctx) {
35499         plugin_data *p;
35500         connection  *con;
35501 -       
35502 +
35503         if (NULL == hctx) return HANDLER_GO_ON;
35504 -       
35505 +
35506         p    = hctx->plugin_data;
35507         con  = hctx->remote_conn;
35508 -       
35509 +
35510         if (con->mode != p->id) return HANDLER_GO_ON;
35511 -       
35512 -       log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
35513 -                       "emergency exit: scgi:", 
35514 -                       "connection-fd:", con->fd,
35515 -                       "fcgi-fd:", hctx->fd);
35516 -       
35517 -       
35518 -       
35519 +
35520 +       log_error_write(srv, __FILE__, __LINE__, "ssdsd",
35521 +                       "emergency exit: scgi:",
35522 +                       "connection-fd:", con->sock->fd,
35523 +                       "fcgi-fd:", hctx->sock->fd);
35524 +
35525 +
35526 +
35527         scgi_connection_cleanup(srv, hctx);
35528 -       
35529 +
35530         return HANDLER_FINISHED;
35531  }
35532  
35533 @@ -2459,27 +2324,28 @@
35534         handler_ctx *hctx = ctx;
35535         connection  *con  = hctx->remote_conn;
35536         plugin_data *p    = hctx->plugin_data;
35537 -       
35538 +
35539         scgi_proc *proc   = hctx->proc;
35540         scgi_extension_host *host= hctx->host;
35541  
35542         if ((revents & FDEVENT_IN) &&
35543 -           hctx->state == FCGI_STATE_READ) {
35544 +           (hctx->state == SCGI_STATE_RESPONSE_HEADER ||
35545 +            hctx->state == SCGI_STATE_RESPONSE_CONTENT)) {
35546                 switch (scgi_demux_response(srv, hctx)) {
35547                 case 0:
35548                         break;
35549                 case 1:
35550                         /* we are done */
35551                         scgi_connection_cleanup(srv, hctx);
35552 -                       
35553 +
35554                         joblist_append(srv, con);
35555                         return HANDLER_FINISHED;
35556                 case -1:
35557                         if (proc->pid && proc->state != PROC_STATE_DIED) {
35558                                 int status;
35559 -                               
35560 +
35561                                 /* only fetch the zombie if it is not already done */
35562 -                               
35563 +#ifndef _WIN32
35564                                 switch(waitpid(proc->pid, &status, WNOHANG)) {
35565                                 case 0:
35566                                         /* child is still alive */
35567 @@ -2489,19 +2355,19 @@
35568                                 default:
35569                                         /* the child should not terminate at all */
35570                                         if (WIFEXITED(status)) {
35571 -                                               log_error_write(srv, __FILE__, __LINE__, "sdsd", 
35572 +                                               log_error_write(srv, __FILE__, __LINE__, "sdsd",
35573                                                                 "child exited, pid:", proc->pid,
35574                                                                 "status:", WEXITSTATUS(status));
35575                                         } else if (WIFSIGNALED(status)) {
35576 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
35577 -                                                               "child signaled:", 
35578 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
35579 +                                                               "child signaled:",
35580                                                                 WTERMSIG(status));
35581                                         } else {
35582 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
35583 -                                                               "child died somehow:", 
35584 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
35585 +                                                               "child died somehow:",
35586                                                                 status);
35587                                         }
35588 -                                       
35589 +
35590                                         if (p->conf.debug) {
35591                                                 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
35592                                                                 "--- scgi spawning",
35593 @@ -2509,40 +2375,41 @@
35594                                                                 "\n\tsocket", host->unixsocket,
35595                                                                 "\n\tcurrent:", 1, "/", host->min_procs);
35596                                         }
35597 -                                       
35598 +
35599                                         if (scgi_spawn_connection(srv, p, host, proc)) {
35600                                                 /* child died */
35601                                                 proc->state = PROC_STATE_DIED;
35602                                         } else {
35603                                                 scgi_proclist_sort_down(srv, host, proc);
35604                                         }
35605 -                                       
35606 +
35607                                         break;
35608                                 }
35609 +#endif
35610                         }
35611  
35612                         if (con->file_started == 0) {
35613                                 /* nothing has been send out yet, try to use another child */
35614 -                               
35615 +
35616                                 if (hctx->wb->bytes_out == 0 &&
35617                                     hctx->reconnects < 5) {
35618                                         scgi_reconnect(srv, hctx);
35619 -                                       
35620 -                                       log_error_write(srv, __FILE__, __LINE__, "sdsdsd", 
35621 +
35622 +                                       log_error_write(srv, __FILE__, __LINE__, "sdsdsd",
35623                                                 "response not sent, request not sent, reconnection.",
35624 -                                               "connection-fd:", con->fd,
35625 -                                               "fcgi-fd:", hctx->fd);
35626 -                                       
35627 +                                               "connection-fd:", con->sock->fd,
35628 +                                               "fcgi-fd:", hctx->sock->fd);
35629 +
35630                                         return HANDLER_WAIT_FOR_FD;
35631                                 }
35632 -                               
35633 -                               log_error_write(srv, __FILE__, __LINE__, "sdsdsd", 
35634 +
35635 +                               log_error_write(srv, __FILE__, __LINE__, "sosdsd",
35636                                                 "response not sent, request sent:", hctx->wb->bytes_out,
35637 -                                               "connection-fd:", con->fd,
35638 -                                               "fcgi-fd:", hctx->fd);
35639 -                               
35640 +                                               "connection-fd:", con->sock->fd,
35641 +                                               "fcgi-fd:", hctx->sock->fd);
35642 +
35643                                 scgi_connection_cleanup(srv, hctx);
35644 -                               
35645 +
35646                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
35647                                 buffer_reset(con->physical.path);
35648                                 con->http_status = 500;
35649 @@ -2550,76 +2417,77 @@
35650                         } else {
35651                                 /* response might have been already started, kill the connection */
35652                                 scgi_connection_cleanup(srv, hctx);
35653 -                               
35654 -                               log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
35655 +
35656 +                               log_error_write(srv, __FILE__, __LINE__, "ssdsd",
35657                                                 "response already sent out, termination connection",
35658 -                                               "connection-fd:", con->fd,
35659 -                                               "fcgi-fd:", hctx->fd);
35660 -                               
35661 +                                               "connection-fd:", con->sock->fd,
35662 +                                               "fcgi-fd:", hctx->sock->fd);
35663 +
35664                                 connection_set_state(srv, con, CON_STATE_ERROR);
35665                         }
35666  
35667                         /* */
35668 -                       
35669 -                       
35670 +
35671 +
35672                         joblist_append(srv, con);
35673                         return HANDLER_FINISHED;
35674                 }
35675         }
35676 -       
35677 +
35678         if (revents & FDEVENT_OUT) {
35679 -               if (hctx->state == FCGI_STATE_CONNECT ||
35680 -                   hctx->state == FCGI_STATE_WRITE) {
35681 +               if (hctx->state == SCGI_STATE_CONNECT ||
35682 +                   hctx->state == SCGI_STATE_WRITE) {
35683                         /* we are allowed to send something out
35684 -                        * 
35685 +                        *
35686                          * 1. in a unfinished connect() call
35687                          * 2. in a unfinished write() call (long POST request)
35688                          */
35689                         return mod_scgi_handle_subrequest(srv, con, p);
35690                 } else {
35691 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
35692 -                                       "got a FDEVENT_OUT and didn't know why:", 
35693 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
35694 +                                       "got a FDEVENT_OUT and didn't know why:",
35695                                         hctx->state);
35696                 }
35697         }
35698 -       
35699 +
35700         /* perhaps this issue is already handled */
35701         if (revents & FDEVENT_HUP) {
35702 -               if (hctx->state == FCGI_STATE_CONNECT) {
35703 +               if (hctx->state == SCGI_STATE_CONNECT) {
35704                         /* getoptsock will catch this one (right ?)
35705 -                        * 
35706 -                        * if we are in connect we might get a EINPROGRESS 
35707 -                        * in the first call and a FDEVENT_HUP in the 
35708 +                        *
35709 +                        * if we are in connect we might get a EINPROGRESS
35710 +                        * in the first call and a FDEVENT_HUP in the
35711                          * second round
35712 -                        * 
35713 +                        *
35714                          * FIXME: as it is a bit ugly.
35715 -                        * 
35716 +                        *
35717                          */
35718                         return mod_scgi_handle_subrequest(srv, con, p);
35719 -               } else if (hctx->state == FCGI_STATE_READ &&
35720 +               } else if ((hctx->state == SCGI_STATE_RESPONSE_HEADER ||
35721 +                           hctx->state == SCGI_STATE_RESPONSE_CONTENT ) &&
35722                            hctx->proc->port == 0) {
35723                         /* FIXME:
35724 -                        * 
35725 +                        *
35726                          * ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket
35727                          * even if the FCGI_FIN packet is not received yet
35728                          */
35729                 } else {
35730 -                       log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd", 
35731 -                                       "error: unexpected close of scgi connection for", 
35732 +                       log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
35733 +                                       "error: unexpected close of scgi connection for",
35734                                         con->uri.path,
35735 -                                       "(no scgi process on host: ", 
35736 +                                       "(no scgi process on host: ",
35737                                         host->host,
35738 -                                       ", port: ", 
35739 +                                       ", port: ",
35740                                         host->port,
35741                                         " ?)",
35742                                         hctx->state);
35743 -                       
35744 +
35745                         connection_set_state(srv, con, CON_STATE_ERROR);
35746                         scgi_connection_close(srv, hctx);
35747                         joblist_append(srv, con);
35748                 }
35749         } else if (revents & FDEVENT_ERR) {
35750 -               log_error_write(srv, __FILE__, __LINE__, "s", 
35751 +               log_error_write(srv, __FILE__, __LINE__, "s",
35752                                 "fcgi: got a FDEVENT_ERR. Don't know why.");
35753                 /* kill all connections to the scgi process */
35754  
35755 @@ -2628,42 +2496,39 @@
35756                 scgi_connection_close(srv, hctx);
35757                 joblist_append(srv, con);
35758         }
35759 -       
35760 +
35761         return HANDLER_FINISHED;
35762  }
35763 -#define PATCH(x) \
35764 -       p->conf.x = s->x;
35765 +
35766  static int scgi_patch_connection(server *srv, connection *con, plugin_data *p) {
35767         size_t i, j;
35768         plugin_config *s = p->config_storage[0];
35769 -       
35770 -       PATCH(exts);
35771 -       PATCH(debug);
35772 -       
35773 +
35774 +       PATCH_OPTION(exts);
35775 +       PATCH_OPTION(debug);
35776 +
35777         /* skip the first, the global context */
35778         for (i = 1; i < srv->config_context->used; i++) {
35779                 data_config *dc = (data_config *)srv->config_context->data[i];
35780                 s = p->config_storage[i];
35781 -               
35782 +
35783                 /* condition didn't match */
35784                 if (!config_check_cond(srv, con, dc)) continue;
35785 -               
35786 +
35787                 /* merge config */
35788                 for (j = 0; j < dc->value->used; j++) {
35789                         data_unset *du = dc->value->data[j];
35790 -                       
35791 +
35792                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.server"))) {
35793 -                               PATCH(exts);
35794 +                               PATCH_OPTION(exts);
35795                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.debug"))) {
35796 -                               PATCH(debug);
35797 +                               PATCH_OPTION(debug);
35798                         }
35799                 }
35800         }
35801 -       
35802 +
35803         return 0;
35804  }
35805 -#undef PATCH
35806 -
35807  
35808  static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
35809         plugin_data *p = p_d;
35810 @@ -2673,30 +2538,30 @@
35811         size_t k;
35812         buffer *fn;
35813         scgi_extension *extension = NULL;
35814 -       
35815 +
35816         /* Possibly, we processed already this request */
35817         if (con->file_started == 1) return HANDLER_GO_ON;
35818 -       
35819 +
35820         fn = uri_path_handler ? con->uri.path : con->physical.path;
35821  
35822         if (buffer_is_empty(fn)) return HANDLER_GO_ON;
35823  
35824         s_len = fn->used - 1;
35825 -       
35826 +
35827         scgi_patch_connection(srv, con, p);
35828  
35829         /* check if extension matches */
35830         for (k = 0; k < p->conf.exts->used; k++) {
35831                 size_t ct_len;
35832 -               
35833 +
35834                 extension = p->conf.exts->exts[k];
35835 -               
35836 +
35837                 if (extension->key->used == 0) continue;
35838 -               
35839 +
35840                 ct_len = extension->key->used - 1;
35841 -               
35842 +
35843                 if (s_len < ct_len) continue;
35844 -               
35845 +
35846                 /* check extension in the form "/scgi_pattern" */
35847                 if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
35848                         break;
35849 @@ -2710,17 +2575,17 @@
35850         if (k == p->conf.exts->used) {
35851                 return HANDLER_GO_ON;
35852         }
35853 -       
35854 +
35855         /* get best server */
35856         for (k = 0, ndx = -1; k < extension->used; k++) {
35857                 scgi_extension_host *host = extension->hosts[k];
35858 -               
35859 +
35860                 /* we should have at least one proc that can do somthing */
35861                 if (host->active_procs == 0) continue;
35862  
35863                 if (used == -1 || host->load < used) {
35864                         used = host->load;
35865 -                       
35866 +
35867                         ndx = k;
35868                 }
35869         }
35870 @@ -2728,12 +2593,12 @@
35871         /* found a server */
35872         if (ndx != -1) {
35873                 scgi_extension_host *host = extension->hosts[ndx];
35874 -               
35875 -               /* 
35876 -                * if check-local is disabled, use the uri.path handler 
35877 -                * 
35878 +
35879 +               /*
35880 +                * if check-local is disabled, use the uri.path handler
35881 +                *
35882                  */
35883 -               
35884 +
35885                 /* init handler-context */
35886                 if (uri_path_handler) {
35887                         if (host->check_local == 0) {
35888 @@ -2741,7 +2606,7 @@
35889                                 char *pathinfo;
35890  
35891                                 hctx = handler_ctx_init();
35892 -                               
35893 +
35894                                 hctx->remote_conn      = con;
35895                                 hctx->plugin_data      = p;
35896                                 hctx->host             = host;
35897 @@ -2749,45 +2614,45 @@
35898  
35899                                 hctx->conf.exts        = p->conf.exts;
35900                                 hctx->conf.debug       = p->conf.debug;
35901 -                               
35902 +
35903                                 con->plugin_ctx[p->id] = hctx;
35904 -                               
35905 +
35906                                 host->load++;
35907 -                               
35908 +
35909                                 con->mode = p->id;
35910  
35911                                 if (con->conf.log_request_handling) {
35912                                         log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_scgi");
35913                                 }
35914  
35915 -                               /* the prefix is the SCRIPT_NAME, 
35916 +                               /* the prefix is the SCRIPT_NAME,
35917                                  * everthing from start to the next slash
35918                                  * this is important for check-local = "disable"
35919 -                                * 
35920 +                                *
35921                                  * if prefix = /admin.fcgi
35922 -                                * 
35923 +                                *
35924                                  * /admin.fcgi/foo/bar
35925 -                                * 
35926 +                                *
35927                                  * SCRIPT_NAME = /admin.fcgi
35928                                  * PATH_INFO   = /foo/bar
35929 -                                * 
35930 +                                *
35931                                  * if prefix = /fcgi-bin/
35932 -                                * 
35933 +                                *
35934                                  * /fcgi-bin/foo/bar
35935 -                                * 
35936 +                                *
35937                                  * SCRIPT_NAME = /fcgi-bin/foo
35938                                  * PATH_INFO   = /bar
35939 -                                * 
35940 +                                *
35941                                  */
35942 -                               
35943 +
35944                                 /* the rewrite is only done for /prefix/? matches */
35945                                 if (extension->key->ptr[0] == '/' &&
35946                                     con->uri.path->used > extension->key->used &&
35947                                     NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
35948 -                                       /* rewrite uri.path and pathinfo */ 
35949 -                                       
35950 +                                       /* rewrite uri.path and pathinfo */
35951 +
35952                                         buffer_copy_string(con->request.pathinfo, pathinfo);
35953 -                                       
35954 +
35955                                         con->uri.path->used -= con->request.pathinfo->used - 1;
35956                                         con->uri.path->ptr[con->uri.path->used - 1] = '\0';
35957                                 }
35958 @@ -2796,21 +2661,21 @@
35959                 } else {
35960                         handler_ctx *hctx;
35961                         hctx = handler_ctx_init();
35962 -                       
35963 +
35964                         hctx->remote_conn      = con;
35965                         hctx->plugin_data      = p;
35966                         hctx->host             = host;
35967                         hctx->proc             = NULL;
35968 -                       
35969 +
35970                         hctx->conf.exts        = p->conf.exts;
35971                         hctx->conf.debug       = p->conf.debug;
35972 -                       
35973 +
35974                         con->plugin_ctx[p->id] = hctx;
35975 -                       
35976 +
35977                         host->load++;
35978 -                       
35979 +
35980                         con->mode = p->id;
35981 -                       
35982 +
35983                         if (con->conf.log_request_handling) {
35984                                 log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
35985                         }
35986 @@ -2821,11 +2686,11 @@
35987                 /* no handler found */
35988                 buffer_reset(con->physical.path);
35989                 con->http_status = 500;
35990 -               
35991 -               log_error_write(srv, __FILE__, __LINE__,  "sb", 
35992 -                               "no fcgi-handler found for:", 
35993 +
35994 +               log_error_write(srv, __FILE__, __LINE__,  "sb",
35995 +                               "no fcgi-handler found for:",
35996                                 fn);
35997 -               
35998 +
35999                 return HANDLER_FINISHED;
36000         }
36001         return HANDLER_GO_ON;
36002 @@ -2844,21 +2709,22 @@
36003  JOBLIST_FUNC(mod_scgi_handle_joblist) {
36004         plugin_data *p = p_d;
36005         handler_ctx *hctx = con->plugin_ctx[p->id];
36006 -       
36007 +
36008         if (hctx == NULL) return HANDLER_GO_ON;
36009  
36010 -       if (hctx->fd != -1) {
36011 +       if (hctx->sock->fd != -1) {
36012                 switch (hctx->state) {
36013 -               case FCGI_STATE_READ:
36014 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
36015 -                       
36016 +               case SCGI_STATE_RESPONSE_HEADER:
36017 +               case SCGI_STATE_RESPONSE_CONTENT:
36018 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
36019 +
36020                         break;
36021 -               case FCGI_STATE_CONNECT:
36022 -               case FCGI_STATE_WRITE:
36023 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
36024 -                       
36025 +               case SCGI_STATE_CONNECT:
36026 +               case SCGI_STATE_WRITE:
36027 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
36028 +
36029                         break;
36030 -               case FCGI_STATE_INIT:
36031 +               case SCGI_STATE_INIT:
36032                         /* at reconnect */
36033                         break;
36034                 default:
36035 @@ -2873,21 +2739,21 @@
36036  
36037  static handler_t scgi_connection_close_callback(server *srv, connection *con, void *p_d) {
36038         plugin_data *p = p_d;
36039 -       
36040 +
36041         return scgi_connection_close(srv, con->plugin_ctx[p->id]);
36042  }
36043  
36044  TRIGGER_FUNC(mod_scgi_handle_trigger) {
36045         plugin_data *p = p_d;
36046         size_t i, j, n;
36047 -       
36048 -       
36049 +
36050 +
36051         /* perhaps we should kill a connect attempt after 10-15 seconds
36052 -        * 
36053 +        *
36054          * currently we wait for the TCP timeout which is on Linux 180 seconds
36055 -        * 
36056 -        * 
36057 -        * 
36058 +        *
36059 +        *
36060 +        *
36061          */
36062  
36063         /* check all childs if they are still up */
36064 @@ -2904,47 +2770,47 @@
36065                         scgi_extension *ex;
36066  
36067                         ex = exts->exts[j];
36068 -                       
36069 +
36070                         for (n = 0; n < ex->used; n++) {
36071 -                               
36072 +
36073                                 scgi_proc *proc;
36074                                 unsigned long sum_load = 0;
36075                                 scgi_extension_host *host;
36076 -                               
36077 +
36078                                 host = ex->hosts[n];
36079 -                               
36080 +
36081                                 scgi_restart_dead_procs(srv, p, host);
36082 -                               
36083 +
36084                                 for (proc = host->first; proc; proc = proc->next) {
36085                                         sum_load += proc->load;
36086                                 }
36087 -                               
36088 +
36089                                 if (host->num_procs &&
36090                                     host->num_procs < host->max_procs &&
36091                                     (sum_load / host->num_procs) > host->max_load_per_proc) {
36092                                         /* overload, spawn new child */
36093                                         scgi_proc *fp = NULL;
36094 -                                       
36095 +
36096                                         if (p->conf.debug) {
36097 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
36098 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
36099                                                                 "overload detected, spawning a new child");
36100                                         }
36101 -                                       
36102 +
36103                                         for (fp = host->unused_procs; fp && fp->pid != 0; fp = fp->next);
36104 -                                       
36105 +
36106                                         if (fp) {
36107                                                 if (fp == host->unused_procs) host->unused_procs = fp->next;
36108 -                                               
36109 +
36110                                                 if (fp->next) fp->next->prev = NULL;
36111 -                                               
36112 +
36113                                                 host->max_id++;
36114                                         } else {
36115                                                 fp = scgi_process_init();
36116                                                 fp->id = host->max_id++;
36117                                         }
36118 -                                       
36119 +
36120                                         host->num_procs++;
36121 -                                       
36122 +
36123                                         if (buffer_is_empty(host->unixsocket)) {
36124                                                 fp->port = host->port + fp->id;
36125                                         } else {
36126 @@ -2952,13 +2818,13 @@
36127                                                 buffer_append_string(fp->socket, "-");
36128                                                 buffer_append_long(fp->socket, fp->id);
36129                                         }
36130 -                                       
36131 +
36132                                         if (scgi_spawn_connection(srv, p, host, fp)) {
36133                                                 log_error_write(srv, __FILE__, __LINE__, "s",
36134                                                                 "ERROR: spawning fcgi failed.");
36135                                                 return HANDLER_ERROR;
36136                                         }
36137 -                                       
36138 +
36139                                         fp->prev = NULL;
36140                                         fp->next = host->first;
36141                                         if (host->first) {
36142 @@ -2966,56 +2832,57 @@
36143                                         }
36144                                         host->first = fp;
36145                                 }
36146 -                               
36147 +
36148                                 for (proc = host->first; proc; proc = proc->next) {
36149                                         if (proc->load != 0) break;
36150                                         if (host->num_procs <= host->min_procs) break;
36151                                         if (proc->pid == 0) continue;
36152 -                                       
36153 +#ifndef _WIN32
36154                                         if (srv->cur_ts - proc->last_used > host->idle_timeout) {
36155                                                 /* a proc is idling for a long time now,
36156                                                  * terminated it */
36157 -                                               
36158 +
36159                                                 if (p->conf.debug) {
36160 -                                                       log_error_write(srv, __FILE__, __LINE__, "ssbsd", 
36161 -                                                                       "idle-timeout reached, terminating child:", 
36162 -                                                                       "socket:", proc->socket, 
36163 +                                                       log_error_write(srv, __FILE__, __LINE__, "ssbsd",
36164 +                                                                       "idle-timeout reached, terminating child:",
36165 +                                                                       "socket:", proc->socket,
36166                                                                         "pid", proc->pid);
36167                                                 }
36168 -                                               
36169 -                                               
36170 +
36171 +
36172                                                 if (proc->next) proc->next->prev = proc->prev;
36173                                                 if (proc->prev) proc->prev->next = proc->next;
36174 -                                               
36175 +
36176                                                 if (proc->prev == NULL) host->first = proc->next;
36177 -                                               
36178 +
36179                                                 proc->prev = NULL;
36180                                                 proc->next = host->unused_procs;
36181 -                                               
36182 +
36183                                                 if (host->unused_procs) host->unused_procs->prev = proc;
36184                                                 host->unused_procs = proc;
36185 -                                               
36186 +
36187                                                 kill(proc->pid, SIGTERM);
36188 -                                               
36189 +
36190                                                 proc->state = PROC_STATE_KILLED;
36191 -                                               
36192 -                                               log_error_write(srv, __FILE__, __LINE__, "ssbsd", 
36193 -                                                                       "killed:", 
36194 -                                                                       "socket:", proc->socket, 
36195 +
36196 +                                               log_error_write(srv, __FILE__, __LINE__, "ssbsd",
36197 +                                                                       "killed:",
36198 +                                                                       "socket:", proc->socket,
36199                                                                         "pid", proc->pid);
36200 -                                               
36201 +
36202                                                 host->num_procs--;
36203 -                                               
36204 +
36205                                                 /* proc is now in unused, let the next second handle the next process */
36206                                                 break;
36207 -                                       }       
36208 +                                       }
36209 +#endif
36210                                 }
36211 -                               
36212 +
36213                                 for (proc = host->unused_procs; proc; proc = proc->next) {
36214                                         int status;
36215 -                                       
36216 +
36217                                         if (proc->pid == 0) continue;
36218 -                                       
36219 +#ifndef _WIN32
36220                                         switch (waitpid(proc->pid, &status, WNOHANG)) {
36221                                         case 0:
36222                                                 /* child still running after timeout, good */
36223 @@ -3023,10 +2890,10 @@
36224                                         case -1:
36225                                                 if (errno != EINTR) {
36226                                                         /* no PID found ? should never happen */
36227 -                                                       log_error_write(srv, __FILE__, __LINE__, "sddss", 
36228 +                                                       log_error_write(srv, __FILE__, __LINE__, "sddss",
36229                                                                         "pid ", proc->pid, proc->state,
36230                                                                         "not found:", strerror(errno));
36231 -                                                       
36232 +
36233  #if 0
36234                                                         if (errno == ECHILD) {
36235                                                                 /* someone else has cleaned up for us */
36236 @@ -3040,25 +2907,26 @@
36237                                                 /* the child should not terminate at all */
36238                                                 if (WIFEXITED(status)) {
36239                                                         if (proc->state != PROC_STATE_KILLED) {
36240 -                                                               log_error_write(srv, __FILE__, __LINE__, "sdb", 
36241 -                                                                               "child exited:", 
36242 +                                                               log_error_write(srv, __FILE__, __LINE__, "sdb",
36243 +                                                                               "child exited:",
36244                                                                                 WEXITSTATUS(status), proc->socket);
36245                                                         }
36246                                                 } else if (WIFSIGNALED(status)) {
36247                                                         if (WTERMSIG(status) != SIGTERM) {
36248 -                                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
36249 -                                                                               "child signaled:", 
36250 +                                                               log_error_write(srv, __FILE__, __LINE__, "sd",
36251 +                                                                               "child signaled:",
36252                                                                                 WTERMSIG(status));
36253                                                         }
36254                                                 } else {
36255 -                                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
36256 -                                                                       "child died somehow:", 
36257 +                                                       log_error_write(srv, __FILE__, __LINE__, "sd",
36258 +                                                                       "child died somehow:",
36259                                                                         status);
36260                                                 }
36261                                                 proc->pid = 0;
36262                                                 proc->state = PROC_STATE_UNSET;
36263                                                 host->max_id--;
36264                                         }
36265 +#endif
36266                                 }
36267                         }
36268                 }
36269 @@ -3082,8 +2950,8 @@
36270         p->handle_subrequest       = mod_scgi_handle_subrequest;
36271         p->handle_joblist          = mod_scgi_handle_joblist;
36272         p->handle_trigger          = mod_scgi_handle_trigger;
36273 -       
36274 +
36275         p->data         = NULL;
36276 -       
36277 +
36278         return 0;
36279  }
36280 --- ../lighttpd-1.4.11/src/mod_secure_download.c        2005-12-14 14:37:29.000000000 +0200
36281 +++ lighttpd-1.4.12/src/mod_secure_download.c   2006-07-16 00:26:03.000000000 +0300
36282 @@ -25,7 +25,7 @@
36283  #ifdef USE_OPENSSL
36284  #define IN const
36285  #else
36286 -#define IN 
36287 +#define IN
36288  #endif
36289  #define OUT
36290  
36291 @@ -36,28 +36,28 @@
36292         buffer *doc_root;
36293         buffer *secret;
36294         buffer *uri_prefix;
36295 -       
36296 +
36297         unsigned short timeout;
36298  } plugin_config;
36299  
36300  typedef struct {
36301         PLUGIN_DATA;
36302 -       
36303 +
36304         buffer *md5;
36305 -       
36306 +
36307         plugin_config **config_storage;
36308 -       
36309 -       plugin_config conf; 
36310 +
36311 +       plugin_config conf;
36312  } plugin_data;
36313  
36314  /* init the plugin data */
36315  INIT_FUNC(mod_secdownload_init) {
36316         plugin_data *p;
36317 -       
36318 +
36319         p = calloc(1, sizeof(*p));
36320 -       
36321 +
36322         p->md5 = buffer_init();
36323 -       
36324 +
36325         return p;
36326  }
36327  
36328 @@ -65,27 +65,27 @@
36329  FREE_FUNC(mod_secdownload_free) {
36330         plugin_data *p = p_d;
36331         UNUSED(srv);
36332 -       
36333 +
36334         if (!p) return HANDLER_GO_ON;
36335 -       
36336 +
36337         if (p->config_storage) {
36338                 size_t i;
36339                 for (i = 0; i < srv->config_context->used; i++) {
36340                         plugin_config *s = p->config_storage[i];
36341 -                       
36342 +
36343                         buffer_free(s->secret);
36344                         buffer_free(s->doc_root);
36345                         buffer_free(s->uri_prefix);
36346 -                       
36347 +
36348                         free(s);
36349                 }
36350                 free(p->config_storage);
36351         }
36352 -       
36353 +
36354         buffer_free(p->md5);
36355 -       
36356 +
36357         free(p);
36358 -       
36359 +
36360         return HANDLER_GO_ON;
36361  }
36362  
36363 @@ -94,107 +94,103 @@
36364  SETDEFAULTS_FUNC(mod_secdownload_set_defaults) {
36365         plugin_data *p = p_d;
36366         size_t i = 0;
36367 -       
36368 -       config_values_t cv[] = { 
36369 +
36370 +       config_values_t cv[] = {
36371                 { "secdownload.secret",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
36372                 { "secdownload.document-root",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
36373                 { "secdownload.uri-prefix",        NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
36374                 { "secdownload.timeout",           NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 3 */
36375                 { NULL,                            NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
36376         };
36377 -       
36378 +
36379         if (!p) return HANDLER_ERROR;
36380 -       
36381 +
36382         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
36383 -       
36384 +
36385         for (i = 0; i < srv->config_context->used; i++) {
36386                 plugin_config *s;
36387 -               
36388 +
36389                 s = calloc(1, sizeof(plugin_config));
36390                 s->secret        = buffer_init();
36391                 s->doc_root      = buffer_init();
36392                 s->uri_prefix    = buffer_init();
36393                 s->timeout       = 60;
36394 -               
36395 +
36396                 cv[0].destination = s->secret;
36397                 cv[1].destination = s->doc_root;
36398                 cv[2].destination = s->uri_prefix;
36399                 cv[3].destination = &(s->timeout);
36400 -               
36401 +
36402                 p->config_storage[i] = s;
36403 -       
36404 +
36405                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
36406                         return HANDLER_ERROR;
36407                 }
36408         }
36409 -       
36410 +
36411         return HANDLER_GO_ON;
36412  }
36413  
36414  /**
36415   * checks if the supplied string is a MD5 string
36416 - * 
36417 + *
36418   * @param str a possible MD5 string
36419   * @return if the supplied string is a valid MD5 string 1 is returned otherwise 0
36420   */
36421  
36422  int is_hex_len(const char *str, size_t len) {
36423         size_t i;
36424 -       
36425 +
36426         if (NULL == str) return 0;
36427 -       
36428 +
36429         for (i = 0; i < len && *str; i++, str++) {
36430                 /* illegal characters */
36431                 if (!((*str >= '0' && *str <= '9') ||
36432                       (*str >= 'a' && *str <= 'f') ||
36433 -                     (*str >= 'A' && *str <= 'F')) 
36434 +                     (*str >= 'A' && *str <= 'F'))
36435                     ) {
36436                         return 0;
36437                 }
36438         }
36439 -       
36440 +
36441         return i == len;
36442  }
36443  
36444 -#define PATCH(x) \
36445 -       p->conf.x = s->x;
36446  static int mod_secdownload_patch_connection(server *srv, connection *con, plugin_data *p) {
36447         size_t i, j;
36448         plugin_config *s = p->config_storage[0];
36449 -       
36450 -       PATCH(secret);
36451 -       PATCH(doc_root);
36452 -       PATCH(uri_prefix);
36453 -       PATCH(timeout);
36454 -       
36455 +
36456 +       PATCH_OPTION(secret);
36457 +       PATCH_OPTION(doc_root);
36458 +       PATCH_OPTION(uri_prefix);
36459 +       PATCH_OPTION(timeout);
36460 +
36461         /* skip the first, the global context */
36462         for (i = 1; i < srv->config_context->used; i++) {
36463                 data_config *dc = (data_config *)srv->config_context->data[i];
36464                 s = p->config_storage[i];
36465 -               
36466 +
36467                 /* condition didn't match */
36468                 if (!config_check_cond(srv, con, dc)) continue;
36469 -               
36470 +
36471                 /* merge config */
36472                 for (j = 0; j < dc->value->used; j++) {
36473                         data_unset *du = dc->value->data[j];
36474 -                       
36475 +
36476                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.secret"))) {
36477 -                               PATCH(secret);
36478 +                               PATCH_OPTION(secret);
36479                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.document-root"))) {
36480 -                               PATCH(doc_root);
36481 +                               PATCH_OPTION(doc_root);
36482                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.uri-prefix"))) {
36483 -                               PATCH(uri_prefix);
36484 +                               PATCH_OPTION(uri_prefix);
36485                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.timeout"))) {
36486 -                               PATCH(timeout);
36487 +                               PATCH_OPTION(timeout);
36488                         }
36489                 }
36490         }
36491 -       
36492 +
36493         return 0;
36494  }
36495 -#undef PATCH
36496 -
36497  
36498  URIHANDLER_FUNC(mod_secdownload_uri_handler) {
36499         plugin_data *p = p_d;
36500 @@ -203,88 +199,88 @@
36501         const char *rel_uri, *ts_str, *md5_str;
36502         time_t ts = 0;
36503         size_t i;
36504 -       
36505 +
36506         if (con->uri.path->used == 0) return HANDLER_GO_ON;
36507 -       
36508 +
36509         mod_secdownload_patch_connection(srv, con, p);
36510  
36511         if (buffer_is_empty(p->conf.uri_prefix)) return HANDLER_GO_ON;
36512 -       
36513 +
36514         if (buffer_is_empty(p->conf.secret)) {
36515                 log_error_write(srv, __FILE__, __LINE__, "s",
36516                                 "secdownload.secret has to be set");
36517                 return HANDLER_ERROR;
36518         }
36519 -       
36520 +
36521         if (buffer_is_empty(p->conf.doc_root)) {
36522                 log_error_write(srv, __FILE__, __LINE__, "s",
36523                                 "secdownload.document-root has to be set");
36524                 return HANDLER_ERROR;
36525         }
36526 -       
36527 -       /* 
36528 +
36529 +       /*
36530          *  /<uri-prefix>[a-f0-9]{32}/[a-f0-9]{8}/<rel-path>
36531          */
36532 -       
36533 +
36534         if (0 != strncmp(con->uri.path->ptr, p->conf.uri_prefix->ptr, p->conf.uri_prefix->used - 1)) return HANDLER_GO_ON;
36535 -       
36536 +
36537         md5_str = con->uri.path->ptr + p->conf.uri_prefix->used - 1;
36538 -       
36539 +
36540         if (!is_hex_len(md5_str, 32)) return HANDLER_GO_ON;
36541         if (*(md5_str + 32) != '/') return HANDLER_GO_ON;
36542 -       
36543 +
36544         ts_str = md5_str + 32 + 1;
36545 -       
36546 +
36547         if (!is_hex_len(ts_str, 8)) return HANDLER_GO_ON;
36548         if (*(ts_str + 8) != '/') return HANDLER_GO_ON;
36549 -       
36550 +
36551         for (i = 0; i < 8; i++) {
36552                 ts = (ts << 4) + hex2int(*(ts_str + i));
36553         }
36554 -       
36555 +
36556         /* timed-out */
36557 -       if (srv->cur_ts - ts > p->conf.timeout || 
36558 +       if (srv->cur_ts - ts > p->conf.timeout ||
36559             srv->cur_ts - ts < -p->conf.timeout) {
36560                 con->http_status = 408;
36561 -               
36562 +
36563                 return HANDLER_FINISHED;
36564         }
36565 -       
36566 +
36567         rel_uri = ts_str + 8;
36568 -       
36569 -       /* checking MD5 
36570 -        * 
36571 +
36572 +       /* checking MD5
36573 +        *
36574          * <secret><rel-path><timestamp-hex>
36575          */
36576 -       
36577 +
36578         buffer_copy_string_buffer(p->md5, p->conf.secret);
36579         buffer_append_string(p->md5, rel_uri);
36580         buffer_append_string_len(p->md5, ts_str, 8);
36581 -       
36582 +
36583         MD5_Init(&Md5Ctx);
36584         MD5_Update(&Md5Ctx, (unsigned char *)p->md5->ptr, p->md5->used - 1);
36585         MD5_Final(HA1, &Md5Ctx);
36586 -       
36587 +
36588         buffer_copy_string_hex(p->md5, (char *)HA1, 16);
36589 -       
36590 +
36591         if (0 != strncmp(md5_str, p->md5->ptr, 32)) {
36592                 con->http_status = 403;
36593 -               
36594 -               log_error_write(srv, __FILE__, __LINE__, "sss", 
36595 +
36596 +               log_error_write(srv, __FILE__, __LINE__, "sss",
36597                                 "md5 invalid:",
36598                                 md5_str, p->md5->ptr);
36599 -               
36600 +
36601                 return HANDLER_FINISHED;
36602         }
36603 -       
36604 +
36605         /* starting with the last / we should have relative-path to the docroot
36606          */
36607 -       
36608 +
36609         buffer_copy_string_buffer(con->physical.doc_root, p->conf.doc_root);
36610         buffer_copy_string(con->physical.rel_path, rel_uri);
36611         buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
36612         buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
36613 -       
36614 +
36615         return HANDLER_GO_ON;
36616  }
36617  
36618 @@ -293,13 +289,13 @@
36619  int mod_secdownload_plugin_init(plugin *p) {
36620         p->version     = LIGHTTPD_VERSION_ID;
36621         p->name        = buffer_init_string("secdownload");
36622 -       
36623 +
36624         p->init        = mod_secdownload_init;
36625         p->handle_physical  = mod_secdownload_uri_handler;
36626         p->set_defaults  = mod_secdownload_set_defaults;
36627         p->cleanup     = mod_secdownload_free;
36628 -       
36629 +
36630         p->data        = NULL;
36631 -       
36632 +
36633         return 0;
36634  }
36635 --- ../lighttpd-1.4.11/src/mod_setenv.c 2006-01-14 20:33:12.000000000 +0200
36636 +++ lighttpd-1.4.12/src/mod_setenv.c    2006-07-16 00:26:04.000000000 +0300
36637 @@ -18,25 +18,25 @@
36638  typedef struct {
36639         array *request_header;
36640         array *response_header;
36641 -       
36642 +
36643         array *environment;
36644  } plugin_config;
36645  
36646  typedef struct {
36647         PLUGIN_DATA;
36648 -       
36649 +
36650         plugin_config **config_storage;
36651 -       
36652 -       plugin_config conf; 
36653 +
36654 +       plugin_config conf;
36655  } plugin_data;
36656  
36657  static handler_ctx * handler_ctx_init() {
36658         handler_ctx * hctx;
36659 -       
36660 +
36661         hctx = calloc(1, sizeof(*hctx));
36662 -       
36663 +
36664         hctx->handled = 0;
36665 -       
36666 +
36667         return hctx;
36668  }
36669  
36670 @@ -48,36 +48,36 @@
36671  /* init the plugin data */
36672  INIT_FUNC(mod_setenv_init) {
36673         plugin_data *p;
36674 -       
36675 +
36676         p = calloc(1, sizeof(*p));
36677 -       
36678 +
36679         return p;
36680  }
36681  
36682  /* detroy the plugin data */
36683  FREE_FUNC(mod_setenv_free) {
36684         plugin_data *p = p_d;
36685 -       
36686 +
36687         UNUSED(srv);
36688  
36689         if (!p) return HANDLER_GO_ON;
36690 -       
36691 +
36692         if (p->config_storage) {
36693                 size_t i;
36694                 for (i = 0; i < srv->config_context->used; i++) {
36695                         plugin_config *s = p->config_storage[i];
36696 -                       
36697 +
36698                         array_free(s->request_header);
36699                         array_free(s->response_header);
36700                         array_free(s->environment);
36701 -                       
36702 +
36703                         free(s);
36704                 }
36705                 free(p->config_storage);
36706         }
36707 -       
36708 +
36709         free(p);
36710 -       
36711 +
36712         return HANDLER_GO_ON;
36713  }
36714  
36715 @@ -86,86 +86,83 @@
36716  SETDEFAULTS_FUNC(mod_setenv_set_defaults) {
36717         plugin_data *p = p_d;
36718         size_t i = 0;
36719 -       
36720 -       config_values_t cv[] = { 
36721 +
36722 +       config_values_t cv[] = {
36723                 { "setenv.add-request-header",  NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
36724                 { "setenv.add-response-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
36725                 { "setenv.add-environment",     NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
36726                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
36727         };
36728 -       
36729 +
36730         if (!p) return HANDLER_ERROR;
36731 -       
36732 +
36733         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
36734 -       
36735 +
36736         for (i = 0; i < srv->config_context->used; i++) {
36737                 plugin_config *s;
36738 -               
36739 +
36740                 s = calloc(1, sizeof(plugin_config));
36741                 s->request_header   = array_init();
36742                 s->response_header  = array_init();
36743                 s->environment      = array_init();
36744 -               
36745 +
36746                 cv[0].destination = s->request_header;
36747                 cv[1].destination = s->response_header;
36748                 cv[2].destination = s->environment;
36749 -               
36750 +
36751                 p->config_storage[i] = s;
36752 -       
36753 +
36754                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
36755                         return HANDLER_ERROR;
36756                 }
36757         }
36758 -       
36759 +
36760         return HANDLER_GO_ON;
36761  }
36762  
36763 -#define PATCH(x) \
36764 -       p->conf.x = s->x;
36765  static int mod_setenv_patch_connection(server *srv, connection *con, plugin_data *p) {
36766         size_t i, j;
36767         plugin_config *s = p->config_storage[0];
36768 -       
36769 -       PATCH(request_header);
36770 -       PATCH(response_header);
36771 -       PATCH(environment);
36772 -       
36773 +
36774 +       PATCH_OPTION(request_header);
36775 +       PATCH_OPTION(response_header);
36776 +       PATCH_OPTION(environment);
36777 +
36778         /* skip the first, the global context */
36779         for (i = 1; i < srv->config_context->used; i++) {
36780                 data_config *dc = (data_config *)srv->config_context->data[i];
36781                 s = p->config_storage[i];
36782 -               
36783 +
36784                 /* condition didn't match */
36785                 if (!config_check_cond(srv, con, dc)) continue;
36786 -               
36787 +
36788                 /* merge config */
36789                 for (j = 0; j < dc->value->used; j++) {
36790                         data_unset *du = dc->value->data[j];
36791 -                       
36792 +
36793                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-request-header"))) {
36794 -                               PATCH(request_header);
36795 +                               PATCH_OPTION(request_header);
36796                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-response-header"))) {
36797 -                               PATCH(response_header);
36798 +                               PATCH_OPTION(response_header);
36799                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-environment"))) {
36800 -                               PATCH(environment);
36801 +                               PATCH_OPTION(environment);
36802                         }
36803                 }
36804         }
36805 -       
36806 +
36807         return 0;
36808  }
36809 -#undef PATCH
36810  
36811  URIHANDLER_FUNC(mod_setenv_uri_handler) {
36812         plugin_data *p = p_d;
36813         size_t k;
36814         handler_ctx *hctx;
36815 -       
36816 +
36817         if (con->plugin_ctx[p->id]) {
36818                 hctx = con->plugin_ctx[p->id];
36819         } else {
36820                 hctx = handler_ctx_init();
36821 -                               
36822 +
36823                 con->plugin_ctx[p->id] = hctx;
36824         }
36825  
36826 @@ -180,52 +177,52 @@
36827         for (k = 0; k < p->conf.request_header->used; k++) {
36828                 data_string *ds = (data_string *)p->conf.request_header->data[k];
36829                 data_string *ds_dst;
36830 -               
36831 +
36832                 if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
36833                         ds_dst = data_string_init();
36834                 }
36835 -               
36836 +
36837                 buffer_copy_string_buffer(ds_dst->key, ds->key);
36838                 buffer_copy_string_buffer(ds_dst->value, ds->value);
36839 -               
36840 +
36841                 array_insert_unique(con->request.headers, (data_unset *)ds_dst);
36842         }
36843 -       
36844 +
36845         for (k = 0; k < p->conf.environment->used; k++) {
36846                 data_string *ds = (data_string *)p->conf.environment->data[k];
36847                 data_string *ds_dst;
36848 -               
36849 +
36850                 if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
36851                         ds_dst = data_string_init();
36852                 }
36853 -               
36854 +
36855                 buffer_copy_string_buffer(ds_dst->key, ds->key);
36856                 buffer_copy_string_buffer(ds_dst->value, ds->value);
36857 -               
36858 +
36859                 array_insert_unique(con->environment, (data_unset *)ds_dst);
36860         }
36861 -       
36862 +
36863         for (k = 0; k < p->conf.response_header->used; k++) {
36864                 data_string *ds = (data_string *)p->conf.response_header->data[k];
36865 -               
36866 +
36867                 response_header_insert(srv, con, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
36868         }
36869 -       
36870 +
36871         /* not found */
36872         return HANDLER_GO_ON;
36873  }
36874  
36875  REQUESTDONE_FUNC(mod_setenv_reset) {
36876         plugin_data *p = p_d;
36877 -       
36878 +
36879         UNUSED(srv);
36880 -       
36881 +
36882         if (con->plugin_ctx[p->id]) {
36883                 handler_ctx_free(con->plugin_ctx[p->id]);
36884                 con->plugin_ctx[p->id] = NULL;
36885         }
36886  
36887 -       return HANDLER_GO_ON;   
36888 +       return HANDLER_GO_ON;
36889  }
36890  
36891  /* this function is called at dlopen() time and inits the callbacks */
36892 @@ -233,15 +230,15 @@
36893  int mod_setenv_plugin_init(plugin *p) {
36894         p->version     = LIGHTTPD_VERSION_ID;
36895         p->name        = buffer_init_string("setenv");
36896 -       
36897 +
36898         p->init        = mod_setenv_init;
36899         p->handle_uri_clean  = mod_setenv_uri_handler;
36900         p->set_defaults  = mod_setenv_set_defaults;
36901         p->cleanup     = mod_setenv_free;
36902 -       
36903 +
36904         p->handle_request_done  = mod_setenv_reset;
36905  
36906         p->data        = NULL;
36907 -       
36908 +
36909         return 0;
36910  }
36911 --- ../lighttpd-1.4.11/src/mod_simple_vhost.c   2005-11-18 15:16:13.000000000 +0200
36912 +++ lighttpd-1.4.12/src/mod_simple_vhost.c      2006-07-16 00:26:04.000000000 +0300
36913 @@ -10,6 +10,8 @@
36914  
36915  #include "plugin.h"
36916  
36917 +#include "sys-files.h"
36918 +
36919  #ifdef HAVE_CONFIG_H
36920  #include "config.h"
36921  #endif
36922 @@ -18,7 +20,7 @@
36923         buffer *server_root;
36924         buffer *default_host;
36925         buffer *document_root;
36926 -       
36927 +
36928         buffer *docroot_cache_key;
36929         buffer *docroot_cache_value;
36930         buffer *docroot_cache_servername;
36931 @@ -28,138 +30,138 @@
36932  
36933  typedef struct {
36934         PLUGIN_DATA;
36935 -       
36936 +
36937         buffer *doc_root;
36938 -       
36939 +
36940         plugin_config **config_storage;
36941 -       plugin_config conf; 
36942 +       plugin_config conf;
36943  } plugin_data;
36944  
36945  INIT_FUNC(mod_simple_vhost_init) {
36946         plugin_data *p;
36947 -       
36948 +
36949         p = calloc(1, sizeof(*p));
36950 -       
36951 +
36952         p->doc_root = buffer_init();
36953 -       
36954 +
36955         return p;
36956  }
36957  
36958  FREE_FUNC(mod_simple_vhost_free) {
36959         plugin_data *p = p_d;
36960 -       
36961 +
36962         UNUSED(srv);
36963  
36964         if (!p) return HANDLER_GO_ON;
36965 -       
36966 +
36967         if (p->config_storage) {
36968                 size_t i;
36969                 for (i = 0; i < srv->config_context->used; i++) {
36970                         plugin_config *s = p->config_storage[i];
36971 -                       
36972 +
36973                         buffer_free(s->document_root);
36974                         buffer_free(s->default_host);
36975                         buffer_free(s->server_root);
36976 -                       
36977 +
36978                         buffer_free(s->docroot_cache_key);
36979                         buffer_free(s->docroot_cache_value);
36980                         buffer_free(s->docroot_cache_servername);
36981 -                       
36982 +
36983                         free(s);
36984                 }
36985 -       
36986 +
36987                 free(p->config_storage);
36988         }
36989 -       
36990 +
36991         buffer_free(p->doc_root);
36992 -       
36993 +
36994         free(p);
36995 -       
36996 +
36997         return HANDLER_GO_ON;
36998  }
36999  
37000  SETDEFAULTS_FUNC(mod_simple_vhost_set_defaults) {
37001         plugin_data *p = p_d;
37002         size_t i;
37003 -       
37004 -       config_values_t cv[] = { 
37005 +
37006 +       config_values_t cv[] = {
37007                 { "simple-vhost.server-root",       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
37008                 { "simple-vhost.default-host",      NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
37009                 { "simple-vhost.document-root",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
37010                 { "simple-vhost.debug",             NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
37011                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
37012         };
37013 -       
37014 +
37015         if (!p) return HANDLER_ERROR;
37016 -       
37017 +
37018         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37019 -       
37020 +
37021         for (i = 0; i < srv->config_context->used; i++) {
37022                 plugin_config *s;
37023 -               
37024 +
37025                 s = calloc(1, sizeof(plugin_config));
37026 -               
37027 +
37028                 s->server_root = buffer_init();
37029                 s->default_host = buffer_init();
37030                 s->document_root = buffer_init();
37031 -               
37032 +
37033                 s->docroot_cache_key = buffer_init();
37034                 s->docroot_cache_value = buffer_init();
37035                 s->docroot_cache_servername = buffer_init();
37036  
37037                 s->debug = 0;
37038 -               
37039 +
37040                 cv[0].destination = s->server_root;
37041                 cv[1].destination = s->default_host;
37042                 cv[2].destination = s->document_root;
37043                 cv[3].destination = &(s->debug);
37044 -               
37045 -               
37046 +
37047 +
37048                 p->config_storage[i] = s;
37049 -               
37050 +
37051                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
37052                         return HANDLER_ERROR;
37053                 }
37054         }
37055 -       
37056 +
37057         return HANDLER_GO_ON;
37058  }
37059  
37060  static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *out, buffer *host) {
37061         stat_cache_entry *sce = NULL;
37062 -       
37063 +
37064         buffer_prepare_copy(out, 128);
37065  
37066         if (p->conf.server_root->used) {
37067                 buffer_copy_string_buffer(out, p->conf.server_root);
37068 -               
37069 +
37070                 if (host->used) {
37071                         /* a hostname has to start with a alpha-numerical character
37072                          * and must not contain a slash "/"
37073                          */
37074                         char *dp;
37075 -                       
37076 -                       BUFFER_APPEND_SLASH(out);
37077 -                       
37078 +
37079 +                       PATHNAME_APPEND_SLASH(out);
37080 +
37081                         if (NULL == (dp = strchr(host->ptr, ':'))) {
37082                                 buffer_append_string_buffer(out, host);
37083                         } else {
37084                                 buffer_append_string_len(out, host->ptr, dp - host->ptr);
37085                         }
37086                 }
37087 -               BUFFER_APPEND_SLASH(out);
37088 -               
37089 +               PATHNAME_APPEND_SLASH(out);
37090 +
37091                 if (p->conf.document_root->used > 2 && p->conf.document_root->ptr[0] == '/') {
37092                         buffer_append_string_len(out, p->conf.document_root->ptr + 1, p->conf.document_root->used - 2);
37093                 } else {
37094                         buffer_append_string_buffer(out, p->conf.document_root);
37095 -                       BUFFER_APPEND_SLASH(out);
37096 +                       PATHNAME_APPEND_SLASH(out);
37097                 }
37098         } else {
37099                 buffer_copy_string_buffer(out, con->conf.document_root);
37100 -               BUFFER_APPEND_SLASH(out);
37101 +               PATHNAME_APPEND_SLASH(out);
37102         }
37103 -       
37104 +
37105         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, out, &sce)) {
37106                 if (p->conf.debug) {
37107                         log_error_write(srv, __FILE__, __LINE__, "sb",
37108 @@ -169,57 +171,53 @@
37109         } else if (!S_ISDIR(sce->st.st_mode)) {
37110                 return -1;
37111         }
37112 -       
37113 +
37114         return 0;
37115  }
37116  
37117 -
37118 -#define PATCH(x) \
37119 -       p->conf.x = s->x;
37120  static int mod_simple_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
37121         size_t i, j;
37122         plugin_config *s = p->config_storage[0];
37123 -       
37124 -       PATCH(server_root);
37125 -       PATCH(default_host);
37126 -       PATCH(document_root);
37127 -       
37128 -       PATCH(docroot_cache_key);
37129 -       PATCH(docroot_cache_value);
37130 -       PATCH(docroot_cache_servername);
37131  
37132 -       PATCH(debug);
37133 -       
37134 +       PATCH_OPTION(server_root);
37135 +       PATCH_OPTION(default_host);
37136 +       PATCH_OPTION(document_root);
37137 +
37138 +       PATCH_OPTION(docroot_cache_key);
37139 +       PATCH_OPTION(docroot_cache_value);
37140 +       PATCH_OPTION(docroot_cache_servername);
37141 +
37142 +       PATCH_OPTION(debug);
37143 +
37144         /* skip the first, the global context */
37145         for (i = 1; i < srv->config_context->used; i++) {
37146                 data_config *dc = (data_config *)srv->config_context->data[i];
37147                 s = p->config_storage[i];
37148 -               
37149 +
37150                 /* condition didn't match */
37151                 if (!config_check_cond(srv, con, dc)) continue;
37152 -               
37153 +
37154                 /* merge config */
37155                 for (j = 0; j < dc->value->used; j++) {
37156                         data_unset *du = dc->value->data[j];
37157 -                       
37158 +
37159                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.server-root"))) {
37160 -                               PATCH(server_root);
37161 -                               PATCH(docroot_cache_key);
37162 -                               PATCH(docroot_cache_value);
37163 -                               PATCH(docroot_cache_servername);
37164 +                               PATCH_OPTION(server_root);
37165 +                               PATCH_OPTION(docroot_cache_key);
37166 +                               PATCH_OPTION(docroot_cache_value);
37167 +                               PATCH_OPTION(docroot_cache_servername);
37168                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.default-host"))) {
37169 -                               PATCH(default_host);
37170 +                               PATCH_OPTION(default_host);
37171                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.document-root"))) {
37172 -                               PATCH(document_root);
37173 +                               PATCH_OPTION(document_root);
37174                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.debug"))) {
37175 -                               PATCH(debug);
37176 +                               PATCH_OPTION(debug);
37177                         }
37178                 }
37179         }
37180 -       
37181 +
37182         return 0;
37183  }
37184 -#undef PATCH
37185  
37186  static handler_t mod_simple_vhost_docroot(server *srv, connection *con, void *p_data) {
37187         plugin_data *p = p_data;
37188 @@ -227,12 +225,12 @@
37189         /*
37190          * cache the last successfull translation from hostname (authority) to docroot
37191          * - this saves us a stat() call
37192 -        * 
37193 +        *
37194          */
37195 -       
37196 +
37197         mod_simple_vhost_patch_connection(srv, con, p);
37198 -       
37199 -       if (p->conf.docroot_cache_key->used && 
37200 +
37201 +       if (p->conf.docroot_cache_key->used &&
37202             con->uri.authority->used &&
37203             buffer_is_equal(p->conf.docroot_cache_key, con->uri.authority)) {
37204                 /* cache hit */
37205 @@ -243,8 +241,8 @@
37206                 if ((con->uri.authority->used == 0) ||
37207                     build_doc_root(srv, con, p, p->doc_root, con->uri.authority)) {
37208                         /* not found, fallback the default-host */
37209 -                       if (build_doc_root(srv, con, p, 
37210 -                                          p->doc_root, 
37211 +                       if (build_doc_root(srv, con, p,
37212 +                                          p->doc_root,
37213                                            p->conf.default_host)) {
37214                                 return HANDLER_GO_ON;
37215                         } else {
37216 @@ -253,15 +251,15 @@
37217                 } else {
37218                         buffer_copy_string_buffer(con->server_name, con->uri.authority);
37219                 }
37220 -               
37221 +
37222                 /* copy to cache */
37223                 buffer_copy_string_buffer(p->conf.docroot_cache_key,        con->uri.authority);
37224                 buffer_copy_string_buffer(p->conf.docroot_cache_value,      p->doc_root);
37225                 buffer_copy_string_buffer(p->conf.docroot_cache_servername, con->server_name);
37226 -               
37227 +
37228                 buffer_copy_string_buffer(con->physical.doc_root, p->doc_root);
37229         }
37230 -       
37231 +
37232         return HANDLER_GO_ON;
37233  }
37234  
37235 @@ -269,13 +267,13 @@
37236  int mod_simple_vhost_plugin_init(plugin *p) {
37237         p->version     = LIGHTTPD_VERSION_ID;
37238         p->name        = buffer_init_string("simple_vhost");
37239 -       
37240 +
37241         p->init        = mod_simple_vhost_init;
37242         p->set_defaults = mod_simple_vhost_set_defaults;
37243         p->handle_docroot  = mod_simple_vhost_docroot;
37244         p->cleanup     = mod_simple_vhost_free;
37245 -       
37246 +
37247         p->data        = NULL;
37248 -       
37249 +
37250         return 0;
37251  }
37252 --- ../lighttpd-1.4.11/src/mod_skeleton.c       2005-10-02 18:30:51.000000000 +0300
37253 +++ lighttpd-1.4.12/src/mod_skeleton.c  2006-07-16 00:26:03.000000000 +0300
37254 @@ -14,13 +14,13 @@
37255  
37256  /**
37257   * this is a skeleton for a lighttpd plugin
37258 - * 
37259 + *
37260   * just replaces every occurance of 'skeleton' by your plugin name
37261 - * 
37262 + *
37263   * e.g. in vim:
37264 - * 
37265 + *
37266   *   :%s/skeleton/myhandler/
37267 - * 
37268 + *
37269   */
37270  
37271  
37272 @@ -33,12 +33,12 @@
37273  
37274  typedef struct {
37275         PLUGIN_DATA;
37276 -       
37277 +
37278         buffer *match_buf;
37279 -       
37280 +
37281         plugin_config **config_storage;
37282 -       
37283 -       plugin_config conf; 
37284 +
37285 +       plugin_config conf;
37286  } plugin_data;
37287  
37288  typedef struct {
37289 @@ -47,36 +47,36 @@
37290  
37291  static handler_ctx * handler_ctx_init() {
37292         handler_ctx * hctx;
37293 -       
37294 +
37295         hctx = calloc(1, sizeof(*hctx));
37296 -       
37297 +
37298         return hctx;
37299  }
37300  
37301  static void handler_ctx_free(handler_ctx *hctx) {
37302 -       
37303 +
37304         free(hctx);
37305  }
37306  
37307  /* init the plugin data */
37308  INIT_FUNC(mod_skeleton_init) {
37309         plugin_data *p;
37310 -       
37311 +
37312         p = calloc(1, sizeof(*p));
37313 -       
37314 +
37315         p->match_buf = buffer_init();
37316 -       
37317 +
37318         return p;
37319  }
37320  
37321  /* detroy the plugin data */
37322  FREE_FUNC(mod_skeleton_free) {
37323         plugin_data *p = p_d;
37324 -       
37325 +
37326         UNUSED(srv);
37327  
37328         if (!p) return HANDLER_GO_ON;
37329 -       
37330 +
37331         if (p->config_storage) {
37332                 size_t i;
37333  
37334 @@ -84,18 +84,18 @@
37335                         plugin_config *s = p->config_storage[i];
37336  
37337                         if (!s) continue;
37338 -                       
37339 +
37340                         array_free(s->match);
37341 -                       
37342 +
37343                         free(s);
37344                 }
37345                 free(p->config_storage);
37346         }
37347 -       
37348 +
37349         buffer_free(p->match_buf);
37350 -       
37351 +
37352         free(p);
37353 -       
37354 +
37355         return HANDLER_GO_ON;
37356  }
37357  
37358 @@ -104,91 +104,88 @@
37359  SETDEFAULTS_FUNC(mod_skeleton_set_defaults) {
37360         plugin_data *p = p_d;
37361         size_t i = 0;
37362 -       
37363 -       config_values_t cv[] = { 
37364 +
37365 +       config_values_t cv[] = {
37366                 { "skeleton.array",             NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
37367                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
37368         };
37369 -       
37370 +
37371         if (!p) return HANDLER_ERROR;
37372 -       
37373 +
37374         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37375 -       
37376 +
37377         for (i = 0; i < srv->config_context->used; i++) {
37378                 plugin_config *s;
37379 -               
37380 +
37381                 s = calloc(1, sizeof(plugin_config));
37382                 s->match    = array_init();
37383 -               
37384 +
37385                 cv[0].destination = s->match;
37386 -               
37387 +
37388                 p->config_storage[i] = s;
37389 -       
37390 +
37391                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
37392                         return HANDLER_ERROR;
37393                 }
37394         }
37395 -       
37396 +
37397         return HANDLER_GO_ON;
37398  }
37399  
37400 -#define PATCH(x) \
37401 -       p->conf.x = s->x;
37402  static int mod_skeleton_patch_connection(server *srv, connection *con, plugin_data *p) {
37403         size_t i, j;
37404         plugin_config *s = p->config_storage[0];
37405 -       
37406 -       PATCH(match);
37407 -       
37408 +
37409 +       PATCH_OPTION(match);
37410 +
37411         /* skip the first, the global context */
37412         for (i = 1; i < srv->config_context->used; i++) {
37413                 data_config *dc = (data_config *)srv->config_context->data[i];
37414                 s = p->config_storage[i];
37415 -               
37416 +
37417                 /* condition didn't match */
37418                 if (!config_check_cond(srv, con, dc)) continue;
37419 -               
37420 +
37421                 /* merge config */
37422                 for (j = 0; j < dc->value->used; j++) {
37423                         data_unset *du = dc->value->data[j];
37424 -                       
37425 +
37426                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("skeleton.array"))) {
37427 -                               PATCH(match);
37428 +                               PATCH_OPTION(match);
37429                         }
37430                 }
37431         }
37432 -       
37433 +
37434         return 0;
37435  }
37436 -#undef PATCH
37437  
37438  URIHANDLER_FUNC(mod_skeleton_uri_handler) {
37439         plugin_data *p = p_d;
37440         int s_len;
37441         size_t k, i;
37442 -       
37443 +
37444         UNUSED(srv);
37445  
37446         if (con->uri.path->used == 0) return HANDLER_GO_ON;
37447 -       
37448 +
37449         mod_skeleton_patch_connection(srv, con, p);
37450  
37451         s_len = con->uri.path->used - 1;
37452 -       
37453 +
37454         for (k = 0; k < p->conf.match->used; k++) {
37455                 data_string *ds = (data_string *)p->conf.match->data[k];
37456                 int ct_len = ds->value->used - 1;
37457 -               
37458 +
37459                 if (ct_len > s_len) continue;
37460                 if (ds->value->used == 0) continue;
37461 -               
37462 +
37463                 if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
37464                         con->http_status = 403;
37465 -       
37466 +
37467                         return HANDLER_FINISHED;
37468                 }
37469         }
37470 -       
37471 +
37472         /* not found */
37473         return HANDLER_GO_ON;
37474  }
37475 @@ -198,13 +195,13 @@
37476  int mod_skeleton_plugin_init(plugin *p) {
37477         p->version     = LIGHTTPD_VERSION_ID;
37478         p->name        = buffer_init_string("skeleton");
37479 -       
37480 +
37481         p->init        = mod_skeleton_init;
37482         p->handle_uri_clean  = mod_skeleton_uri_handler;
37483         p->set_defaults  = mod_skeleton_set_defaults;
37484         p->cleanup     = mod_skeleton_free;
37485 -       
37486 +
37487         p->data        = NULL;
37488 -       
37489 +
37490         return 0;
37491  }
37492 --- ../lighttpd-1.4.11/src/mod_sql_vhost_core.c 1970-01-01 03:00:00.000000000 +0300
37493 +++ lighttpd-1.4.12/src/mod_sql_vhost_core.c    2006-07-16 00:26:04.000000000 +0300
37494 @@ -0,0 +1,209 @@
37495 +#include <stdio.h>
37496 +#include <errno.h>
37497 +#include <fcntl.h>
37498 +#include <string.h>
37499 +
37500 +#ifdef HAVE_CONFIG_H
37501 +#include "config.h"
37502 +#endif
37503 +
37504 +#include "plugin.h"
37505 +#include "log.h"
37506 +
37507 +#include "stat_cache.h"
37508 +
37509 +#include "mod_sql_vhost_core.h"
37510 +
37511 +#define plugin_data mod_sql_vhost_core_plugin_data
37512 +#define plugin_config mod_sql_vhost_core_plugin_config
37513 +
37514 +/* init the plugin data */
37515 +INIT_FUNC(mod_sql_vhost_core_init) {
37516 +       plugin_data *p;
37517 +
37518 +       p = calloc(1, sizeof(*p));
37519 +
37520 +       p->docroot = buffer_init();
37521 +       p->host = buffer_init();
37522 +
37523 +       return p;
37524 +}
37525 +
37526 +/* cleanup the plugin data */
37527 +SERVER_FUNC(mod_sql_vhost_core_cleanup) {
37528 +       plugin_data *p = p_d;
37529 +
37530 +       UNUSED(srv);
37531 +
37532 +       if (!p) return HANDLER_GO_ON;
37533 +
37534 +       if (p->config_storage) {
37535 +               size_t i;
37536 +               for (i = 0; i < srv->config_context->used; i++) {
37537 +                       plugin_config *s = p->config_storage[i];
37538 +
37539 +                       if (!s) continue;
37540 +
37541 +                       buffer_free(s->db);
37542 +                       buffer_free(s->user);
37543 +                       buffer_free(s->pass);
37544 +                       buffer_free(s->sock);
37545 +                       buffer_free(s->backend);
37546 +
37547 +                       free(s);
37548 +               }
37549 +               free(p->config_storage);
37550 +       }
37551 +       buffer_free(p->docroot);
37552 +       buffer_free(p->host);
37553 +
37554 +       free(p);
37555 +
37556 +       return HANDLER_GO_ON;
37557 +}
37558 +
37559 +/* set configuration values */
37560 +SERVER_FUNC(mod_sql_vhost_core_set_defaults) {
37561 +       plugin_data *p = p_d;
37562 +
37563 +       size_t i = 0;
37564 +
37565 +       config_values_t cv[] = {
37566 +               { "sql-vhost.db",       NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 0 * e.g. vhost */
37567 +               { "sql-vhost.user",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 1 * lighty */
37568 +               { "sql-vhost.pass",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 2 * secrect */
37569 +               { "sql-vhost.sock",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 3 * /tmp/mysql.sock */
37570 +               { "sql-vhost.select-vhost", NULL, T_CONFIG_STRING,      T_CONFIG_SCOPE_SERVER }, /* 4 * SELECT ... FROM hosts WHERE hostname = ? */
37571 +               { "sql-vhost.hostname", NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 5 * 127.0.0.1 */
37572 +               { "sql-vhost.port",     NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_SERVER }, /* 6 * 3306 */
37573 +               { "sql-vhost.backend",  NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 7 * mysql */
37574 +
37575 +               /* backward compat */
37576 +               { "mysql-vhost.db",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 8 == 0 */
37577 +               { "mysql-vhost.user",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 9 == 1 */
37578 +               { "mysql-vhost.pass",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 10 == 2 */
37579 +               { "mysql-vhost.sock",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 11 == 3 */
37580 +               { "mysql-vhost.sql",    NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 12 == 4 */
37581 +               { "mysql-vhost.hostname", NULL, T_CONFIG_STRING,T_CONFIG_SCOPE_SERVER }, /* 13 == 5 */
37582 +               { "mysql-vhost.port",   NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_SERVER }, /* 14 == 6 */
37583 +
37584 +                { NULL,                        NULL, T_CONFIG_UNSET,   T_CONFIG_SCOPE_UNSET }
37585 +        };
37586 +
37587 +       p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37588 +
37589 +       for (i = 0; i < srv->config_context->used; i++) {
37590 +               plugin_config *s;
37591 +
37592 +               s = calloc(1, sizeof(plugin_config));
37593 +               s->db = buffer_init();
37594 +               s->user = buffer_init();
37595 +               s->pass = buffer_init();
37596 +               s->sock = buffer_init();
37597 +               s->hostname = buffer_init();
37598 +               s->backend = buffer_init();
37599 +               s->port   = 0;               /* default port for mysql */
37600 +               s->select_vhost = buffer_init();
37601 +               s->backend_data = NULL;
37602 +
37603 +               cv[0].destination = s->db;
37604 +               cv[1].destination = s->user;
37605 +               cv[2].destination = s->pass;
37606 +               cv[3].destination = s->sock;
37607 +               cv[4].destination = s->select_vhost;
37608 +               cv[5].destination = s->hostname;
37609 +               cv[6].destination = &(s->port);
37610 +               cv[7].destination = s->backend;
37611 +
37612 +               /* backend compat */
37613 +               cv[8].destination = cv[0].destination;
37614 +               cv[9].destination = cv[1].destination;
37615 +               cv[10].destination = cv[2].destination;
37616 +               cv[11].destination = cv[3].destination;
37617 +               cv[12].destination = cv[4].destination;
37618 +               cv[13].destination = cv[5].destination;
37619 +               cv[14].destination = cv[6].destination;
37620 +
37621 +               p->config_storage[i] = s;
37622 +
37623 +               if (config_insert_values_global(srv,
37624 +                       ((data_config *)srv->config_context->data[i])->value,
37625 +                       cv)) return HANDLER_ERROR;
37626 +
37627 +               /* we only parse the config, the backend plugin will patch itself into the plugin-struct */
37628 +       }
37629 +
37630 +        return HANDLER_GO_ON;
37631 +}
37632 +
37633 +static int mod_sql_vhost_core_patch_connection(server *srv, connection *con, plugin_data *p) {
37634 +       size_t i;
37635 +       plugin_config *s = p->config_storage[0];
37636 +
37637 +       PATCH_OPTION(backend_data);
37638 +       PATCH_OPTION(get_vhost);
37639 +
37640 +       /* skip the first, the global context */
37641 +       for (i = 1; i < srv->config_context->used; i++) {
37642 +               data_config *dc = (data_config *)srv->config_context->data[i];
37643 +               s = p->config_storage[i];
37644 +
37645 +               /* condition didn't match */
37646 +               if (!config_check_cond(srv, con, dc)) continue;
37647 +
37648 +               if (s->backend_data) {
37649 +                       PATCH_OPTION(backend_data);
37650 +                       PATCH_OPTION(get_vhost);
37651 +               }
37652 +       }
37653 +
37654 +       return 0;
37655 +}
37656 +
37657 +/* handle document root request */
37658 +CONNECTION_FUNC(mod_sql_vhost_core_handle_docroot) {
37659 +       plugin_data *p = p_d;
37660 +       stat_cache_entry *sce;
37661 +
37662 +       /* no host specified? */
37663 +       if (!con->uri.authority->used) return HANDLER_GO_ON;
37664 +
37665 +       mod_sql_vhost_core_patch_connection(srv, con, p);
37666 +
37667 +       /* do we have backend ? */
37668 +       if (!p->conf.get_vhost) return HANDLER_GO_ON;
37669 +
37670 +       /* ask the backend for the data */
37671 +       if (0 != p->conf.get_vhost(srv, con, p->conf.backend_data, p->docroot, p->host)) {
37672 +               return HANDLER_GO_ON;
37673 +       }
37674 +
37675 +       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->docroot, &sce)) {
37676 +               log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->docroot);
37677 +               return HANDLER_GO_ON;
37678 +       }
37679 +        if (!S_ISDIR(sce->st.st_mode)) {
37680 +               log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", p->docroot);
37681 +               return HANDLER_GO_ON;
37682 +       }
37683 +
37684 +       buffer_copy_string_buffer(con->server_name, p->host);
37685 +       buffer_copy_string_buffer(con->physical.doc_root, p->docroot);
37686 +
37687 +       return HANDLER_GO_ON;
37688 +}
37689 +
37690 +/* this function is called at dlopen() time and inits the callbacks */
37691 +int mod_sql_vhost_core_plugin_init(plugin *p) {
37692 +       p->version     = LIGHTTPD_VERSION_ID;
37693 +       p->name                         = buffer_init_string("mod_sql_vhost_core");
37694 +
37695 +       p->init                         = mod_sql_vhost_core_init;
37696 +       p->cleanup                      = mod_sql_vhost_core_cleanup;
37697 +
37698 +       p->set_defaults                 = mod_sql_vhost_core_set_defaults;
37699 +       p->handle_docroot               = mod_sql_vhost_core_handle_docroot;
37700 +
37701 +       return 0;
37702 +}
37703 +
37704 --- ../lighttpd-1.4.11/src/mod_sql_vhost_core.h 1970-01-01 03:00:00.000000000 +0300
37705 +++ lighttpd-1.4.12/src/mod_sql_vhost_core.h    2006-07-16 00:26:04.000000000 +0300
37706 @@ -0,0 +1,49 @@
37707 +#ifndef _MOD_SQL_VHOST_CORE_H_
37708 +#define _MOD_SQL_VHOST_CORE_H_
37709 +
37710 +#include "buffer.h"
37711 +#include "plugin.h"
37712 +
37713 +#define SQLVHOST_BACKEND_GETVHOST_PARAMS \
37714 +       (server *srv, connection *con, void *p_d, buffer *docroot, buffer *host)
37715 +
37716 +#define SQLVHOST_BACKEND_GETVHOST_RETVAL handler_t
37717 +
37718 +#define SQLVHOST_BACKEND_GETVHOST(name) \
37719 +       SQLVHOST_BACKEND_GETVHOST_RETVAL name SQLVHOST_BACKEND_GETVHOST_PARAMS
37720 +
37721 +#define SQLVHOST_BACKEND_GETVHOST_PTR(name) \
37722 +       SQLVHOST_BACKEND_GETVHOST_RETVAL (* name)SQLVHOST_BACKEND_GETVHOST_PARAMS
37723 +
37724 +typedef struct {
37725 +       buffer  *db;
37726 +       buffer  *user;
37727 +       buffer  *pass;
37728 +       buffer  *sock;
37729 +
37730 +       buffer  *hostname;
37731 +       unsigned short port;
37732 +
37733 +       buffer  *backend;
37734 +       void *backend_data;
37735 +
37736 +       buffer *select_vhost;
37737 +
37738 +       SQLVHOST_BACKEND_GETVHOST_PTR(get_vhost);
37739 +} mod_sql_vhost_core_plugin_config;
37740 +
37741 +/* global plugin data */
37742 +typedef struct {
37743 +       PLUGIN_DATA;
37744 +
37745 +       buffer  *docroot;
37746 +       buffer  *host;
37747 +
37748 +       mod_sql_vhost_core_plugin_config **config_storage;
37749 +
37750 +       mod_sql_vhost_core_plugin_config conf;
37751 +} mod_sql_vhost_core_plugin_data;
37752 +
37753 +
37754 +
37755 +#endif
37756 --- ../lighttpd-1.4.11/src/mod_ssi.c    2006-03-04 17:09:48.000000000 +0200
37757 +++ lighttpd-1.4.12/src/mod_ssi.c       2006-07-16 00:26:04.000000000 +0300
37758 @@ -6,7 +6,6 @@
37759  #include <string.h>
37760  #include <errno.h>
37761  #include <time.h>
37762 -#include <unistd.h>
37763  
37764  #include "base.h"
37765  #include "log.h"
37766 @@ -23,6 +22,8 @@
37767  #include "inet_ntop_cache.h"
37768  
37769  #include "sys-socket.h"
37770 +#include "sys-strings.h"
37771 +#include "sys-files.h"
37772  
37773  #ifdef HAVE_PWD_H
37774  #include <pwd.h>
37775 @@ -39,15 +40,15 @@
37776  /* init the plugin data */
37777  INIT_FUNC(mod_ssi_init) {
37778         plugin_data *p;
37779 -       
37780 +
37781         p = calloc(1, sizeof(*p));
37782 -       
37783 +
37784         p->timefmt = buffer_init();
37785         p->stat_fn = buffer_init();
37786 -       
37787 +
37788         p->ssi_vars = array_init();
37789         p->ssi_cgi_env = array_init();
37790 -       
37791 +
37792         return p;
37793  }
37794  
37795 @@ -55,21 +56,21 @@
37796  FREE_FUNC(mod_ssi_free) {
37797         plugin_data *p = p_d;
37798         UNUSED(srv);
37799 -       
37800 +
37801         if (!p) return HANDLER_GO_ON;
37802 -       
37803 +
37804         if (p->config_storage) {
37805                 size_t i;
37806                 for (i = 0; i < srv->config_context->used; i++) {
37807                         plugin_config *s = p->config_storage[i];
37808 -                       
37809 +
37810                         array_free(s->ssi_extension);
37811 -                       
37812 +
37813                         free(s);
37814                 }
37815                 free(p->config_storage);
37816         }
37817 -       
37818 +
37819         array_free(p->ssi_vars);
37820         array_free(p->ssi_cgi_env);
37821  #ifdef HAVE_PCRE_H
37822 @@ -77,9 +78,9 @@
37823  #endif
37824         buffer_free(p->timefmt);
37825         buffer_free(p->stat_fn);
37826 -       
37827 +
37828         free(p);
37829 -       
37830 +
37831         return HANDLER_GO_ON;
37832  }
37833  
37834 @@ -92,36 +93,36 @@
37835         const char *errptr;
37836         int erroff;
37837  #endif
37838 -       
37839 -       config_values_t cv[] = { 
37840 +
37841 +       config_values_t cv[] = {
37842                 { "ssi.extension",              NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
37843                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
37844         };
37845 -       
37846 +
37847         if (!p) return HANDLER_ERROR;
37848 -       
37849 +
37850         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37851 -       
37852 +
37853         for (i = 0; i < srv->config_context->used; i++) {
37854                 plugin_config *s;
37855 -               
37856 +
37857                 s = calloc(1, sizeof(plugin_config));
37858                 s->ssi_extension  = array_init();
37859 -               
37860 +
37861                 cv[0].destination = s->ssi_extension;
37862 -               
37863 +
37864                 p->config_storage[i] = s;
37865 -       
37866 +
37867                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
37868                         return HANDLER_ERROR;
37869                 }
37870         }
37871 -       
37872 +
37873  #ifdef HAVE_PCRE_H
37874         /* allow 2 params */
37875         if (NULL == (p->ssi_regex = pcre_compile("<!--#([a-z]+)\\s+(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?-->", 0, &errptr, &erroff, NULL))) {
37876                 log_error_write(srv, __FILE__, __LINE__, "sds",
37877 -                               "ssi: pcre ", 
37878 +                               "ssi: pcre ",
37879                                 erroff, errptr);
37880                 return HANDLER_ERROR;
37881         }
37882 @@ -130,52 +131,52 @@
37883                         "mod_ssi: pcre support is missing, please recompile with pcre support or remove mod_ssi from the list of modules");
37884         return HANDLER_ERROR;
37885  #endif
37886 -       
37887 +
37888         return HANDLER_GO_ON;
37889  }
37890  
37891  int ssi_env_add(array *env, const char *key, const char *val) {
37892         data_string *ds;
37893 -                       
37894 +
37895         if (NULL == (ds = (data_string *)array_get_unused_element(env, TYPE_STRING))) {
37896                 ds = data_string_init();
37897         }
37898         buffer_copy_string(ds->key,   key);
37899         buffer_copy_string(ds->value, val);
37900 -       
37901 +
37902         array_insert_unique(env, (data_unset *)ds);
37903 -       
37904 +
37905         return 0;
37906  }
37907  
37908  /**
37909   *
37910   *  the next two functions are take from fcgi.c
37911 - * 
37912 + *
37913   */
37914  
37915  static int ssi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
37916         size_t i;
37917 -       
37918 +
37919         for (i = 0; i < con->request.headers->used; i++) {
37920                 data_string *ds;
37921 -               
37922 +
37923                 ds = (data_string *)con->request.headers->data[i];
37924 -               
37925 +
37926                 if (ds->value->used && ds->key->used) {
37927                         size_t j;
37928                         buffer_reset(srv->tmp_buf);
37929 -                       
37930 +
37931                         /* don't forward the Authorization: Header */
37932                         if (0 == strcasecmp(ds->key->ptr, "AUTHORIZATION")) {
37933                                 continue;
37934                         }
37935 -                       
37936 +
37937                         if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
37938                                 buffer_copy_string(srv->tmp_buf, "HTTP_");
37939                                 srv->tmp_buf->used--;
37940                         }
37941 -                       
37942 +
37943                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
37944                         for (j = 0; j < ds->key->used - 1; j++) {
37945                                 char c = '_';
37946 @@ -189,33 +190,33 @@
37947                                 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
37948                         }
37949                         srv->tmp_buf->ptr[srv->tmp_buf->used] = '\0';
37950 -                       
37951 +
37952                         ssi_env_add(p->ssi_cgi_env, srv->tmp_buf->ptr, ds->value->ptr);
37953                 }
37954         }
37955 -       
37956 +
37957         return 0;
37958  }
37959  
37960  static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) {
37961         char buf[32];
37962 -       
37963 +
37964         server_socket *srv_sock = con->srv_socket;
37965 -       
37966 +
37967  #ifdef HAVE_IPV6
37968         char b2[INET6_ADDRSTRLEN + 1];
37969  #endif
37970  
37971  #define CONST_STRING(x) \
37972                 x
37973 -       
37974 +
37975         array_reset(p->ssi_cgi_env);
37976 -       
37977 +
37978         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_SOFTWARE"), PACKAGE_NAME"/"PACKAGE_VERSION);
37979         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_NAME"),
37980  #ifdef HAVE_IPV6
37981 -                    inet_ntop(srv_sock->addr.plain.sa_family, 
37982 -                              srv_sock->addr.plain.sa_family == AF_INET6 ? 
37983 +                    inet_ntop(srv_sock->addr.plain.sa_family,
37984 +                              srv_sock->addr.plain.sa_family == AF_INET6 ?
37985                                (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
37986                                (const void *) &(srv_sock->addr.ipv4.sin_addr),
37987                                b2, sizeof(b2)-1)
37988 @@ -224,28 +225,28 @@
37989  #endif
37990                      );
37991         ssi_env_add(p->ssi_cgi_env, CONST_STRING("GATEWAY_INTERFACE"), "CGI/1.1");
37992 -               
37993 -       ltostr(buf, 
37994 +
37995 +       ltostr(buf,
37996  #ifdef HAVE_IPV6
37997                ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
37998  #else
37999                ntohs(srv_sock->addr.ipv4.sin_port)
38000  #endif
38001                );
38002 -       
38003 +
38004         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PORT"), buf);
38005 -       
38006 +
38007         ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_ADDR"),
38008                     inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
38009 -       
38010 +
38011         if (con->authed_user->used) {
38012                 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_USER"),
38013                              con->authed_user->ptr);
38014         }
38015 -       
38016 +
38017         if (con->request.content_length > 0) {
38018                 /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
38019 -               
38020 +
38021                 /* request.content_length < SSIZE_MAX, see request.c */
38022                 ltostr(buf, con->request.content_length);
38023                 ssi_env_add(p->ssi_cgi_env, CONST_STRING("CONTENT_LENGTH"), buf);
38024 @@ -271,30 +272,30 @@
38025         if (con->request.pathinfo->used) {
38026                 ssi_env_add(p->ssi_cgi_env, CONST_STRING("PATH_INFO"), con->request.pathinfo->ptr);
38027         }
38028 -               
38029 +
38030         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SCRIPT_FILENAME"), con->physical.path->ptr);
38031         ssi_env_add(p->ssi_cgi_env, CONST_STRING("DOCUMENT_ROOT"), con->physical.doc_root->ptr);
38032 -       
38033 +
38034         ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_URI"), con->request.uri->ptr);
38035         ssi_env_add(p->ssi_cgi_env, CONST_STRING("QUERY_STRING"), con->uri.query->used ? con->uri.query->ptr : "");
38036         ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_METHOD"), get_http_method_name(con->request.http_method));
38037         ssi_env_add(p->ssi_cgi_env, CONST_STRING("REDIRECT_STATUS"), "200");
38038         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PROTOCOL"), get_http_version_name(con->request.http_version));
38039 -       
38040 +
38041         ssi_env_add_request_headers(srv, con, p);
38042 -       
38043 +
38044         return 0;
38045  }
38046  
38047 -static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, 
38048 +static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
38049                             const char **l, size_t n) {
38050         size_t i, ssicmd = 0;
38051         char buf[255];
38052         buffer *b = NULL;
38053 -       
38054 -       struct { 
38055 +
38056 +       struct {
38057                 const char *var;
38058 -               enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD, 
38059 +               enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD,
38060                                 SSI_CONFIG, SSI_PRINTENV, SSI_SET, SSI_IF, SSI_ELIF,
38061                                 SSI_ELSE, SSI_ENDIF, SSI_EXEC } type;
38062         } ssicmds[] = {
38063 @@ -310,27 +311,27 @@
38064                 { "endif",    SSI_ENDIF },
38065                 { "else",     SSI_ELSE },
38066                 { "exec",     SSI_EXEC },
38067 -               
38068 +
38069                 { NULL, SSI_UNSET }
38070         };
38071 -       
38072 +
38073         for (i = 0; ssicmds[i].var; i++) {
38074                 if (0 == strcmp(l[1], ssicmds[i].var)) {
38075                         ssicmd = ssicmds[i].type;
38076                         break;
38077                 }
38078         }
38079 -       
38080 +
38081         switch(ssicmd) {
38082         case SSI_ECHO: {
38083                 /* echo */
38084                 int var = 0, enc = 0;
38085                 const char *var_val = NULL;
38086                 stat_cache_entry *sce = NULL;
38087 -               
38088 -               struct { 
38089 +
38090 +               struct {
38091                         const char *var;
38092 -                       enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI, 
38093 +                       enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI,
38094                                         SSI_ECHO_LAST_MODIFIED, SSI_ECHO_USER_NAME } type;
38095                 } echovars[] = {
38096                         { "DATE_GMT",      SSI_ECHO_DATE_GMT },
38097 @@ -339,27 +340,27 @@
38098                         { "DOCUMENT_URI",  SSI_ECHO_DOCUMENT_URI },
38099                         { "LAST_MODIFIED", SSI_ECHO_LAST_MODIFIED },
38100                         { "USER_NAME",     SSI_ECHO_USER_NAME },
38101 -                       
38102 +
38103                         { NULL, SSI_ECHO_UNSET }
38104                 };
38105 -               
38106 -               struct { 
38107 +
38108 +               struct {
38109                         const char *var;
38110                         enum { SSI_ENC_UNSET, SSI_ENC_URL, SSI_ENC_NONE, SSI_ENC_ENTITY } type;
38111                 } encvars[] = {
38112                         { "url",          SSI_ENC_URL },
38113                         { "none",         SSI_ENC_NONE },
38114                         { "entity",       SSI_ENC_ENTITY },
38115 -                       
38116 +
38117                         { NULL, SSI_ENC_UNSET }
38118                 };
38119 -               
38120 +
38121                 for (i = 2; i < n; i += 2) {
38122                         if (0 == strcmp(l[i], "var")) {
38123                                 int j;
38124 -                               
38125 +
38126                                 var_val = l[i+1];
38127 -                               
38128 +
38129                                 for (j = 0; echovars[j].var; j++) {
38130                                         if (0 == strcmp(l[i+1], echovars[j].var)) {
38131                                                 var = echovars[j].type;
38132 @@ -368,7 +369,7 @@
38133                                 }
38134                         } else if (0 == strcmp(l[i], "encoding")) {
38135                                 int j;
38136 -                               
38137 +
38138                                 for (j = 0; encvars[j].var; j++) {
38139                                         if (0 == strcmp(l[i+1], encvars[j].var)) {
38140                                                 enc = encvars[j].type;
38141 @@ -377,26 +378,26 @@
38142                                 }
38143                         } else {
38144                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38145 -                                               "ssi: unknow attribute for ", 
38146 +                                               "ssi: unknow attribute for ",
38147                                                 l[1], l[i]);
38148                         }
38149                 }
38150 -               
38151 +
38152                 if (p->if_is_false) break;
38153 -               
38154 +
38155                 if (!var_val) {
38156                         log_error_write(srv, __FILE__, __LINE__, "sss",
38157 -                                       "ssi: ", 
38158 +                                       "ssi: ",
38159                                         l[1], "var is missing");
38160                         break;
38161                 }
38162  
38163                 stat_cache_get_entry(srv, con, con->physical.path, &sce);
38164 -               
38165 +
38166                 switch(var) {
38167                 case SSI_ECHO_USER_NAME: {
38168                         struct passwd *pw;
38169 -                       
38170 +
38171                         b = chunkqueue_get_append_buffer(con->write_queue);
38172  #ifdef HAVE_PWD_H
38173                         if (NULL == (pw = getpwuid(sce->st.st_uid))) {
38174 @@ -411,7 +412,7 @@
38175                 }
38176                 case SSI_ECHO_LAST_MODIFIED:    {
38177                         time_t t = sce->st.st_mtime;
38178 -                       
38179 +
38180                         b = chunkqueue_get_append_buffer(con->write_queue);
38181                         if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
38182                                 buffer_copy_string(b, "(none)");
38183 @@ -422,7 +423,7 @@
38184                 }
38185                 case SSI_ECHO_DATE_LOCAL: {
38186                         time_t t = time(NULL);
38187 -                       
38188 +
38189                         b = chunkqueue_get_append_buffer(con->write_queue);
38190                         if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
38191                                 buffer_copy_string(b, "(none)");
38192 @@ -433,7 +434,7 @@
38193                 }
38194                 case SSI_ECHO_DATE_GMT: {
38195                         time_t t = time(NULL);
38196 -                       
38197 +
38198                         b = chunkqueue_get_append_buffer(con->write_queue);
38199                         if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, gmtime(&t))) {
38200                                 buffer_copy_string(b, "(none)");
38201 @@ -444,7 +445,7 @@
38202                 }
38203                 case SSI_ECHO_DOCUMENT_NAME: {
38204                         char *sl;
38205 -                       
38206 +
38207                         b = chunkqueue_get_append_buffer(con->write_queue);
38208                         if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
38209                                 buffer_copy_string_buffer(b, con->physical.path);
38210 @@ -461,15 +462,15 @@
38211                 default: {
38212                         data_string *ds;
38213                         /* check if it is a cgi-var */
38214 -                       
38215 +
38216                         b = chunkqueue_get_append_buffer(con->write_queue);
38217 -                       
38218 +
38219                         if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, var_val))) {
38220                                 buffer_copy_string_buffer(b, ds->value);
38221                         } else {
38222                                 buffer_copy_string(b, "(none)");
38223                         }
38224 -                       
38225 +
38226                         break;
38227                 }
38228                 }
38229 @@ -481,7 +482,7 @@
38230                 const char * file_path = NULL, *virt_path = NULL;
38231                 struct stat st;
38232                 char *sl;
38233 -               
38234 +
38235                 for (i = 2; i < n; i += 2) {
38236                         if (0 == strcmp(l[i], "file")) {
38237                                 file_path = l[i+1];
38238 @@ -489,28 +490,28 @@
38239                                 virt_path = l[i+1];
38240                         } else {
38241                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38242 -                                               "ssi: unknow attribute for ", 
38243 +                                               "ssi: unknow attribute for ",
38244                                                 l[1], l[i]);
38245                         }
38246                 }
38247 -               
38248 +
38249                 if (!file_path && !virt_path) {
38250                         log_error_write(srv, __FILE__, __LINE__, "sss",
38251 -                                       "ssi: ", 
38252 +                                       "ssi: ",
38253                                         l[1], "file or virtual are missing");
38254                         break;
38255                 }
38256 -               
38257 +
38258                 if (file_path && virt_path) {
38259                         log_error_write(srv, __FILE__, __LINE__, "sss",
38260 -                                       "ssi: ", 
38261 +                                       "ssi: ",
38262                                         l[1], "only one of file and virtual is allowed here");
38263                         break;
38264                 }
38265 -               
38266 -               
38267 +
38268 +
38269                 if (p->if_is_false) break;
38270 -               
38271 +
38272                 if (file_path) {
38273                         /* current doc-root */
38274                         if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
38275 @@ -519,46 +520,46 @@
38276                                 buffer_copy_string_len(p->stat_fn, con->physical.path->ptr, sl - con->physical.path->ptr + 1);
38277                         }
38278  
38279 -                       buffer_copy_string(srv->tmp_buf, file_path); 
38280 +                       buffer_copy_string(srv->tmp_buf, file_path);
38281                         buffer_urldecode_path(srv->tmp_buf);
38282 -                       buffer_path_simplify(srv->tmp_buf, srv->tmp_buf); 
38283 -                       buffer_append_string_buffer(p->stat_fn, srv->tmp_buf); 
38284 +                       buffer_path_simplify(srv->tmp_buf, srv->tmp_buf);
38285 +                       buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
38286                 } else {
38287                         /* virtual */
38288 -                       
38289 +
38290                         if (virt_path[0] == '/') {
38291                                 buffer_copy_string(p->stat_fn, virt_path);
38292                         } else {
38293                                 /* there is always a / */
38294                                 sl = strrchr(con->uri.path->ptr, '/');
38295 -                               
38296 +
38297                                 buffer_copy_string_len(p->stat_fn, con->uri.path->ptr, sl - con->uri.path->ptr + 1);
38298                                 buffer_append_string(p->stat_fn, virt_path);
38299                         }
38300 -                       
38301 +
38302                         buffer_urldecode_path(p->stat_fn);
38303                         buffer_path_simplify(srv->tmp_buf, p->stat_fn);
38304 -                       
38305 +
38306                         /* we have an uri */
38307 -                       
38308 +
38309                         buffer_copy_string_buffer(p->stat_fn, con->physical.doc_root);
38310                         buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
38311                 }
38312 -               
38313 +
38314                 if (0 == stat(p->stat_fn->ptr, &st)) {
38315                         time_t t = st.st_mtime;
38316 -                       
38317 +
38318                         switch (ssicmd) {
38319                         case SSI_FSIZE:
38320                                 b = chunkqueue_get_append_buffer(con->write_queue);
38321                                 if (p->sizefmt) {
38322                                         int j = 0;
38323                                         const char *abr[] = { " B", " kB", " MB", " GB", " TB", NULL };
38324 -                                       
38325 +
38326                                         off_t s = st.st_size;
38327 -                                       
38328 +
38329                                         for (j = 0; s > 1024 && abr[j+1]; s /= 1024, j++);
38330 -                                       
38331 +
38332                                         buffer_copy_off_t(b, s);
38333                                         buffer_append_string(b, abr[j]);
38334                                 } else {
38335 @@ -579,7 +580,7 @@
38336                         }
38337                 } else {
38338                         log_error_write(srv, __FILE__, __LINE__, "sbs",
38339 -                                       "ssi: stating failed ", 
38340 +                                       "ssi: stating failed ",
38341                                         p->stat_fn, strerror(errno));
38342                 }
38343                 break;
38344 @@ -593,33 +594,33 @@
38345                                 val = l[i+1];
38346                         } else {
38347                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38348 -                                               "ssi: unknow attribute for ", 
38349 +                                               "ssi: unknow attribute for ",
38350                                                 l[1], l[i]);
38351                         }
38352                 }
38353 -               
38354 +
38355                 if (p->if_is_false) break;
38356 -               
38357 +
38358                 if (key && val) {
38359                         data_string *ds;
38360 -                       
38361 +
38362                         if (NULL == (ds = (data_string *)array_get_unused_element(p->ssi_vars, TYPE_STRING))) {
38363                                 ds = data_string_init();
38364                         }
38365                         buffer_copy_string(ds->key,   key);
38366                         buffer_copy_string(ds->value, val);
38367 -                       
38368 +
38369                         array_insert_unique(p->ssi_vars, (data_unset *)ds);
38370                 } else {
38371                         log_error_write(srv, __FILE__, __LINE__, "sss",
38372 -                                       "ssi: var and value have to be set in", 
38373 +                                       "ssi: var and value have to be set in",
38374                                         l[0], l[1]);
38375                 }
38376                 break;
38377         }
38378 -       case SSI_CONFIG: 
38379 +       case SSI_CONFIG:
38380                 if (p->if_is_false) break;
38381 -               
38382 +
38383                 for (i = 2; i < n; i += 2) {
38384                         if (0 == strcmp(l[i], "timefmt")) {
38385                                 buffer_copy_string(p->timefmt, l[i+1]);
38386 @@ -632,63 +633,65 @@
38387                                         log_error_write(srv, __FILE__, __LINE__, "sssss",
38388                                                         "ssi: unknow value for attribute '",
38389                                                         l[i],
38390 -                                                       "' for ", 
38391 +                                                       "' for ",
38392                                                         l[1], l[i+1]);
38393                                 }
38394                         } else {
38395                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38396 -                                               "ssi: unknow attribute for ", 
38397 +                                               "ssi: unknow attribute for ",
38398                                                 l[1], l[i]);
38399                         }
38400                 }
38401                 break;
38402         case SSI_PRINTENV:
38403                 if (p->if_is_false) break;
38404 -               
38405 +
38406                 b = chunkqueue_get_append_buffer(con->write_queue);
38407                 buffer_copy_string(b, "<pre>");
38408                 for (i = 0; i < p->ssi_vars->used; i++) {
38409                         data_string *ds = (data_string *)p->ssi_vars->data[p->ssi_vars->sorted[i]];
38410 -                       
38411 +
38412                         buffer_append_string_buffer(b, ds->key);
38413                         buffer_append_string(b, ": ");
38414                         buffer_append_string_buffer(b, ds->value);
38415                         buffer_append_string(b, "<br />");
38416 -                                       
38417 +
38418                 }
38419                 buffer_append_string(b, "</pre>");
38420 -               
38421 +
38422                 break;
38423         case SSI_EXEC: {
38424 +#ifndef _WIN32
38425 +
38426                 const char *cmd = NULL;
38427                 pid_t pid;
38428                 int from_exec_fds[2];
38429 -               
38430 +
38431                 for (i = 2; i < n; i += 2) {
38432                         if (0 == strcmp(l[i], "cmd")) {
38433                                 cmd = l[i+1];
38434                         } else {
38435                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38436 -                                               "ssi: unknow attribute for ", 
38437 +                                               "ssi: unknow attribute for ",
38438                                                 l[1], l[i]);
38439                         }
38440                 }
38441 -               
38442 +
38443                 if (p->if_is_false) break;
38444 -               
38445 +
38446                 /* create a return pipe and send output to the html-page
38447 -                * 
38448 -                * as exec is assumed evil it is implemented synchronously 
38449 +                *
38450 +                * as exec is assumed evil it is implemented synchronously
38451                  */
38452 -               
38453 +
38454                 if (!cmd) break;
38455 -#ifdef HAVE_FORK       
38456 +
38457                 if (pipe(from_exec_fds)) {
38458 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
38459 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
38460                                         "pipe failed: ", strerror(errno));
38461                         return -1;
38462                 }
38463 -       
38464 +
38465                 /* fork, execve */
38466                 switch (pid = fork()) {
38467                 case 0: {
38468 @@ -698,14 +701,14 @@
38469                         close(from_exec_fds[1]);
38470                         /* not needed */
38471                         close(from_exec_fds[0]);
38472 -                       
38473 +
38474                         /* close stdin */
38475                         close(STDIN_FILENO);
38476 -               
38477 +
38478                         execl("/bin/sh", "sh", "-c", cmd, NULL);
38479 -                       
38480 +
38481                         log_error_write(srv, __FILE__, __LINE__, "sss", "spawing exec failed:", strerror(errno), cmd);
38482 -               
38483 +
38484                         /* */
38485                         SEGFAULT();
38486                         break;
38487 @@ -718,9 +721,9 @@
38488                         /* father */
38489                         int status;
38490                         ssize_t r;
38491 -                       
38492 +
38493                         close(from_exec_fds[1]);
38494 -                       
38495 +
38496                         /* wait for the client to end */
38497                         if (-1 == waitpid(pid, &status, 0)) {
38498                                 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed:", strerror(errno));
38499 @@ -730,7 +733,7 @@
38500  
38501                                 while(1) {
38502                                         if (ioctl(from_exec_fds[0], FIONREAD, &toread)) {
38503 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
38504 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
38505                                                         "unexpected end-of-file (perhaps the ssi-exec process died)");
38506                                                 return -1;
38507                                         }
38508 @@ -738,10 +741,10 @@
38509                                         if (toread > 0) {
38510                                                 b = chunkqueue_get_append_buffer(con->write_queue);
38511  
38512 -                                               buffer_prepare_copy(b, toread + 1); 
38513 +                                               buffer_prepare_copy(b, toread + 1);
38514  
38515                                                 if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) {
38516 -                                                       /* read failed */ 
38517 +                                                       /* read failed */
38518                                                         break;
38519                                                 } else {
38520                                                         b->used = r;
38521 @@ -755,59 +758,58 @@
38522                                 log_error_write(srv, __FILE__, __LINE__, "s", "process exited abnormally");
38523                         }
38524                         close(from_exec_fds[0]);
38525 -                       
38526 +
38527                         break;
38528                 }
38529                 }
38530  #else
38531 -
38532                 return -1;
38533  #endif
38534 -               
38535 +
38536                 break;
38537         }
38538         case SSI_IF: {
38539                 const char *expr = NULL;
38540 -               
38541 +
38542                 for (i = 2; i < n; i += 2) {
38543                         if (0 == strcmp(l[i], "expr")) {
38544                                 expr = l[i+1];
38545                         } else {
38546                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38547 -                                               "ssi: unknow attribute for ", 
38548 +                                               "ssi: unknow attribute for ",
38549                                                 l[1], l[i]);
38550                         }
38551                 }
38552 -               
38553 +
38554                 if (!expr) {
38555                         log_error_write(srv, __FILE__, __LINE__, "sss",
38556 -                                       "ssi: ", 
38557 +                                       "ssi: ",
38558                                         l[1], "expr missing");
38559                         break;
38560                 }
38561 -               
38562 +
38563                 if ((!p->if_is_false) &&
38564 -                   ((p->if_is_false_level == 0) || 
38565 +                   ((p->if_is_false_level == 0) ||
38566                      (p->if_level < p->if_is_false_level))) {
38567                         switch (ssi_eval_expr(srv, con, p, expr)) {
38568                         case -1:
38569 -                       case 0: 
38570 -                               p->if_is_false = 1; 
38571 +                       case 0:
38572 +                               p->if_is_false = 1;
38573                                 p->if_is_false_level = p->if_level;
38574                                 break;
38575 -                       case 1: 
38576 -                               p->if_is_false = 0; 
38577 +                       case 1:
38578 +                               p->if_is_false = 0;
38579                                 break;
38580                         }
38581                 }
38582 -               
38583 +
38584                 p->if_level++;
38585 -               
38586 +
38587                 break;
38588         }
38589         case SSI_ELSE:
38590                 p->if_level--;
38591 -               
38592 +
38593                 if (p->if_is_false) {
38594                         if ((p->if_level == p->if_is_false_level) &&
38595                             (p->if_is_false_endif == 0)) {
38596 @@ -815,11 +817,11 @@
38597                         }
38598                 } else {
38599                         p->if_is_false = 1;
38600 -                       
38601 +
38602                         p->if_is_false_level = p->if_level;
38603                 }
38604                 p->if_level++;
38605 -               
38606 +
38607                 break;
38608         case SSI_ELIF: {
38609                 const char *expr = NULL;
38610 @@ -828,52 +830,52 @@
38611                                 expr = l[i+1];
38612                         } else {
38613                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38614 -                                               "ssi: unknow attribute for ", 
38615 +                                               "ssi: unknow attribute for ",
38616                                                 l[1], l[i]);
38617                         }
38618                 }
38619 -               
38620 +
38621                 if (!expr) {
38622                         log_error_write(srv, __FILE__, __LINE__, "sss",
38623 -                                       "ssi: ", 
38624 +                                       "ssi: ",
38625                                         l[1], "expr missing");
38626                         break;
38627                 }
38628 -               
38629 +
38630                 p->if_level--;
38631 -               
38632 +
38633                 if (p->if_level == p->if_is_false_level) {
38634                         if ((p->if_is_false) &&
38635                             (p->if_is_false_endif == 0)) {
38636                                 switch (ssi_eval_expr(srv, con, p, expr)) {
38637                                 case -1:
38638 -                               case 0: 
38639 -                                       p->if_is_false = 1; 
38640 +                               case 0:
38641 +                                       p->if_is_false = 1;
38642                                         p->if_is_false_level = p->if_level;
38643                                         break;
38644 -                               case 1: 
38645 -                                       p->if_is_false = 0; 
38646 +                               case 1:
38647 +                                       p->if_is_false = 0;
38648                                         break;
38649                                 }
38650                         } else {
38651 -                               p->if_is_false = 1; 
38652 +                               p->if_is_false = 1;
38653                                 p->if_is_false_level = p->if_level;
38654                                 p->if_is_false_endif = 1;
38655                         }
38656                 }
38657 -               
38658 +
38659                 p->if_level++;
38660 -               
38661 +
38662                 break;
38663         }
38664         case SSI_ENDIF:
38665                 p->if_level--;
38666 -               
38667 +
38668                 if (p->if_level == p->if_is_false_level) {
38669                         p->if_is_false = 0;
38670                         p->if_is_false_endif = 0;
38671                 }
38672 -                       
38673 +
38674                 break;
38675         default:
38676                 log_error_write(srv, __FILE__, __LINE__, "ss",
38677 @@ -881,41 +883,41 @@
38678                                 l[1]);
38679                 break;
38680         }
38681 -       
38682 +
38683         return 0;
38684 -       
38685 +
38686  }
38687  
38688  static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) {
38689         stream s;
38690  #ifdef  HAVE_PCRE_H
38691         int i, n;
38692 -       
38693 +
38694  #define N 10
38695         int ovec[N * 3];
38696  #endif
38697 -       
38698 +
38699         /* get a stream to the file */
38700 -       
38701 +
38702         array_reset(p->ssi_vars);
38703         array_reset(p->ssi_cgi_env);
38704         buffer_copy_string(p->timefmt, "%a, %d %b %Y %H:%M:%S %Z");
38705         p->sizefmt = 0;
38706         build_ssi_cgi_vars(srv, con, p);
38707         p->if_is_false = 0;
38708 -       
38709 +
38710         if (-1 == stream_open(&s, con->physical.path)) {
38711                 log_error_write(srv, __FILE__, __LINE__, "sb",
38712                                 "stream-open: ", con->physical.path);
38713                 return -1;
38714         }
38715 -       
38716 -       
38717 +
38718 +
38719         /**
38720 -        * <!--#element attribute=value attribute=value ... --> 
38721 -        * 
38722 +        * <!--#element attribute=value attribute=value ... -->
38723 +        *
38724          * config       DONE
38725 -        *   errmsg     -- missing 
38726 +        *   errmsg     -- missing
38727          *   sizefmt    DONE
38728          *   timefmt    DONE
38729          * echo         DONE
38730 @@ -937,13 +939,13 @@
38731          * set          DONE
38732          *   var        DONE
38733          *   value      DONE
38734 -        * 
38735 +        *
38736          * if           DONE
38737          * elif         DONE
38738          * else         DONE
38739          * endif        DONE
38740 -        * 
38741 -        * 
38742 +        *
38743 +        *
38744          * expressions
38745          * AND, OR      DONE
38746          * comp         DONE
38747 @@ -951,118 +953,115 @@
38748          * $...         DONE
38749          * '...'        DONE
38750          * ( ... )      DONE
38751 -        * 
38752 -        * 
38753 -        * 
38754 +        *
38755 +        *
38756 +        *
38757          * ** all DONE **
38758 -        * DATE_GMT 
38759 -        *   The current date in Greenwich Mean Time. 
38760 -        * DATE_LOCAL 
38761 -        *   The current date in the local time zone. 
38762 -        * DOCUMENT_NAME 
38763 -        *   The filename (excluding directories) of the document requested by the user. 
38764 -        * DOCUMENT_URI 
38765 -        *   The (%-decoded) URL path of the document requested by the user. Note that in the case of nested include files, this is not then URL for the current document. 
38766 -        * LAST_MODIFIED 
38767 -        *   The last modification date of the document requested by the user. 
38768 -        * USER_NAME 
38769 +        * DATE_GMT
38770 +        *   The current date in Greenwich Mean Time.
38771 +        * DATE_LOCAL
38772 +        *   The current date in the local time zone.
38773 +        * DOCUMENT_NAME
38774 +        *   The filename (excluding directories) of the document requested by the user.
38775 +        * DOCUMENT_URI
38776 +        *   The (%-decoded) URL path of the document requested by the user. Note that in the case of nested include files, this is not then URL for the current document.
38777 +        * LAST_MODIFIED
38778 +        *   The last modification date of the document requested by the user.
38779 +        * USER_NAME
38780          *   Contains the owner of the file which included it.
38781 -        * 
38782 +        *
38783          */
38784 -#ifdef HAVE_PCRE_H     
38785 +#ifdef HAVE_PCRE_H
38786         for (i = 0; (n = pcre_exec(p->ssi_regex, NULL, s.start, s.size, i, 0, ovec, N * 3)) > 0; i = ovec[1]) {
38787                 const char **l;
38788                 /* take everything from last offset to current match pos */
38789 -               
38790 +
38791                 if (!p->if_is_false) chunkqueue_append_file(con->write_queue, con->physical.path, i, ovec[0] - i);
38792 -               
38793 +
38794                 pcre_get_substring_list(s.start, ovec, n, &l);
38795                 process_ssi_stmt(srv, con, p, l, n);
38796                 pcre_free_substring_list(l);
38797         }
38798 -       
38799 +
38800         switch(n) {
38801         case PCRE_ERROR_NOMATCH:
38802                 /* copy everything/the rest */
38803                 chunkqueue_append_file(con->write_queue, con->physical.path, i, s.size - i);
38804 -               
38805 +
38806                 break;
38807         default:
38808                 log_error_write(srv, __FILE__, __LINE__, "sd",
38809                                 "execution error while matching: ", n);
38810                 break;
38811         }
38812 -#endif 
38813 -       
38814 -       
38815 +#endif
38816 +
38817 +
38818         stream_close(&s);
38819 -       
38820 +
38821         con->file_started  = 1;
38822         con->file_finished = 1;
38823 -       
38824 +
38825         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
38826 -       
38827 +
38828         /* reset physical.path */
38829         buffer_reset(con->physical.path);
38830 -       
38831 +
38832         return 0;
38833  }
38834  
38835 -#define PATCH(x) \
38836 -       p->conf.x = s->x;
38837  static int mod_ssi_patch_connection(server *srv, connection *con, plugin_data *p) {
38838         size_t i, j;
38839         plugin_config *s = p->config_storage[0];
38840 -       
38841 -       PATCH(ssi_extension);
38842 -       
38843 +
38844 +       PATCH_OPTION(ssi_extension);
38845 +
38846         /* skip the first, the global context */
38847         for (i = 1; i < srv->config_context->used; i++) {
38848                 data_config *dc = (data_config *)srv->config_context->data[i];
38849                 s = p->config_storage[i];
38850 -               
38851 +
38852                 /* condition didn't match */
38853                 if (!config_check_cond(srv, con, dc)) continue;
38854 -               
38855 +
38856                 /* merge config */
38857                 for (j = 0; j < dc->value->used; j++) {
38858                         data_unset *du = dc->value->data[j];
38859 -                       
38860 +
38861                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssi.extension"))) {
38862 -                               PATCH(ssi_extension);
38863 +                               PATCH_OPTION(ssi_extension);
38864                         }
38865                 }
38866         }
38867 -       
38868 +
38869         return 0;
38870  }
38871 -#undef PATCH
38872  
38873  URIHANDLER_FUNC(mod_ssi_physical_path) {
38874         plugin_data *p = p_d;
38875         size_t k;
38876 -       
38877 +
38878         if (con->physical.path->used == 0) return HANDLER_GO_ON;
38879 -       
38880 +
38881         mod_ssi_patch_connection(srv, con, p);
38882 -       
38883 +
38884         for (k = 0; k < p->conf.ssi_extension->used; k++) {
38885                 data_string *ds = (data_string *)p->conf.ssi_extension->data[k];
38886 -               
38887 +
38888                 if (ds->value->used == 0) continue;
38889 -               
38890 +
38891                 if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
38892                         /* handle ssi-request */
38893 -                       
38894 +
38895                         if (mod_ssi_handle_request(srv, con, p)) {
38896                                 /* on error */
38897                                 con->http_status = 500;
38898                         }
38899 -                       
38900 +
38901                         return HANDLER_FINISHED;
38902                 }
38903         }
38904 -       
38905 +
38906         /* not found */
38907         return HANDLER_GO_ON;
38908  }
38909 @@ -1072,13 +1071,13 @@
38910  int mod_ssi_plugin_init(plugin *p) {
38911         p->version     = LIGHTTPD_VERSION_ID;
38912         p->name        = buffer_init_string("ssi");
38913 -       
38914 +
38915         p->init        = mod_ssi_init;
38916         p->handle_subrequest_start = mod_ssi_physical_path;
38917         p->set_defaults  = mod_ssi_set_defaults;
38918         p->cleanup     = mod_ssi_free;
38919 -       
38920 +
38921         p->data        = NULL;
38922 -       
38923 +
38924         return 0;
38925  }
38926 --- ../lighttpd-1.4.11/src/mod_ssi.h    2005-08-11 01:26:39.000000000 +0300
38927 +++ lighttpd-1.4.12/src/mod_ssi.h       2006-07-16 00:26:04.000000000 +0300
38928 @@ -19,23 +19,23 @@
38929  
38930  typedef struct {
38931         PLUGIN_DATA;
38932 -       
38933 -#ifdef HAVE_PCRE_H     
38934 +
38935 +#ifdef HAVE_PCRE_H
38936         pcre *ssi_regex;
38937 -#endif 
38938 +#endif
38939         buffer *timefmt;
38940         int sizefmt;
38941 -       
38942 +
38943         buffer *stat_fn;
38944 -       
38945 +
38946         array *ssi_vars;
38947         array *ssi_cgi_env;
38948 -       
38949 +
38950         int if_level, if_is_false_level, if_is_false, if_is_false_endif;
38951 -       
38952 +
38953         plugin_config **config_storage;
38954 -       
38955 -       plugin_config conf; 
38956 +
38957 +       plugin_config conf;
38958  } plugin_data;
38959  
38960  int ssi_eval_expr(server *srv, connection *con, plugin_data *p, const char *expr);
38961 --- ../lighttpd-1.4.11/src/mod_ssi_expr.c       2005-08-11 01:26:48.000000000 +0300
38962 +++ lighttpd-1.4.12/src/mod_ssi_expr.c  2006-07-16 00:26:04.000000000 +0300
38963 @@ -11,9 +11,9 @@
38964         const char *input;
38965         size_t offset;
38966         size_t size;
38967 -       
38968 +
38969         int line_pos;
38970 -       
38971 +
38972         int in_key;
38973         int in_brace;
38974         int in_cond;
38975 @@ -21,15 +21,15 @@
38976  
38977  ssi_val_t *ssi_val_init() {
38978         ssi_val_t *s;
38979 -       
38980 +
38981         s = calloc(1, sizeof(*s));
38982 -       
38983 +
38984         return s;
38985  }
38986  
38987  void ssi_val_free(ssi_val_t *s) {
38988         if (s->str) buffer_free(s->str);
38989 -       
38990 +
38991         free(s);
38992  }
38993  
38994 @@ -45,175 +45,175 @@
38995                               ssi_tokenizer_t *t, int *token_id, buffer *token) {
38996         int tid = 0;
38997         size_t i;
38998 -       
38999 +
39000         UNUSED(con);
39001  
39002         for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
39003                 char c = t->input[t->offset];
39004                 data_string *ds;
39005 -               
39006 +
39007                 switch (c) {
39008 -               case '=': 
39009 +               case '=':
39010                         tid = TK_EQ;
39011 -                       
39012 +
39013                         t->offset++;
39014                         t->line_pos++;
39015 -                       
39016 +
39017                         buffer_copy_string(token, "(=)");
39018 -                       
39019 +
39020                         break;
39021                 case '>':
39022                         if (t->input[t->offset + 1] == '=') {
39023                                 t->offset += 2;
39024                                 t->line_pos += 2;
39025 -                               
39026 +
39027                                 tid = TK_GE;
39028 -                               
39029 +
39030                                 buffer_copy_string(token, "(>=)");
39031                         } else {
39032                                 t->offset += 1;
39033                                 t->line_pos += 1;
39034 -                               
39035 +
39036                                 tid = TK_GT;
39037 -                               
39038 +
39039                                 buffer_copy_string(token, "(>)");
39040                         }
39041 -                       
39042 +
39043                         break;
39044                 case '<':
39045                         if (t->input[t->offset + 1] == '=') {
39046                                 t->offset += 2;
39047                                 t->line_pos += 2;
39048 -                               
39049 +
39050                                 tid = TK_LE;
39051 -                               
39052 +
39053                                 buffer_copy_string(token, "(<=)");
39054                         } else {
39055                                 t->offset += 1;
39056                                 t->line_pos += 1;
39057 -                               
39058 +
39059                                 tid = TK_LT;
39060 -                               
39061 +
39062                                 buffer_copy_string(token, "(<)");
39063                         }
39064 -                       
39065 +
39066                         break;
39067 -                       
39068 +
39069                 case '!':
39070                         if (t->input[t->offset + 1] == '=') {
39071                                 t->offset += 2;
39072                                 t->line_pos += 2;
39073 -                               
39074 +
39075                                 tid = TK_NE;
39076 -                               
39077 +
39078                                 buffer_copy_string(token, "(!=)");
39079                         } else {
39080                                 t->offset += 1;
39081                                 t->line_pos += 1;
39082 -                               
39083 +
39084                                 tid = TK_NOT;
39085 -                               
39086 +
39087                                 buffer_copy_string(token, "(!)");
39088                         }
39089 -                       
39090 +
39091                         break;
39092                 case '&':
39093                         if (t->input[t->offset + 1] == '&') {
39094                                 t->offset += 2;
39095                                 t->line_pos += 2;
39096 -                               
39097 +
39098                                 tid = TK_AND;
39099 -                               
39100 +
39101                                 buffer_copy_string(token, "(&&)");
39102                         } else {
39103 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
39104 -                                               "pos:", t->line_pos, 
39105 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
39106 +                                               "pos:", t->line_pos,
39107                                                 "missing second &");
39108                                 return -1;
39109                         }
39110 -                       
39111 +
39112                         break;
39113                 case '|':
39114                         if (t->input[t->offset + 1] == '|') {
39115                                 t->offset += 2;
39116                                 t->line_pos += 2;
39117 -                               
39118 +
39119                                 tid = TK_OR;
39120 -                               
39121 +
39122                                 buffer_copy_string(token, "(||)");
39123                         } else {
39124 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
39125 -                                               "pos:", t->line_pos, 
39126 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
39127 +                                               "pos:", t->line_pos,
39128                                                 "missing second |");
39129                                 return -1;
39130                         }
39131 -                       
39132 +
39133                         break;
39134                 case '\t':
39135                 case ' ':
39136                         t->offset++;
39137                         t->line_pos++;
39138                         break;
39139 -                       
39140 +
39141                 case '\'':
39142                         /* search for the terminating " */
39143                         for (i = 1; t->input[t->offset + i] && t->input[t->offset + i] != '\'';  i++);
39144 -                       
39145 +
39146                         if (t->input[t->offset + i]) {
39147                                 tid = TK_VALUE;
39148 -                               
39149 +
39150                                 buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
39151 -                               
39152 +
39153                                 t->offset += i + 1;
39154                                 t->line_pos += i + 1;
39155                         } else {
39156                                 /* ERROR */
39157 -                               
39158 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
39159 -                                               "pos:", t->line_pos, 
39160 +
39161 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
39162 +                                               "pos:", t->line_pos,
39163                                                 "missing closing quote");
39164 -                               
39165 +
39166                                 return -1;
39167                         }
39168 -                       
39169 +
39170                         break;
39171                 case '(':
39172                         t->offset++;
39173                         t->in_brace++;
39174 -                               
39175 +
39176                         tid = TK_LPARAN;
39177 -                               
39178 +
39179                         buffer_copy_string(token, "(");
39180                         break;
39181                 case ')':
39182                         t->offset++;
39183                         t->in_brace--;
39184 -                               
39185 +
39186                         tid = TK_RPARAN;
39187 -                               
39188 +
39189                         buffer_copy_string(token, ")");
39190                         break;
39191                 case '$':
39192                         if (t->input[t->offset + 1] == '{') {
39193                                 for (i = 2; t->input[t->offset + i] && t->input[t->offset + i] != '}';  i++);
39194 -                               
39195 +
39196                                 if (t->input[t->offset + i] != '}') {
39197 -                                       log_error_write(srv, __FILE__, __LINE__, "sds", 
39198 -                                                       "pos:", t->line_pos, 
39199 +                                       log_error_write(srv, __FILE__, __LINE__, "sds",
39200 +                                                       "pos:", t->line_pos,
39201                                                         "missing closing quote");
39202 -                                       
39203 +
39204                                         return -1;
39205                                 }
39206 -                               
39207 +
39208                                 buffer_copy_string_len(token, t->input + t->offset + 2, i-3);
39209                         } else {
39210                                 for (i = 1; isalpha(t->input[t->offset + i]) || t->input[t->offset + i] == '_';  i++);
39211 -                               
39212 +
39213                                 buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
39214                         }
39215 -                       
39216 +
39217                         tid = TK_VALUE;
39218 -                       
39219 +
39220                         if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, token->ptr))) {
39221                                 buffer_copy_string_buffer(token, ds->value);
39222                         } else if (NULL != (ds = (data_string *)array_get_element(p->ssi_vars, token->ptr))) {
39223 @@ -221,16 +221,16 @@
39224                         } else {
39225                                 buffer_copy_string(token, "");
39226                         }
39227 -                               
39228 +
39229                         t->offset += i;
39230                         t->line_pos += i;
39231 -                       
39232 +
39233                         break;
39234                 default:
39235                         for (i = 0; isgraph(t->input[t->offset + i]);  i++) {
39236                                 char d = t->input[t->offset + i];
39237                                 switch(d) {
39238 -                               case ' ': 
39239 +                               case ' ':
39240                                 case '\t':
39241                                 case ')':
39242                                 case '(':
39243 @@ -244,25 +244,25 @@
39244                                         break;
39245                                 }
39246                         }
39247 -                       
39248 +
39249                         tid = TK_VALUE;
39250 -                               
39251 +
39252                         buffer_copy_string_len(token, t->input + t->offset, i);
39253 -                               
39254 +
39255                         t->offset += i;
39256                         t->line_pos += i;
39257 -                       
39258 +
39259                         break;
39260                 }
39261         }
39262 -                       
39263 +
39264         if (tid) {
39265                 *token_id = tid;
39266 -               
39267 +
39268                 return 1;
39269         } else if (t->offset < t->size) {
39270 -               log_error_write(srv, __FILE__, __LINE__, "sds", 
39271 -                               "pos:", t->line_pos, 
39272 +               log_error_write(srv, __FILE__, __LINE__, "sds",
39273 +                               "pos:", t->line_pos,
39274                                 "foobar");
39275         }
39276         return 0;
39277 @@ -275,50 +275,50 @@
39278         buffer *token;
39279         ssi_ctx_t context;
39280         int ret;
39281 -       
39282 +
39283         t.input = expr;
39284         t.offset = 0;
39285         t.size = strlen(expr);
39286         t.line_pos = 1;
39287 -       
39288 +
39289         t.in_key = 1;
39290         t.in_brace = 0;
39291         t.in_cond = 0;
39292 -       
39293 +
39294         context.ok = 1;
39295         context.srv = srv;
39296 -       
39297 +
39298         /* default context */
39299 -       
39300 +
39301         pParser = ssiexprparserAlloc( malloc );
39302         token = buffer_init();
39303         while((1 == (ret = ssi_expr_tokenizer(srv, con, p, &t, &token_id, token))) && context.ok) {
39304                 ssiexprparser(pParser, token_id, token, &context);
39305 -               
39306 +
39307                 token = buffer_init();
39308         }
39309         ssiexprparser(pParser, 0, token, &context);
39310         ssiexprparserFree(pParser, free );
39311 -       
39312 +
39313         buffer_free(token);
39314 -       
39315 +
39316         if (ret == -1) {
39317 -               log_error_write(srv, __FILE__, __LINE__, "s", 
39318 +               log_error_write(srv, __FILE__, __LINE__, "s",
39319                                 "expr parser failed");
39320                 return -1;
39321         }
39322 -       
39323 +
39324         if (context.ok == 0) {
39325 -               log_error_write(srv, __FILE__, __LINE__, "sds", 
39326 -                               "pos:", t.line_pos, 
39327 +               log_error_write(srv, __FILE__, __LINE__, "sds",
39328 +                               "pos:", t.line_pos,
39329                                 "parser failed somehow near here");
39330                 return -1;
39331         }
39332  #if 0
39333 -       log_error_write(srv, __FILE__, __LINE__, "ssd", 
39334 +       log_error_write(srv, __FILE__, __LINE__, "ssd",
39335                         "expr: ",
39336                         expr,
39337                         context.val.bo);
39338 -#endif 
39339 +#endif
39340         return context.val.bo;
39341  }
39342 --- ../lighttpd-1.4.11/src/mod_ssi_expr.h       2005-08-11 01:26:48.000000000 +0300
39343 +++ lighttpd-1.4.12/src/mod_ssi_expr.h  2006-07-16 00:26:04.000000000 +0300
39344 @@ -5,16 +5,16 @@
39345  
39346  typedef struct {
39347         enum { SSI_TYPE_UNSET, SSI_TYPE_BOOL, SSI_TYPE_STRING } type;
39348 -       
39349 +
39350         buffer *str;
39351         int     bo;
39352  } ssi_val_t;
39353  
39354  typedef struct {
39355         int     ok;
39356 -       
39357 +
39358         ssi_val_t val;
39359 -       
39360 +
39361         void   *srv;
39362  } ssi_ctx_t;
39363  
39364 --- ../lighttpd-1.4.11/src/mod_ssi_exprparser.c 2005-10-03 00:40:25.000000000 +0300
39365 +++ lighttpd-1.4.12/src/mod_ssi_exprparser.c    2006-07-17 22:02:23.000000000 +0300
39366 @@ -18,10 +18,10 @@
39367  /* Next is all token values, in a form suitable for use by makeheaders.
39368  ** This section will be null unless lemon is run with the -m switch.
39369  */
39370 -/* 
39371 +/*
39372  ** These constants (all generated automatically by the parser generator)
39373  ** specify the various kinds of tokens (terminals) that the parser
39374 -** understands. 
39375 +** understands.
39376  **
39377  ** Each symbol here is a terminal symbol in the grammar.
39378  */
39379 @@ -38,7 +38,7 @@
39380  **                       and nonterminals.  "int" is used otherwise.
39381  **    YYNOCODE           is a number of type YYCODETYPE which corresponds
39382  **                       to no legal terminal or nonterminal number.  This
39383 -**                       number is used to fill in empty slots of the hash 
39384 +**                       number is used to fill in empty slots of the hash
39385  **                       table.
39386  **    YYFALLBACK         If defined, this indicates that one or more tokens
39387  **                       have fall-back values which should be used if the
39388 @@ -47,7 +47,7 @@
39389  **                       and nonterminal numbers.  "unsigned char" is
39390  **                       used if there are fewer than 250 rules and
39391  **                       states combined.  "int" is used otherwise.
39392 -**    ssiexprparserTOKENTYPE     is the data type used for minor tokens given 
39393 +**    ssiexprparserTOKENTYPE     is the data type used for minor tokens given
39394  **                       directly to the parser from the tokenizer.
39395  **    YYMINORTYPE        is the data type used for all minor tokens.
39396  **                       This is typically a union of many types, one of
39397 @@ -91,7 +91,7 @@
39398  /* Next are that tables used to determine what action to take based on the
39399  ** current state and lookahead token.  These tables are used to implement
39400  ** functions that take a state number and lookahead value and return an
39401 -** action integer.  
39402 +** action integer.
39403  **
39404  ** Suppose the action integer is N.  Then the action is determined as
39405  ** follows
39406 @@ -116,7 +116,7 @@
39407  ** If the index value yy_shift_ofst[S]+X is out of range or if the value
39408  ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
39409  ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
39410 -** and that yy_default[S] should be used instead.  
39411 +** and that yy_default[S] should be used instead.
39412  **
39413  ** The formula above is for computing the action when the lookahead is
39414  ** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
39415 @@ -168,7 +168,7 @@
39416  
39417  /* The next table maps tokens into fallback tokens.  If a construct
39418  ** like the following:
39419 -** 
39420 +**
39421  **      %fallback ID X Y Z.
39422  **
39423  ** appears in the grammer, then ID becomes a fallback token for X, Y,
39424 @@ -219,10 +219,10 @@
39425  #endif /* NDEBUG */
39426  
39427  #ifndef NDEBUG
39428 -/* 
39429 +/*
39430  ** Turn parser tracing on by giving a stream to which to write the trace
39431  ** and a prompt to preface each trace message.  Tracing is turned off
39432 -** by making either argument NULL 
39433 +** by making either argument NULL
39434  **
39435  ** Inputs:
39436  ** <ul>
39437 @@ -247,7 +247,7 @@
39438  #ifndef NDEBUG
39439  /* For tracing shifts, the names of all terminals and nonterminals
39440  ** are required.  The following table supplies these names */
39441 -static const char *yyTokenName[] = { 
39442 +static const char *yyTokenName[] = {
39443    "$",             "AND",           "OR",            "EQ",          
39444    "NE",            "GT",            "GE",            "LT",          
39445    "LE",            "NOT",           "LPARAN",        "RPARAN",      
39446 @@ -295,7 +295,7 @@
39447  #endif
39448  }
39449  
39450 -/* 
39451 +/*
39452  ** This function allocates a new parser.
39453  ** The only argument is a pointer to a function which works like
39454  ** malloc.
39455 @@ -326,7 +326,7 @@
39456      /* Here is inserted the actions which take place when a
39457      ** terminal or non-terminal is destroyed.  This can happen
39458      ** when the symbol is popped from the stack during a
39459 -    ** reduce or during error processing or when a parser is 
39460 +    ** reduce or during error processing or when a parser is
39461      ** being destroyed before it is finished parsing.
39462      **
39463      ** Note: during a reduce, the only symbols destroyed are those
39464 @@ -379,7 +379,7 @@
39465    return yymajor;
39466  }
39467  
39468 -/* 
39469 +/*
39470  ** Deallocate and destroy a parser.  Destructors are all called for
39471  ** all stack elements before shutting the parser down.
39472  **
39473 @@ -415,7 +415,7 @@
39474  ){
39475    int i;
39476    int stateno = pParser->yystack[pParser->yyidx].stateno;
39477
39478 +
39479    /* if( pParser->yyidx<0 ) return YY_NO_ACTION;  */
39480    i = yy_shift_ofst[stateno];
39481    if( i==YY_SHIFT_USE_DFLT ){
39482 @@ -459,7 +459,7 @@
39483  ){
39484    int i;
39485    int stateno = pParser->yystack[pParser->yyidx].stateno;
39486
39487 +
39488    i = yy_reduce_ofst[stateno];
39489    if( i==YY_REDUCE_USE_DFLT ){
39490      return yy_default[stateno];
39491 @@ -559,7 +559,7 @@
39492    ssiexprparserARG_FETCH;
39493    yymsp = &yypParser->yystack[yypParser->yyidx];
39494  #ifndef NDEBUG
39495 -  if( yyTraceFILE && yyruleno>=0 
39496 +  if( yyTraceFILE && yyruleno>=0
39497          && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
39498      fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
39499        yyRuleName[yyruleno]);
39500 @@ -872,7 +872,7 @@
39501  #ifdef YYERRORSYMBOL
39502        /* A syntax error has occurred.
39503        ** The response to an error depends upon whether or not the
39504 -      ** grammar defines an error token "ERROR".  
39505 +      ** grammar defines an error token "ERROR".
39506        **
39507        ** This is what we do if the grammar does define ERROR:
39508        **
39509 --- ../lighttpd-1.4.11/src/mod_staticfile.c     2006-02-15 14:31:14.000000000 +0200
39510 +++ lighttpd-1.4.12/src/mod_staticfile.c        2006-07-16 00:26:03.000000000 +0300
39511 @@ -14,9 +14,11 @@
39512  #include "http_chunk.h"
39513  #include "response.h"
39514  
39515 +#include "sys-files.h"
39516 +#include "sys-strings.h"
39517  /**
39518   * this is a staticfile for a lighttpd plugin
39519 - * 
39520 + *
39521   */
39522  
39523  
39524 @@ -29,48 +31,48 @@
39525  
39526  typedef struct {
39527         PLUGIN_DATA;
39528 -       
39529 +
39530         buffer *range_buf;
39531 -       
39532 +
39533         plugin_config **config_storage;
39534 -       
39535 -       plugin_config conf; 
39536 +
39537 +       plugin_config conf;
39538  } plugin_data;
39539  
39540  /* init the plugin data */
39541  INIT_FUNC(mod_staticfile_init) {
39542         plugin_data *p;
39543 -       
39544 +
39545         p = calloc(1, sizeof(*p));
39546 -       
39547 +
39548         p->range_buf = buffer_init();
39549 -       
39550 +
39551         return p;
39552  }
39553  
39554 -/* detroy the plugin data */
39555 +/* destroy the plugin data */
39556  FREE_FUNC(mod_staticfile_free) {
39557         plugin_data *p = p_d;
39558 -       
39559 +
39560         UNUSED(srv);
39561  
39562         if (!p) return HANDLER_GO_ON;
39563 -       
39564 +
39565         if (p->config_storage) {
39566                 size_t i;
39567                 for (i = 0; i < srv->config_context->used; i++) {
39568                         plugin_config *s = p->config_storage[i];
39569 -                       
39570 +
39571                         array_free(s->exclude_ext);
39572 -                       
39573 +
39574                         free(s);
39575                 }
39576                 free(p->config_storage);
39577         }
39578         buffer_free(p->range_buf);
39579 -       
39580 +
39581         free(p);
39582 -       
39583 +
39584         return HANDLER_GO_ON;
39585  }
39586  
39587 @@ -79,63 +81,60 @@
39588  SETDEFAULTS_FUNC(mod_staticfile_set_defaults) {
39589         plugin_data *p = p_d;
39590         size_t i = 0;
39591 -       
39592 -       config_values_t cv[] = { 
39593 +
39594 +       config_values_t cv[] = {
39595                 { "static-file.exclude-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
39596                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
39597         };
39598 -       
39599 +
39600         if (!p) return HANDLER_ERROR;
39601 -       
39602 +
39603         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
39604 -       
39605 +
39606         for (i = 0; i < srv->config_context->used; i++) {
39607                 plugin_config *s;
39608 -               
39609 +
39610                 s = calloc(1, sizeof(plugin_config));
39611                 s->exclude_ext    = array_init();
39612 -               
39613 +
39614                 cv[0].destination = s->exclude_ext;
39615 -               
39616 +
39617                 p->config_storage[i] = s;
39618 -       
39619 +
39620                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
39621                         return HANDLER_ERROR;
39622                 }
39623         }
39624 -       
39625 +
39626         return HANDLER_GO_ON;
39627  }
39628  
39629 -#define PATCH(x) \
39630 -       p->conf.x = s->x;
39631  static int mod_staticfile_patch_connection(server *srv, connection *con, plugin_data *p) {
39632         size_t i, j;
39633         plugin_config *s = p->config_storage[0];
39634 -       
39635 -       PATCH(exclude_ext);
39636 -       
39637 +
39638 +       PATCH_OPTION(exclude_ext);
39639 +
39640         /* skip the first, the global context */
39641         for (i = 1; i < srv->config_context->used; i++) {
39642                 data_config *dc = (data_config *)srv->config_context->data[i];
39643                 s = p->config_storage[i];
39644 -               
39645 +
39646                 /* condition didn't match */
39647                 if (!config_check_cond(srv, con, dc)) continue;
39648 -               
39649 +
39650                 /* merge config */
39651                 for (j = 0; j < dc->value->used; j++) {
39652                         data_unset *du = dc->value->data[j];
39653 -                       
39654 +
39655                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("static-file.exclude-extensions"))) {
39656 -                               PATCH(exclude_ext);
39657 +                               PATCH_OPTION(exclude_ext);
39658                         }
39659                 }
39660         }
39661 -       
39662 +
39663         return 0;
39664  }
39665 -#undef PATCH
39666  
39667  static int http_response_parse_range(server *srv, connection *con, plugin_data *p) {
39668         int multipart = 0;
39669 @@ -146,69 +145,69 @@
39670         data_string *ds;
39671         stat_cache_entry *sce = NULL;
39672         buffer *content_type = NULL;
39673 -       
39674 +
39675         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
39676                 SEGFAULT();
39677         }
39678 -       
39679 +
39680         start = 0;
39681         end = sce->st.st_size - 1;
39682 -       
39683 +
39684         con->response.content_length = 0;
39685 -       
39686 +
39687         if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Content-Type"))) {
39688                 content_type = ds->value;
39689         }
39690 -       
39691 +
39692         for (s = con->request.http_range, error = 0;
39693              !error && *s && NULL != (minus = strchr(s, '-')); ) {
39694                 char *err;
39695                 off_t la, le;
39696 -               
39697 +
39698                 if (s == minus) {
39699                         /* -<stop> */
39700 -                       
39701 +
39702                         le = strtoll(s, &err, 10);
39703 -                       
39704 +
39705                         if (le == 0) {
39706                                 /* RFC 2616 - 14.35.1 */
39707 -                               
39708 +
39709                                 con->http_status = 416;
39710                                 error = 1;
39711                         } else if (*err == '\0') {
39712                                 /* end */
39713                                 s = err;
39714 -                               
39715 +
39716                                 end = sce->st.st_size - 1;
39717                                 start = sce->st.st_size + le;
39718                         } else if (*err == ',') {
39719                                 multipart = 1;
39720                                 s = err + 1;
39721 -                               
39722 +
39723                                 end = sce->st.st_size - 1;
39724                                 start = sce->st.st_size + le;
39725                         } else {
39726                                 error = 1;
39727                         }
39728 -                       
39729 +
39730                 } else if (*(minus+1) == '\0' || *(minus+1) == ',') {
39731                         /* <start>- */
39732 -                       
39733 +
39734                         la = strtoll(s, &err, 10);
39735 -                       
39736 +
39737                         if (err == minus) {
39738                                 /* ok */
39739 -                               
39740 +
39741                                 if (*(err + 1) == '\0') {
39742                                         s = err + 1;
39743 -                                       
39744 +
39745                                         end = sce->st.st_size - 1;
39746                                         start = la;
39747 -                                       
39748 +
39749                                 } else if (*(err + 1) == ',') {
39750                                         multipart = 1;
39751                                         s = err + 2;
39752 -                                       
39753 +
39754                                         end = sce->st.st_size - 1;
39755                                         start = la;
39756                                 } else {
39757 @@ -220,64 +219,64 @@
39758                         }
39759                 } else {
39760                         /* <start>-<stop> */
39761 -                       
39762 +
39763                         la = strtoll(s, &err, 10);
39764 -                       
39765 +
39766                         if (err == minus) {
39767                                 le = strtoll(minus+1, &err, 10);
39768 -                               
39769 +
39770                                 /* RFC 2616 - 14.35.1 */
39771                                 if (la > le) {
39772                                         error = 1;
39773                                 }
39774 -                                       
39775 +
39776                                 if (*err == '\0') {
39777                                         /* ok, end*/
39778                                         s = err;
39779 -                                       
39780 +
39781                                         end = le;
39782                                         start = la;
39783                                 } else if (*err == ',') {
39784                                         multipart = 1;
39785                                         s = err + 1;
39786 -                                       
39787 +
39788                                         end = le;
39789                                         start = la;
39790                                 } else {
39791                                         /* error */
39792 -                                       
39793 +
39794                                         error = 1;
39795                                 }
39796                         } else {
39797                                 /* error */
39798 -                               
39799 +
39800                                 error = 1;
39801                         }
39802                 }
39803 -               
39804 +
39805                 if (!error) {
39806                         if (start < 0) start = 0;
39807 -                       
39808 +
39809                         /* RFC 2616 - 14.35.1 */
39810                         if (end > sce->st.st_size - 1) end = sce->st.st_size - 1;
39811 -                       
39812 +
39813                         if (start > sce->st.st_size - 1) {
39814                                 error = 1;
39815 -                               
39816 +
39817                                 con->http_status = 416;
39818                         }
39819                 }
39820 -               
39821 +
39822                 if (!error) {
39823                         if (multipart) {
39824                                 /* write boundary-header */
39825                                 buffer *b;
39826 -                               
39827 +
39828                                 b = chunkqueue_get_append_buffer(con->write_queue);
39829 -                               
39830 +
39831                                 buffer_copy_string(b, "\r\n--");
39832                                 buffer_append_string(b, boundary);
39833 -                               
39834 +
39835                                 /* write Content-Range */
39836                                 buffer_append_string(b, "\r\nContent-Range: bytes ");
39837                                 buffer_append_off_t(b, start);
39838 @@ -285,54 +284,54 @@
39839                                 buffer_append_off_t(b, end);
39840                                 buffer_append_string(b, "/");
39841                                 buffer_append_off_t(b, sce->st.st_size);
39842 -                               
39843 +
39844                                 buffer_append_string(b, "\r\nContent-Type: ");
39845                                 buffer_append_string_buffer(b, content_type);
39846 -                               
39847 +
39848                                 /* write END-OF-HEADER */
39849                                 buffer_append_string(b, "\r\n\r\n");
39850 -                               
39851 +
39852                                 con->response.content_length += b->used - 1;
39853 -                               
39854 +
39855                         }
39856 -                       
39857 +
39858                         chunkqueue_append_file(con->write_queue, con->physical.path, start, end - start + 1);
39859                         con->response.content_length += end - start + 1;
39860                 }
39861         }
39862 -       
39863 +
39864         /* something went wrong */
39865         if (error) return -1;
39866 -       
39867 +
39868         if (multipart) {
39869                 /* add boundary end */
39870                 buffer *b;
39871 -               
39872 +
39873                 b = chunkqueue_get_append_buffer(con->write_queue);
39874 -               
39875 +
39876                 buffer_copy_string_len(b, "\r\n--", 4);
39877                 buffer_append_string(b, boundary);
39878                 buffer_append_string_len(b, "--\r\n", 4);
39879 -               
39880 +
39881                 con->response.content_length += b->used - 1;
39882 -               
39883 +
39884                 /* set header-fields */
39885 -               
39886 +
39887                 buffer_copy_string(p->range_buf, "multipart/byteranges; boundary=");
39888                 buffer_append_string(p->range_buf, boundary);
39889 -               
39890 +
39891                 /* overwrite content-type */
39892                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->range_buf));
39893         } else {
39894                 /* add Content-Range-header */
39895 -               
39896 +
39897                 buffer_copy_string(p->range_buf, "bytes ");
39898                 buffer_append_off_t(p->range_buf, start);
39899                 buffer_append_string(p->range_buf, "-");
39900                 buffer_append_off_t(p->range_buf, end);
39901                 buffer_append_string(p->range_buf, "/");
39902                 buffer_append_off_t(p->range_buf, sce->st.st_size);
39903 -               
39904 +
39905                 response_header_insert(srv, con, CONST_STR_LEN("Content-Range"), CONST_BUF_LEN(p->range_buf));
39906         }
39907  
39908 @@ -347,12 +346,12 @@
39909         stat_cache_entry *sce = NULL;
39910         buffer *mtime;
39911         data_string *ds;
39912 -       
39913 +
39914         /* someone else has done a decision for us */
39915         if (con->http_status != 0) return HANDLER_GO_ON;
39916         if (con->uri.path->used == 0) return HANDLER_GO_ON;
39917         if (con->physical.path->used == 0) return HANDLER_GO_ON;
39918 -       
39919 +
39920         /* someone else has handled this request */
39921         if (con->mode != DIRECT) return HANDLER_GO_ON;
39922  
39923 @@ -365,52 +364,52 @@
39924         default:
39925                 return HANDLER_GO_ON;
39926         }
39927 -       
39928 +
39929         mod_staticfile_patch_connection(srv, con, p);
39930 -       
39931 +
39932         s_len = con->uri.path->used - 1;
39933 -       
39934 +
39935         /* ignore certain extensions */
39936         for (k = 0; k < p->conf.exclude_ext->used; k++) {
39937 -               ds = (data_string *)p->conf.exclude_ext->data[k]; 
39938 -               
39939 +               ds = (data_string *)p->conf.exclude_ext->data[k];
39940 +
39941                 if (ds->value->used == 0) continue;
39942  
39943                 if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
39944                         return HANDLER_GO_ON;
39945                 }
39946         }
39947 -       
39948 +
39949  
39950         if (con->conf.log_request_handling) {
39951                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling file as static file");
39952         }
39953 -       
39954 +
39955         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
39956                 con->http_status = 403;
39957 -               
39958 +
39959                 log_error_write(srv, __FILE__, __LINE__, "sbsb",
39960                                 "not a regular file:", con->uri.path,
39961                                 "->", con->physical.path);
39962 -               
39963 +
39964                 return HANDLER_FINISHED;
39965         }
39966 -       
39967 -       /* we only handline regular files */
39968 +
39969 +       /* we only handle regular files */
39970         if (!S_ISREG(sce->st.st_mode)) {
39971                 con->http_status = 404;
39972 -               
39973 +
39974                 if (con->conf.log_file_not_found) {
39975                         log_error_write(srv, __FILE__, __LINE__, "sbsb",
39976                                         "not a regular file:", con->uri.path,
39977                                         "->", sce->name);
39978                 }
39979 -               
39980 +
39981                 return HANDLER_FINISHED;
39982         }
39983  
39984 -       /* mod_compress might set several data directly, don't overwrite them */
39985 -       
39986 +       /* mod_compress might set several parameters directly; don't overwrite them */
39987 +
39988         /* set response content-type, if not set already */
39989  
39990         if (NULL == array_get_element(con->response.headers, "Content-Type")) {
39991 @@ -420,15 +419,15 @@
39992                         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
39993                 }
39994         }
39995 -       
39996 +
39997         if (NULL == array_get_element(con->response.headers, "ETag")) {
39998                 /* generate e-tag */
39999                 etag_mutate(con->physical.etag, sce->etag);
40000 -       
40001 +
40002                 response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
40003         }
40004         response_header_overwrite(srv, con, CONST_STR_LEN("Accept-Ranges"), CONST_STR_LEN("bytes"));
40005 -       
40006 +
40007         /* prepare header */
40008         if (NULL == (ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"))) {
40009                 mtime = strftime_cache_get(srv, sce->st.st_mtime);
40010 @@ -444,34 +443,34 @@
40011                 /* check if we have a conditional GET */
40012  
40013                 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If-Range"))) {
40014 -                       /* if the value is the same as our ETag, we do a Range-request, 
40015 +                       /* if the value is the same as our ETag, we do a Range-request,
40016                          * otherwise a full 200 */
40017  
40018                         if (!buffer_is_equal(ds->value, con->physical.etag)) {
40019                                 do_range_request = 0;
40020                         }
40021                 }
40022 -       
40023 +
40024                 if (do_range_request) {
40025                         /* content prepared, I'm done */
40026                         con->file_finished = 1;
40027 -               
40028 +
40029                         if (0 == http_response_parse_range(srv, con, p)) {
40030                                 con->http_status = 206;
40031                         }
40032                         return HANDLER_FINISHED;
40033                 }
40034         }
40035 -       
40036 +
40037         /* if we are still here, prepare body */
40038 -       
40039 -       /* we add it here for all requests 
40040 -        * the HEAD request will drop it afterwards again 
40041 +
40042 +       /* we add it here for all requests
40043 +        * the HEAD request will drop it afterwards again
40044          */
40045         http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
40046 -       
40047 +
40048         con->file_finished = 1;
40049 -       
40050 +
40051         return HANDLER_FINISHED;
40052  }
40053  
40054 @@ -480,13 +479,13 @@
40055  int mod_staticfile_plugin_init(plugin *p) {
40056         p->version     = LIGHTTPD_VERSION_ID;
40057         p->name        = buffer_init_string("staticfile");
40058 -       
40059 +
40060         p->init        = mod_staticfile_init;
40061         p->handle_subrequest_start = mod_staticfile_subrequest;
40062         p->set_defaults  = mod_staticfile_set_defaults;
40063         p->cleanup     = mod_staticfile_free;
40064 -       
40065 +
40066         p->data        = NULL;
40067 -       
40068 +
40069         return 0;
40070  }
40071 --- ../lighttpd-1.4.11/src/mod_status.c 2006-01-10 21:45:32.000000000 +0200
40072 +++ lighttpd-1.4.12/src/mod_status.c    2006-07-16 00:26:04.000000000 +0300
40073 @@ -4,7 +4,6 @@
40074  #include <fcntl.h>
40075  #include <stdlib.h>
40076  #include <string.h>
40077 -#include <unistd.h>
40078  #include <errno.h>
40079  #include <time.h>
40080  #include <stdio.h>
40081 @@ -29,114 +28,114 @@
40082  
40083  typedef struct {
40084         PLUGIN_DATA;
40085 -       
40086 +
40087         double traffic_out;
40088         double requests;
40089 -       
40090 +
40091         double mod_5s_traffic_out[5];
40092         double mod_5s_requests[5];
40093         size_t mod_5s_ndx;
40094 -       
40095 +
40096         double rel_traffic_out;
40097         double rel_requests;
40098 -       
40099 +
40100         double abs_traffic_out;
40101         double abs_requests;
40102 -       
40103 +
40104         double bytes_written;
40105 -       
40106 +
40107         buffer *module_list;
40108 -       
40109 +
40110         plugin_config **config_storage;
40111 -       
40112 -       plugin_config conf; 
40113 +
40114 +       plugin_config conf;
40115  } plugin_data;
40116  
40117  INIT_FUNC(mod_status_init) {
40118         plugin_data *p;
40119         size_t i;
40120 -       
40121 +
40122         p = calloc(1, sizeof(*p));
40123 -       
40124 +
40125         p->traffic_out = p->requests = 0;
40126         p->rel_traffic_out = p->rel_requests = 0;
40127         p->abs_traffic_out = p->abs_requests = 0;
40128         p->bytes_written = 0;
40129         p->module_list = buffer_init();
40130 -       
40131 +
40132         for (i = 0; i < 5; i++) {
40133                 p->mod_5s_traffic_out[i] = p->mod_5s_requests[i] = 0;
40134         }
40135 -       
40136 +
40137         return p;
40138  }
40139  
40140  FREE_FUNC(mod_status_free) {
40141         plugin_data *p = p_d;
40142 -       
40143 +
40144         UNUSED(srv);
40145  
40146         if (!p) return HANDLER_GO_ON;
40147 -       
40148 +
40149         buffer_free(p->module_list);
40150 -       
40151 +
40152         if (p->config_storage) {
40153                 size_t i;
40154                 for (i = 0; i < srv->config_context->used; i++) {
40155                         plugin_config *s = p->config_storage[i];
40156 -                       
40157 +
40158                         buffer_free(s->status_url);
40159                         buffer_free(s->statistics_url);
40160                         buffer_free(s->config_url);
40161 -                       
40162 +
40163                         free(s);
40164                 }
40165                 free(p->config_storage);
40166         }
40167 -       
40168 -       
40169 +
40170 +
40171         free(p);
40172 -       
40173 +
40174         return HANDLER_GO_ON;
40175  }
40176  
40177  SETDEFAULTS_FUNC(mod_status_set_defaults) {
40178         plugin_data *p = p_d;
40179         size_t i;
40180 -       
40181 -       config_values_t cv[] = { 
40182 +
40183 +       config_values_t cv[] = {
40184                 { "status.status-url",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
40185                 { "status.config-url",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
40186                 { "status.enable-sort",          NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
40187                 { "status.statistics-url",       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
40188                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
40189         };
40190 -       
40191 +
40192         if (!p) return HANDLER_ERROR;
40193 -       
40194 +
40195         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
40196 -       
40197 +
40198         for (i = 0; i < srv->config_context->used; i++) {
40199                 plugin_config *s;
40200 -               
40201 +
40202                 s = calloc(1, sizeof(plugin_config));
40203                 s->config_url    = buffer_init();
40204                 s->status_url    = buffer_init();
40205                 s->sort          = 1;
40206                 s->statistics_url    = buffer_init();
40207 -               
40208 +
40209                 cv[0].destination = s->status_url;
40210                 cv[1].destination = s->config_url;
40211                 cv[2].destination = &(s->sort);
40212                 cv[3].destination = s->statistics_url;
40213 -               
40214 +
40215                 p->config_storage[i] = s;
40216 -       
40217 +
40218                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
40219                         return HANDLER_ERROR;
40220                 }
40221         }
40222 -       
40223 +
40224         return HANDLER_GO_ON;
40225  }
40226  
40227 @@ -151,7 +150,7 @@
40228         buffer_append_string(b, value);
40229         BUFFER_APPEND_STRING_CONST(b, "</td>\n");
40230         BUFFER_APPEND_STRING_CONST(b, "   </tr>\n");
40231 -       
40232 +
40233         return 0;
40234  }
40235  
40236 @@ -161,13 +160,13 @@
40237         buffer_append_string(b, key);
40238         BUFFER_APPEND_STRING_CONST(b, "</th>\n");
40239         BUFFER_APPEND_STRING_CONST(b, "   </tr>\n");
40240 -       
40241 +
40242         return 0;
40243  }
40244  
40245  static int mod_status_header_append_sort(buffer *b, void *p_d, const char* key) {
40246         plugin_data *p = p_d;
40247 -       
40248 +
40249         if (p->conf.sort) {
40250                 BUFFER_APPEND_STRING_CONST(b, "<th class=\"status\"><a href=\"#\" class=\"sortheader\" onclick=\"resort(this);return false;\">");
40251                 buffer_append_string(b, key);
40252 @@ -177,13 +176,13 @@
40253                 buffer_append_string(b, key);
40254                 BUFFER_APPEND_STRING_CONST(b, "</th>\n");
40255         }
40256 -       
40257 +
40258         return 0;
40259  }
40260  
40261  static int mod_status_get_multiplier(double *avg, char *multiplier, int size) {
40262         *multiplier = ' ';
40263 -       
40264 +
40265         if (*avg > size) { *avg /= size; *multiplier = 'k'; }
40266         if (*avg > size) { *avg /= size; *multiplier = 'M'; }
40267         if (*avg > size) { *avg /= size; *multiplier = 'G'; }
40268 @@ -202,21 +201,21 @@
40269         size_t j;
40270         double avg;
40271         char multiplier = '\0';
40272 -       char buf[32];
40273 +       char buf[128];
40274         time_t ts;
40275 -       
40276 +
40277         int days, hours, mins, seconds;
40278 -       
40279 +
40280         b = chunkqueue_get_append_buffer(con->write_queue);
40281  
40282 -       BUFFER_COPY_STRING_CONST(b, 
40283 +       BUFFER_COPY_STRING_CONST(b,
40284                                  "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
40285                                  "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
40286                                  "         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
40287                                  "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
40288                                  " <head>\n"
40289                                  "  <title>Status</title>\n");
40290 -       
40291 +
40292         BUFFER_APPEND_STRING_CONST(b,
40293                                    "  <style type=\"text/css\">\n"
40294                                    "    table.status { border: black solid thin; }\n"
40295 @@ -226,14 +225,14 @@
40296                                    "    a.sortheader { background-color: black; color: white; font-weight: bold; text-decoration: none; display: block; }\n"
40297                                    "    span.sortarrow { color: white; text-decoration: none; }\n"
40298                                    "  </style>\n");
40299 -       
40300 +
40301         if (p->conf.sort) {
40302                 BUFFER_APPEND_STRING_CONST(b,
40303                                            "<script type=\"text/javascript\">\n"
40304                                            "// <!--\n"
40305                                            "var sort_column;\n"
40306                                            "var prev_span = null;\n");
40307 -               
40308 +
40309                 BUFFER_APPEND_STRING_CONST(b,
40310                                            "function get_inner_text(el) {\n"
40311                                            " if((typeof el == 'string')||(typeof el == 'undefined'))\n"
40312 @@ -251,7 +250,7 @@
40313                                            " }\n"
40314                                            " return str;\n"
40315                                            "}\n");
40316 -               
40317 +
40318                 BUFFER_APPEND_STRING_CONST(b,
40319                                            "function sortfn(a,b) {\n"
40320                                            " var at = get_inner_text(a.cells[sort_column]);\n"
40321 @@ -266,7 +265,7 @@
40322                                            "  else return 1;\n"
40323                                            " }\n"
40324                                            "}\n");
40325 -               
40326 +
40327                 BUFFER_APPEND_STRING_CONST(b,
40328                                            "function resort(lnk) {\n"
40329                                            " var span = lnk.childNodes[1];\n"
40330 @@ -276,7 +275,7 @@
40331                                            "  rows[j-1] = table.rows[j];\n"
40332                                            " sort_column = lnk.parentNode.cellIndex;\n"
40333                                            " rows.sort(sortfn);\n");
40334 -               
40335 +
40336                 BUFFER_APPEND_STRING_CONST(b,
40337                                            " if (prev_span != null) prev_span.innerHTML = '';\n"
40338                                            " if (span.getAttribute('sortdir')=='down') {\n"
40339 @@ -294,175 +293,175 @@
40340                                            "// -->\n"
40341                                            "</script>\n");
40342         }
40343 -       
40344 -       BUFFER_APPEND_STRING_CONST(b, 
40345 +
40346 +       BUFFER_APPEND_STRING_CONST(b,
40347                                  " </head>\n"
40348                                  " <body>\n");
40349 -       
40350 -       
40351 -       
40352 +
40353 +
40354 +
40355         /* connection listing */
40356         BUFFER_APPEND_STRING_CONST(b, "<h1>Server-Status</h1>");
40357 -       
40358 -       BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\">");
40359 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Hostname</td><td class=\"string\">");
40360 +
40361 +       BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\" id=\"status\" summary=\"Server Status\">");
40362 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Hostname</td><td class=\"string\"><span id=\"host_addr\">");
40363         buffer_append_string_buffer(b, con->uri.authority);
40364 -       BUFFER_APPEND_STRING_CONST(b, " (");
40365 +       BUFFER_APPEND_STRING_CONST(b, "</span> (<span id=\"host_name\">");
40366         buffer_append_string_buffer(b, con->server_name);
40367 -       BUFFER_APPEND_STRING_CONST(b, ")</td></tr>\n");
40368 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Uptime</td><td class=\"string\">");
40369 -       
40370 +       BUFFER_APPEND_STRING_CONST(b, "</span>)</td></tr>\n");
40371 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Uptime</td><td class=\"string\" id=\"uptime\">");
40372 +
40373         ts = srv->cur_ts - srv->startup_ts;
40374 -       
40375 +
40376         days = ts / (60 * 60 * 24);
40377         ts %= (60 * 60 * 24);
40378 -       
40379 +
40380         hours = ts / (60 * 60);
40381         ts %= (60 * 60);
40382 -       
40383 +
40384         mins = ts / (60);
40385         ts %= (60);
40386 -       
40387 +
40388         seconds = ts;
40389 -       
40390 +
40391         if (days) {
40392                 buffer_append_long(b, days);
40393                 BUFFER_APPEND_STRING_CONST(b, " days ");
40394         }
40395 -       
40396 +
40397         if (hours) {
40398                 buffer_append_long(b, hours);
40399                 BUFFER_APPEND_STRING_CONST(b, " hours ");
40400         }
40401 -       
40402 +
40403         if (mins) {
40404                 buffer_append_long(b, mins);
40405                 BUFFER_APPEND_STRING_CONST(b, " min ");
40406         }
40407 -       
40408 +
40409         buffer_append_long(b, seconds);
40410         BUFFER_APPEND_STRING_CONST(b, " s");
40411 -       
40412 +
40413         BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
40414         BUFFER_APPEND_STRING_CONST(b, "<tr><td>Started at</td><td class=\"string\">");
40415 -       
40416 +
40417         ts = srv->startup_ts;
40418 -       
40419 -       strftime(buf, sizeof(buf) - 1, "%Y-%m-%d %H:%M:%S", localtime(&ts));
40420 +
40421 +       strftime(buf, sizeof(buf) - 1, "<span id=\"start_date\">%Y-%m-%d</span> <span id=\"start_time\">%H:%M:%S</span>", localtime(&ts));
40422         buffer_append_string(b, buf);
40423         BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
40424 -       
40425 -       
40426 +
40427 +
40428         BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">absolute (since start)</th></tr>\n");
40429 -       
40430 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
40431 +
40432 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\" ><span id=\"requests\">");
40433         avg = p->abs_requests;
40434  
40435         mod_status_get_multiplier(&avg, &multiplier, 1000);
40436 -       
40437 +
40438         buffer_append_long(b, avg);
40439 -       BUFFER_APPEND_STRING_CONST(b, " ");
40440 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_mult\">");
40441         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40442 -       BUFFER_APPEND_STRING_CONST(b, "req</td></tr>\n");
40443 -       
40444 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
40445 +       BUFFER_APPEND_STRING_CONST(b, "</span>req</td></tr>\n");
40446 +
40447 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"traffic\">");
40448         avg = p->abs_traffic_out;
40449  
40450         mod_status_get_multiplier(&avg, &multiplier, 1024);
40451  
40452         sprintf(buf, "%.2f", avg);
40453         buffer_append_string(b, buf);
40454 -       BUFFER_APPEND_STRING_CONST(b, " ");
40455 +       BUFFER_APPEND_STRING_CONST(b, "</span>  <span id=\"traffic_mult\">");
40456         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40457 -       BUFFER_APPEND_STRING_CONST(b, "byte</td></tr>\n");
40458 +       BUFFER_APPEND_STRING_CONST(b, "</span>byte</td></tr>\n");
40459  
40460  
40461  
40462         BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (since start)</th></tr>\n");
40463 -       
40464 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
40465 +
40466 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\"><span id=\"requests_avg\">");
40467         avg = p->abs_requests / (srv->cur_ts - srv->startup_ts);
40468  
40469         mod_status_get_multiplier(&avg, &multiplier, 1000);
40470  
40471         buffer_append_long(b, avg);
40472 -       BUFFER_APPEND_STRING_CONST(b, " ");
40473 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_avg_mult\">");
40474         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40475 -       BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n");
40476 -       
40477 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
40478 +       BUFFER_APPEND_STRING_CONST(b, "</span>req/s</td></tr>\n");
40479 +
40480 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"traffic_avg\">");
40481         avg = p->abs_traffic_out / (srv->cur_ts - srv->startup_ts);
40482  
40483         mod_status_get_multiplier(&avg, &multiplier, 1024);
40484  
40485         sprintf(buf, "%.2f", avg);
40486         buffer_append_string(b, buf);
40487 -       BUFFER_APPEND_STRING_CONST(b, " ");
40488 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"traffic_avg_mult\">");
40489         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40490 -       BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n");
40491 +       BUFFER_APPEND_STRING_CONST(b, "</span>byte/s</td></tr>\n");
40492 +
40493 +
40494  
40495 -       
40496 -       
40497         BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (5s sliding average)</th></tr>\n");
40498         for (j = 0, avg = 0; j < 5; j++) {
40499                 avg += p->mod_5s_requests[j];
40500         }
40501 -       
40502 +
40503         avg /= 5;
40504 -       
40505 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
40506 +
40507 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\"><span id=\"requests_sliding_avg\">");
40508  
40509         mod_status_get_multiplier(&avg, &multiplier, 1000);
40510  
40511         buffer_append_long(b, avg);
40512 -       BUFFER_APPEND_STRING_CONST(b, " ");
40513 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_sliding_avg_mult\">");
40514         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40515 -       
40516 -       BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n");
40517 -       
40518 +
40519 +       BUFFER_APPEND_STRING_CONST(b, "</span>req/s</td></tr>\n");
40520 +
40521         for (j = 0, avg = 0; j < 5; j++) {
40522                 avg += p->mod_5s_traffic_out[j];
40523         }
40524 -       
40525 +
40526         avg /= 5;
40527 -       
40528 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
40529 +
40530 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"requests_sliding_traffic\">");
40531  
40532         mod_status_get_multiplier(&avg, &multiplier, 1024);
40533  
40534         sprintf(buf, "%.2f", avg);
40535         buffer_append_string(b, buf);
40536 -       BUFFER_APPEND_STRING_CONST(b, " ");
40537 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_sliding_traffic_mult\">");
40538         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40539 -       BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n");
40540 -       
40541 +       BUFFER_APPEND_STRING_CONST(b, "</span>byte/s</td></tr>\n");
40542 +
40543         BUFFER_APPEND_STRING_CONST(b, "</table>\n");
40544 -       
40545 -       
40546 +
40547 +
40548         BUFFER_APPEND_STRING_CONST(b, "<hr />\n<pre><b>legend</b>\n");
40549         BUFFER_APPEND_STRING_CONST(b, ". = connect, C = close, E = hard error\n");
40550         BUFFER_APPEND_STRING_CONST(b, "r = read, R = read-POST, W = write, h = handle-request\n");
40551         BUFFER_APPEND_STRING_CONST(b, "q = request-start,  Q = request-end\n");
40552         BUFFER_APPEND_STRING_CONST(b, "s = response-start, S = response-end\n");
40553 -       
40554 -       BUFFER_APPEND_STRING_CONST(b, "<b>");
40555 +
40556 +       BUFFER_APPEND_STRING_CONST(b, "<strong><span id=\"connections\">");
40557         buffer_append_long(b, srv->conns->used);
40558 -       BUFFER_APPEND_STRING_CONST(b, " connections</b>\n");
40559 -       
40560 +       BUFFER_APPEND_STRING_CONST(b, "</span> connections</strong>\n");
40561 +
40562         for (j = 0; j < srv->conns->used; j++) {
40563                 connection *c = srv->conns->ptr[j];
40564                 const char *state = connection_get_short_state(c->state);
40565 -               
40566 +
40567                 buffer_append_string_len(b, state, 1);
40568 -               
40569 +
40570                 if (((j + 1) % 50) == 0) {
40571                         BUFFER_APPEND_STRING_CONST(b, "\n");
40572                 }
40573         }
40574 -       
40575 +
40576         BUFFER_APPEND_STRING_CONST(b, "\n</pre><hr />\n<h2>Connections</h2>\n");
40577 -       
40578 -       BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\">\n");
40579 +
40580 +       BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\" summary=\"Current connections\" id=\"clients\">\n");
40581         BUFFER_APPEND_STRING_CONST(b, "<tr>");
40582         mod_status_header_append_sort(b, p_d, "Client IP");
40583         mod_status_header_append_sort(b, p_d, "Read");
40584 @@ -473,16 +472,16 @@
40585         mod_status_header_append_sort(b, p_d, "URI");
40586         mod_status_header_append_sort(b, p_d, "File");
40587         BUFFER_APPEND_STRING_CONST(b, "</tr>\n");
40588 -       
40589 +
40590         for (j = 0; j < srv->conns->used; j++) {
40591                 connection *c = srv->conns->ptr[j];
40592 -               
40593 -               BUFFER_APPEND_STRING_CONST(b, "<tr><td class=\"string\">");
40594 -               
40595 +
40596 +               BUFFER_APPEND_STRING_CONST(b, "<tr><td class=\"string ip\">");
40597 +
40598                 buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(c->dst_addr)));
40599 -               
40600 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
40601 -               
40602 +
40603 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int bytes_read\">");
40604 +
40605                 if (con->request.content_length) {
40606                         buffer_append_long(b, c->request_content_queue->bytes_in);
40607                         BUFFER_APPEND_STRING_CONST(b, "/");
40608 @@ -490,55 +489,55 @@
40609                 } else {
40610                         BUFFER_APPEND_STRING_CONST(b, "0/0");
40611                 }
40612 -       
40613 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
40614 -               
40615 +
40616 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int bytes_written\">");
40617 +
40618                 buffer_append_off_t(b, chunkqueue_written(c->write_queue));
40619                 BUFFER_APPEND_STRING_CONST(b, "/");
40620                 buffer_append_off_t(b, chunkqueue_length(c->write_queue));
40621 -               
40622 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40623 -               
40624 +
40625 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string state\">");
40626 +
40627                 buffer_append_string(b, connection_get_state(c->state));
40628 -               
40629 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
40630 -               
40631 +
40632 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int time\">");
40633 +
40634                 buffer_append_long(b, srv->cur_ts - c->request_start);
40635 -               
40636 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40637 -               
40638 +
40639 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string host\">");
40640 +
40641                 if (buffer_is_empty(c->server_name)) {
40642                         buffer_append_string_buffer(b, c->uri.authority);
40643                 }
40644                 else {
40645                         buffer_append_string_buffer(b, c->server_name);
40646                 }
40647 -               
40648 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40649 -               
40650 +
40651 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string uri\">");
40652 +
40653                 if (!buffer_is_empty(c->uri.path)) {
40654                         buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.path), ENCODING_HTML);
40655                 }
40656 -               
40657 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40658 -               
40659 +
40660 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string file\">");
40661 +
40662                 buffer_append_string_buffer(b, c->physical.path);
40663 -               
40664 +
40665                 BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
40666         }
40667 -       
40668 -       
40669 -       BUFFER_APPEND_STRING_CONST(b, 
40670 +
40671 +
40672 +       BUFFER_APPEND_STRING_CONST(b,
40673                       "</table>\n");
40674 -       
40675 -       
40676 -       BUFFER_APPEND_STRING_CONST(b, 
40677 +
40678 +
40679 +       BUFFER_APPEND_STRING_CONST(b,
40680                       " </body>\n"
40681                       "</html>\n"
40682                       );
40683 -       
40684 +
40685         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
40686 -       
40687 +
40688         return 0;
40689  }
40690  
40691 @@ -548,7 +547,7 @@
40692         buffer *b;
40693         double avg;
40694         time_t ts;
40695 -       
40696 +
40697         b = chunkqueue_get_append_buffer(con->write_queue);
40698  
40699         /* output total number of requests */
40700 @@ -556,19 +555,19 @@
40701         avg = p->abs_requests;
40702         buffer_append_long(b, avg);
40703         BUFFER_APPEND_STRING_CONST(b, "\n");
40704 -       
40705 +
40706         /* output total traffic out in kbytes */
40707         BUFFER_APPEND_STRING_CONST(b, "Total kBytes: ");
40708         avg = p->abs_traffic_out / 1024;
40709         buffer_append_long(b, avg);
40710         BUFFER_APPEND_STRING_CONST(b, "\n");
40711 -       
40712 +
40713         /* output uptime */
40714         BUFFER_APPEND_STRING_CONST(b, "Uptime: ");
40715         ts = srv->cur_ts - srv->startup_ts;
40716         buffer_append_long(b, ts);
40717         BUFFER_APPEND_STRING_CONST(b, "\n");
40718 -       
40719 +
40720         /* output busy servers */
40721         BUFFER_APPEND_STRING_CONST(b, "BusyServers: ");
40722         buffer_append_long(b, srv->conns->used);
40723 @@ -577,7 +576,7 @@
40724         /* set text/plain output */
40725  
40726         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
40727 -       
40728 +
40729         return 0;
40730  }
40731  
40732 @@ -591,10 +590,10 @@
40733                 /* we have nothing to send */
40734                 con->http_status = 204;
40735                 con->file_finished = 1;
40736 -       
40737 +
40738                 return HANDLER_FINISHED;
40739         }
40740 -       
40741 +
40742         b = chunkqueue_get_append_buffer(con->write_queue);
40743  
40744         for (i = 0; i < st->used; i++) {
40745 @@ -605,27 +604,27 @@
40746                 buffer_append_long(b, ((data_integer *)(st->data[ndx]))->value);
40747                 buffer_append_string(b, "\n");
40748         }
40749 -       
40750 +
40751         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
40752 -       
40753 +
40754         con->http_status = 200;
40755         con->file_finished = 1;
40756 -       
40757 +
40758         return HANDLER_FINISHED;
40759  }
40760  
40761  
40762  static handler_t mod_status_handle_server_status(server *srv, connection *con, void *p_d) {
40763 -       
40764 +
40765         if (buffer_is_equal_string(con->uri.query, CONST_STR_LEN("auto"))) {
40766                 mod_status_handle_server_status_text(srv, con, p_d);
40767         } else {
40768                 mod_status_handle_server_status_html(srv, con, p_d);
40769         }
40770 -       
40771 +
40772         con->http_status = 200;
40773         con->file_finished = 1;
40774 -       
40775 +
40776         return HANDLER_FINISHED;
40777  }
40778  
40779 @@ -634,9 +633,9 @@
40780         plugin_data *p = p_d;
40781         buffer *b, *m = p->module_list;
40782         size_t i;
40783 -       
40784 -       struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] = 
40785 -       { 
40786 +
40787 +       struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
40788 +       {
40789                 /* - poll is most reliable
40790                  * - select works everywhere
40791                  * - linux-* are experimental
40792 @@ -661,10 +660,10 @@
40793  #endif
40794                 { FDEVENT_HANDLER_UNSET,          NULL }
40795         };
40796 -       
40797 +
40798         b = chunkqueue_get_append_buffer(con->write_queue);
40799 -       
40800 -       BUFFER_COPY_STRING_CONST(b, 
40801 +
40802 +       BUFFER_COPY_STRING_CONST(b,
40803                            "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
40804                            "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
40805                            "         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
40806 @@ -675,7 +674,7 @@
40807                            " <body>\n"
40808                            "  <h1>" PACKAGE_NAME " " PACKAGE_VERSION "</h1>\n"
40809                            "  <table border=\"1\">\n");
40810 -       
40811 +
40812         mod_status_header_append(b, "Server-Features");
40813  #ifdef HAVE_PCRE_H
40814         mod_status_row_append(b, "RegEx Conditionals", "enabled");
40815 @@ -683,21 +682,21 @@
40816         mod_status_row_append(b, "RegEx Conditionals", "disabled - pcre missing");
40817  #endif
40818         mod_status_header_append(b, "Network Engine");
40819 -       
40820 +
40821         for (i = 0; event_handlers[i].name; i++) {
40822                 if (event_handlers[i].et == srv->event_handler) {
40823                         mod_status_row_append(b, "fd-Event-Handler", event_handlers[i].name);
40824                         break;
40825                 }
40826         }
40827 -       
40828 +
40829         mod_status_header_append(b, "Config-File-Settings");
40830 -       
40831 +
40832         for (i = 0; i < srv->plugins.used; i++) {
40833                 plugin **ps = srv->plugins.ptr;
40834 -               
40835 +
40836                 plugin *pl = ps[i];
40837 -       
40838 +
40839                 if (i == 0) {
40840                         buffer_copy_string_buffer(m, pl->name);
40841                 } else {
40842 @@ -705,137 +704,135 @@
40843                         buffer_append_string_buffer(m, pl->name);
40844                 }
40845         }
40846 -       
40847 +
40848         mod_status_row_append(b, "Loaded Modules", m->ptr);
40849 -       
40850 +
40851         BUFFER_APPEND_STRING_CONST(b, "  </table>\n");
40852 -       
40853 -       BUFFER_APPEND_STRING_CONST(b, 
40854 +
40855 +       BUFFER_APPEND_STRING_CONST(b,
40856                       " </body>\n"
40857                       "</html>\n"
40858                       );
40859 -       
40860 +
40861         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
40862 -       
40863 +
40864         con->http_status = 200;
40865         con->file_finished = 1;
40866 -       
40867 +
40868         return HANDLER_FINISHED;
40869  }
40870  
40871 -#define PATCH(x) \
40872 -       p->conf.x = s->x;
40873  static int mod_status_patch_connection(server *srv, connection *con, plugin_data *p) {
40874         size_t i, j;
40875         plugin_config *s = p->config_storage[0];
40876 -       
40877 -       PATCH(status_url);
40878 -       PATCH(config_url);
40879 -       PATCH(sort);
40880 -       PATCH(statistics_url);
40881 -       
40882 +
40883 +       PATCH_OPTION(status_url);
40884 +       PATCH_OPTION(config_url);
40885 +       PATCH_OPTION(sort);
40886 +       PATCH_OPTION(statistics_url);
40887 +
40888         /* skip the first, the global context */
40889         for (i = 1; i < srv->config_context->used; i++) {
40890                 data_config *dc = (data_config *)srv->config_context->data[i];
40891                 s = p->config_storage[i];
40892 -               
40893 +
40894                 /* condition didn't match */
40895                 if (!config_check_cond(srv, con, dc)) continue;
40896 -               
40897 +
40898                 /* merge config */
40899                 for (j = 0; j < dc->value->used; j++) {
40900                         data_unset *du = dc->value->data[j];
40901 -                       
40902 +
40903                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.status-url"))) {
40904 -                               PATCH(status_url);
40905 +                               PATCH_OPTION(status_url);
40906                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.config-url"))) {
40907 -                               PATCH(config_url);
40908 +                               PATCH_OPTION(config_url);
40909                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.enable-sort"))) {
40910 -                               PATCH(sort);
40911 +                               PATCH_OPTION(sort);
40912                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.statistics-url"))) {
40913 -                               PATCH(statistics_url);
40914 -                       } 
40915 +                               PATCH_OPTION(statistics_url);
40916 +                       }
40917                 }
40918         }
40919 -       
40920 +
40921         return 0;
40922  }
40923  
40924  static handler_t mod_status_handler(server *srv, connection *con, void *p_d) {
40925         plugin_data *p = p_d;
40926 -       
40927 +
40928         mod_status_patch_connection(srv, con, p);
40929 -       
40930 -       if (!buffer_is_empty(p->conf.status_url) && 
40931 +
40932 +       if (!buffer_is_empty(p->conf.status_url) &&
40933             buffer_is_equal(p->conf.status_url, con->uri.path)) {
40934                 return mod_status_handle_server_status(srv, con, p_d);
40935 -       } else if (!buffer_is_empty(p->conf.config_url) && 
40936 +       } else if (!buffer_is_empty(p->conf.config_url) &&
40937             buffer_is_equal(p->conf.config_url, con->uri.path)) {
40938                 return mod_status_handle_server_config(srv, con, p_d);
40939 -       } else if (!buffer_is_empty(p->conf.statistics_url) && 
40940 +       } else if (!buffer_is_empty(p->conf.statistics_url) &&
40941             buffer_is_equal(p->conf.statistics_url, con->uri.path)) {
40942                 return mod_status_handle_server_statistics(srv, con, p_d);
40943         }
40944 -       
40945 +
40946         return HANDLER_GO_ON;
40947  }
40948  
40949  TRIGGER_FUNC(mod_status_trigger) {
40950         plugin_data *p = p_d;
40951         size_t i;
40952 -       
40953 +
40954         /* check all connections */
40955         for (i = 0; i < srv->conns->used; i++) {
40956                 connection *c = srv->conns->ptr[i];
40957 -               
40958 +
40959                 p->bytes_written += c->bytes_written_cur_second;
40960         }
40961 -       
40962 +
40963         /* a sliding average */
40964         p->mod_5s_traffic_out[p->mod_5s_ndx] = p->bytes_written;
40965         p->mod_5s_requests   [p->mod_5s_ndx] = p->requests;
40966 -       
40967 +
40968         p->mod_5s_ndx = (p->mod_5s_ndx+1) % 5;
40969 -       
40970 +
40971         p->abs_traffic_out += p->bytes_written;
40972         p->rel_traffic_out += p->bytes_written;
40973 -       
40974 +
40975         p->bytes_written = 0;
40976 -       
40977 +
40978         /* reset storage - second */
40979         p->traffic_out = 0;
40980         p->requests    = 0;
40981 -       
40982 +
40983         return HANDLER_GO_ON;
40984  }
40985  
40986  REQUESTDONE_FUNC(mod_status_account) {
40987         plugin_data *p = p_d;
40988 -       
40989 +
40990         UNUSED(srv);
40991  
40992         p->requests++;
40993         p->rel_requests++;
40994         p->abs_requests++;
40995 -       
40996 +
40997         p->bytes_written += con->bytes_written_cur_second;
40998 -       
40999 +
41000         return HANDLER_GO_ON;
41001  }
41002  
41003  int mod_status_plugin_init(plugin *p) {
41004         p->version     = LIGHTTPD_VERSION_ID;
41005         p->name        = buffer_init_string("status");
41006 -       
41007 +
41008         p->init        = mod_status_init;
41009         p->cleanup     = mod_status_free;
41010         p->set_defaults= mod_status_set_defaults;
41011 -       
41012 +
41013         p->handle_uri_clean    = mod_status_handler;
41014         p->handle_trigger      = mod_status_trigger;
41015         p->handle_request_done = mod_status_account;
41016 -       
41017 +
41018         p->data        = NULL;
41019 -       
41020 +
41021         return 0;
41022  }
41023 --- ../lighttpd-1.4.11/src/mod_trigger_b4_dl.c  2005-09-23 22:53:55.000000000 +0300
41024 +++ lighttpd-1.4.12/src/mod_trigger_b4_dl.c     2006-07-16 00:26:03.000000000 +0300
41025 @@ -24,18 +24,18 @@
41026  
41027  /**
41028   * this is a trigger_b4_dl for a lighttpd plugin
41029 - * 
41030 + *
41031   */
41032  
41033  /* plugin config for all request/connections */
41034  
41035  typedef struct {
41036         buffer *db_filename;
41037 -       
41038 +
41039         buffer *trigger_url;
41040         buffer *download_url;
41041         buffer *deny_url;
41042 -       
41043 +
41044         array  *mc_hosts;
41045         buffer *mc_namespace;
41046  #if defined(HAVE_PCRE_H)
41047 @@ -46,58 +46,58 @@
41048         GDBM_FILE db;
41049  #endif
41050  
41051 -#if defined(HAVE_MEMCACHE_H) 
41052 +#if defined(HAVE_MEMCACHE_H)
41053         struct memcache *mc;
41054  #endif
41055 -       
41056 +
41057         unsigned short trigger_timeout;
41058         unsigned short debug;
41059  } plugin_config;
41060  
41061  typedef struct {
41062         PLUGIN_DATA;
41063 -       
41064 +
41065         buffer *tmp_buf;
41066 -       
41067 +
41068         plugin_config **config_storage;
41069 -       
41070 -       plugin_config conf; 
41071 +
41072 +       plugin_config conf;
41073  } plugin_data;
41074  
41075  /* init the plugin data */
41076  INIT_FUNC(mod_trigger_b4_dl_init) {
41077         plugin_data *p;
41078 -       
41079 +
41080         p = calloc(1, sizeof(*p));
41081 -       
41082 +
41083         p->tmp_buf = buffer_init();
41084 -       
41085 +
41086         return p;
41087  }
41088  
41089  /* detroy the plugin data */
41090  FREE_FUNC(mod_trigger_b4_dl_free) {
41091         plugin_data *p = p_d;
41092 -       
41093 +
41094         UNUSED(srv);
41095  
41096         if (!p) return HANDLER_GO_ON;
41097 -       
41098 +
41099         if (p->config_storage) {
41100                 size_t i;
41101                 for (i = 0; i < srv->config_context->used; i++) {
41102                         plugin_config *s = p->config_storage[i];
41103  
41104                         if (!s) continue;
41105 -                       
41106 +
41107                         buffer_free(s->db_filename);
41108                         buffer_free(s->download_url);
41109                         buffer_free(s->trigger_url);
41110                         buffer_free(s->deny_url);
41111 -                       
41112 +
41113                         buffer_free(s->mc_namespace);
41114                         array_free(s->mc_hosts);
41115 -                       
41116 +
41117  #if defined(HAVE_PCRE_H)
41118                         if (s->trigger_regex) pcre_free(s->trigger_regex);
41119                         if (s->download_regex) pcre_free(s->download_regex);
41120 @@ -108,16 +108,16 @@
41121  #if defined(HAVE_MEMCACHE_H)
41122                         if (s->mc) mc_free(s->mc);
41123  #endif
41124 -                       
41125 +
41126                         free(s);
41127                 }
41128                 free(p->config_storage);
41129         }
41130 -       
41131 +
41132         buffer_free(p->tmp_buf);
41133 -       
41134 +
41135         free(p);
41136 -       
41137 +
41138         return HANDLER_GO_ON;
41139  }
41140  
41141 @@ -126,9 +126,9 @@
41142  SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) {
41143         plugin_data *p = p_d;
41144         size_t i = 0;
41145 -       
41146 -       
41147 -       config_values_t cv[] = { 
41148 +
41149 +
41150 +       config_values_t cv[] = {
41151                 { "trigger-before-download.gdbm-filename",   NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
41152                 { "trigger-before-download.trigger-url",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
41153                 { "trigger-before-download.download-url",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
41154 @@ -139,18 +139,18 @@
41155                 { "trigger-before-download.debug",           NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 7 */
41156                 { NULL,                        NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
41157         };
41158 -       
41159 +
41160         if (!p) return HANDLER_ERROR;
41161 -       
41162 +
41163         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
41164 -       
41165 +
41166         for (i = 0; i < srv->config_context->used; i++) {
41167                 plugin_config *s;
41168  #if defined(HAVE_PCRE_H)
41169                 const char *errptr;
41170                 int erroff;
41171  #endif
41172 -               
41173 +
41174                 s = calloc(1, sizeof(plugin_config));
41175                 s->db_filename    = buffer_init();
41176                 s->download_url   = buffer_init();
41177 @@ -158,7 +158,7 @@
41178                 s->deny_url       = buffer_init();
41179                 s->mc_hosts       = array_init();
41180                 s->mc_namespace   = buffer_init();
41181 -               
41182 +
41183                 cv[0].destination = s->db_filename;
41184                 cv[1].destination = s->trigger_url;
41185                 cv[2].destination = s->download_url;
41186 @@ -167,41 +167,41 @@
41187                 cv[5].destination = s->mc_hosts;
41188                 cv[6].destination = s->mc_namespace;
41189                 cv[7].destination = &(s->debug);
41190 -               
41191 +
41192                 p->config_storage[i] = s;
41193 -       
41194 +
41195                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
41196                         return HANDLER_ERROR;
41197                 }
41198  #if defined(HAVE_GDBM_H)
41199                 if (!buffer_is_empty(s->db_filename)) {
41200                         if (NULL == (s->db = gdbm_open(s->db_filename->ptr, 4096, GDBM_WRCREAT | GDBM_NOLOCK, S_IRUSR | S_IWUSR, 0))) {
41201 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
41202 +                               log_error_write(srv, __FILE__, __LINE__, "s",
41203                                                 "gdbm-open failed");
41204                                 return HANDLER_ERROR;
41205                         }
41206                 }
41207  #endif
41208 -#if defined(HAVE_PCRE_H)               
41209 +#if defined(HAVE_PCRE_H)
41210                 if (!buffer_is_empty(s->download_url)) {
41211                         if (NULL == (s->download_regex = pcre_compile(s->download_url->ptr,
41212                                                                       0, &errptr, &erroff, NULL))) {
41213 -                               
41214 -                               log_error_write(srv, __FILE__, __LINE__, "sbss", 
41215 -                                               "compiling regex for download-url failed:", 
41216 +
41217 +                               log_error_write(srv, __FILE__, __LINE__, "sbss",
41218 +                                               "compiling regex for download-url failed:",
41219                                                 s->download_url, "pos:", erroff);
41220                                 return HANDLER_ERROR;
41221                         }
41222                 }
41223 -               
41224 +
41225                 if (!buffer_is_empty(s->trigger_url)) {
41226                         if (NULL == (s->trigger_regex = pcre_compile(s->trigger_url->ptr,
41227                                                                      0, &errptr, &erroff, NULL))) {
41228 -                               
41229 -                               log_error_write(srv, __FILE__, __LINE__, "sbss", 
41230 -                                               "compiling regex for trigger-url failed:", 
41231 +
41232 +                               log_error_write(srv, __FILE__, __LINE__, "sbss",
41233 +                                               "compiling regex for trigger-url failed:",
41234                                                 s->trigger_url, "pos:", erroff);
41235 -                               
41236 +
41237                                 return HANDLER_ERROR;
41238                         }
41239                 }
41240 @@ -211,100 +211,97 @@
41241  #if defined(HAVE_MEMCACHE_H)
41242                         size_t k;
41243                         s->mc = mc_new();
41244 -               
41245 +
41246                         for (k = 0; k < s->mc_hosts->used; k++) {
41247                                 data_string *ds = (data_string *)s->mc_hosts->data[k];
41248 -                               
41249 +
41250                                 if (0 != mc_server_add4(s->mc, ds->value->ptr)) {
41251 -                                       log_error_write(srv, __FILE__, __LINE__, "sb", 
41252 -                                                       "connection to host failed:", 
41253 +                                       log_error_write(srv, __FILE__, __LINE__, "sb",
41254 +                                                       "connection to host failed:",
41255                                                         ds->value);
41256 -                                       
41257 +
41258                                         return HANDLER_ERROR;
41259                                 }
41260                         }
41261  #else
41262 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
41263 +                       log_error_write(srv, __FILE__, __LINE__, "s",
41264                                         "memcache support is not compiled in but trigger-before-download.memcache-hosts is set, aborting");
41265                         return HANDLER_ERROR;
41266  #endif
41267                 }
41268 -               
41269 +
41270  
41271  #if (!defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H)) || !defined(HAVE_PCRE_H)
41272 -               log_error_write(srv, __FILE__, __LINE__, "s", 
41273 +               log_error_write(srv, __FILE__, __LINE__, "s",
41274                                 "(either gdbm or libmemcache) and pcre are require, but were not found, aborting");
41275                 return HANDLER_ERROR;
41276  #endif
41277         }
41278 -       
41279 +
41280         return HANDLER_GO_ON;
41281  }
41282  
41283 -#define PATCH(x) \
41284 -       p->conf.x = s->x;
41285  static int mod_trigger_b4_dl_patch_connection(server *srv, connection *con, plugin_data *p) {
41286         size_t i, j;
41287         plugin_config *s = p->config_storage[0];
41288 -       
41289 +
41290  #if defined(HAVE_GDBM)
41291 -       PATCH(db);
41292 -#endif 
41293 +       PATCH_OPTION(db);
41294 +#endif
41295  #if defined(HAVE_PCRE_H)
41296 -       PATCH(download_regex);
41297 -       PATCH(trigger_regex);
41298 -#endif 
41299 -       PATCH(trigger_timeout);
41300 -       PATCH(deny_url);
41301 -       PATCH(mc_namespace);
41302 -       PATCH(debug);
41303 +       PATCH_OPTION(download_regex);
41304 +       PATCH_OPTION(trigger_regex);
41305 +#endif
41306 +       PATCH_OPTION(trigger_timeout);
41307 +       PATCH_OPTION(deny_url);
41308 +       PATCH_OPTION(mc_namespace);
41309 +       PATCH_OPTION(debug);
41310  #if defined(HAVE_MEMCACHE_H)
41311 -       PATCH(mc);
41312 +       PATCH_OPTION(mc);
41313  #endif
41314 -       
41315 +
41316         /* skip the first, the global context */
41317         for (i = 1; i < srv->config_context->used; i++) {
41318                 data_config *dc = (data_config *)srv->config_context->data[i];
41319                 s = p->config_storage[i];
41320 -               
41321 +
41322                 /* condition didn't match */
41323                 if (!config_check_cond(srv, con, dc)) continue;
41324 -               
41325 +
41326                 /* merge config */
41327                 for (j = 0; j < dc->value->used; j++) {
41328                         data_unset *du = dc->value->data[j];
41329  
41330                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.download-url"))) {
41331  #if defined(HAVE_PCRE_H)
41332 -                               PATCH(download_regex);
41333 +                               PATCH_OPTION(download_regex);
41334  #endif
41335                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-url"))) {
41336  # if defined(HAVE_PCRE_H)
41337 -                               PATCH(trigger_regex);
41338 +                               PATCH_OPTION(trigger_regex);
41339  # endif
41340                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.gdbm-filename"))) {
41341  #if defined(HAVE_GDBM_H)
41342 -                               PATCH(db);
41343 +                               PATCH_OPTION(db);
41344  #endif
41345                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-timeout"))) {
41346 -                               PATCH(trigger_timeout);
41347 +                               PATCH_OPTION(trigger_timeout);
41348                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.debug"))) {
41349 -                               PATCH(debug);
41350 +                               PATCH_OPTION(debug);
41351                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.deny-url"))) {
41352 -                               PATCH(deny_url);
41353 +                               PATCH_OPTION(deny_url);
41354                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-namespace"))) {
41355 -                               PATCH(mc_namespace);
41356 +                               PATCH_OPTION(mc_namespace);
41357                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-hosts"))) {
41358  #if defined(HAVE_MEMCACHE_H)
41359 -                               PATCH(mc);
41360 +                               PATCH_OPTION(mc);
41361  #endif
41362                         }
41363                 }
41364         }
41365 -       
41366 +
41367         return 0;
41368  }
41369 -#undef PATCH
41370  
41371  URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
41372         plugin_data *p = p_d;
41373 @@ -315,20 +312,20 @@
41374         int n;
41375  # define N 10
41376         int ovec[N * 3];
41377 -       
41378 +
41379         if (con->uri.path->used == 0) return HANDLER_GO_ON;
41380 -       
41381 +
41382         mod_trigger_b4_dl_patch_connection(srv, con, p);
41383 -       
41384 +
41385         if (!p->conf.trigger_regex || !p->conf.download_regex) return HANDLER_GO_ON;
41386 -       
41387 +
41388  # if !defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H)
41389         return HANDLER_GO_ON;
41390  # elif defined(HAVE_GDBM_H) && defined(HAVE_MEMCACHE_H)
41391         if (!p->conf.db && !p->conf.mc) return HANDLER_GO_ON;
41392         if (p->conf.db && p->conf.mc) {
41393                 /* can't decide which one */
41394 -               
41395 +
41396                 return HANDLER_GO_ON;
41397         }
41398  # elif defined(HAVE_GDBM_H)
41399 @@ -336,12 +333,12 @@
41400  # else
41401         if (!p->conf.mc) return HANDLER_GO_ON;
41402  # endif
41403 -       
41404 +
41405         if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "X-Forwarded-For"))) {
41406                 /* X-Forwarded-For contains the ip behind the proxy */
41407 -               
41408 +
41409                 remote_ip = ds->value->ptr;
41410 -               
41411 +
41412                 /* memcache can't handle spaces */
41413         } else {
41414                 remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
41415 @@ -350,13 +347,13 @@
41416         if (p->conf.debug) {
41417                 log_error_write(srv, __FILE__, __LINE__, "ss", "(debug) remote-ip:", remote_ip);
41418         }
41419 -               
41420 +
41421         /* check if URL is a trigger -> insert IP into DB */
41422         if ((n = pcre_exec(p->conf.trigger_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
41423                 if (n != PCRE_ERROR_NOMATCH) {
41424                         log_error_write(srv, __FILE__, __LINE__, "sd",
41425                                         "execution error while matching:", n);
41426 -                       
41427 +
41428                         return HANDLER_ERROR;
41429                 }
41430         } else {
41431 @@ -364,34 +361,34 @@
41432                 if (p->conf.db) {
41433                         /* the trigger matched */
41434                         datum key, val;
41435 -                       
41436 +
41437                         key.dptr = (char *)remote_ip;
41438                         key.dsize = strlen(remote_ip);
41439 -                       
41440 +
41441                         val.dptr = (char *)&(srv->cur_ts);
41442                         val.dsize = sizeof(srv->cur_ts);
41443 -                       
41444 +
41445                         if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
41446                                 log_error_write(srv, __FILE__, __LINE__, "s",
41447                                                 "insert failed");
41448                         }
41449                 }
41450  # endif
41451 -# if defined(HAVE_MEMCACHE_H)          
41452 +# if defined(HAVE_MEMCACHE_H)
41453                 if (p->conf.mc) {
41454                         size_t i;
41455                         buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace);
41456                         buffer_append_string(p->tmp_buf, remote_ip);
41457 -                       
41458 +
41459                         for (i = 0; i < p->tmp_buf->used - 1; i++) {
41460                                 if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
41461                         }
41462 -                       
41463 +
41464                         if (p->conf.debug) {
41465                                 log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) triggered IP:", p->tmp_buf);
41466                         }
41467  
41468 -                       if (0 != mc_set(p->conf.mc, 
41469 +                       if (0 != mc_set(p->conf.mc,
41470                                         CONST_BUF_LEN(p->tmp_buf),
41471                                         (char *)&(srv->cur_ts), sizeof(srv->cur_ts),
41472                                         p->conf.trigger_timeout, 0)) {
41473 @@ -401,7 +398,7 @@
41474                 }
41475  # endif
41476         }
41477 -               
41478 +
41479         /* check if URL is a download -> check IP in DB, update timestamp */
41480         if ((n = pcre_exec(p->conf.download_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
41481                 if (n != PCRE_ERROR_NOMATCH) {
41482 @@ -411,93 +408,93 @@
41483                 }
41484         } else {
41485                 /* the download uri matched */
41486 -# if defined(HAVE_GDBM_H)              
41487 +# if defined(HAVE_GDBM_H)
41488                 if (p->conf.db) {
41489                         datum key, val;
41490                         time_t last_hit;
41491 -               
41492 +
41493                         key.dptr = (char *)remote_ip;
41494                         key.dsize = strlen(remote_ip);
41495 -                       
41496 +
41497                         val = gdbm_fetch(p->conf.db, key);
41498 -               
41499 +
41500                         if (val.dptr == NULL) {
41501                                 /* not found, redirect */
41502 -                               
41503 +
41504                                 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
41505 -                               
41506 +
41507                                 con->http_status = 307;
41508 -                               
41509 +
41510                                 return HANDLER_FINISHED;
41511                         }
41512 -                       
41513 +
41514                         last_hit = *(time_t *)(val.dptr);
41515 -                       
41516 +
41517                         free(val.dptr);
41518 -                       
41519 +
41520                         if (srv->cur_ts - last_hit > p->conf.trigger_timeout) {
41521                                 /* found, but timeout, redirect */
41522 -                               
41523 +
41524                                 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
41525                                 con->http_status = 307;
41526 -                               
41527 +
41528                                 if (p->conf.db) {
41529                                         if (0 != gdbm_delete(p->conf.db, key)) {
41530                                                 log_error_write(srv, __FILE__, __LINE__, "s",
41531                                                                 "delete failed");
41532                                         }
41533                                 }
41534 -                               
41535 +
41536                                 return HANDLER_FINISHED;
41537                         }
41538 -                       
41539 +
41540                         val.dptr = (char *)&(srv->cur_ts);
41541                         val.dsize = sizeof(srv->cur_ts);
41542 -                       
41543 +
41544                         if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
41545                                 log_error_write(srv, __FILE__, __LINE__, "s",
41546                                                 "insert failed");
41547                         }
41548                 }
41549  # endif
41550 -               
41551 -# if defined(HAVE_MEMCACHE_H)          
41552 +
41553 +# if defined(HAVE_MEMCACHE_H)
41554                 if (p->conf.mc) {
41555                         void *r;
41556                         size_t i;
41557 -                       
41558 +
41559                         buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace);
41560                         buffer_append_string(p->tmp_buf, remote_ip);
41561 -                       
41562 +
41563                         for (i = 0; i < p->tmp_buf->used - 1; i++) {
41564                                 if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
41565                         }
41566 -                       
41567 +
41568                         if (p->conf.debug) {
41569                                 log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) checking IP:", p->tmp_buf);
41570                         }
41571  
41572                         /**
41573 -                        * 
41574 +                        *
41575                          * memcached is do expiration for us, as long as we can fetch it every thing is ok
41576 -                        * and the timestamp is updated 
41577 -                        * 
41578 +                        * and the timestamp is updated
41579 +                        *
41580                          */
41581 -                       if (NULL == (r = mc_aget(p->conf.mc, 
41582 +                       if (NULL == (r = mc_aget(p->conf.mc,
41583                                                  CONST_BUF_LEN(p->tmp_buf)
41584                                                  ))) {
41585 -                               
41586 +
41587                                 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
41588 -                               
41589 +
41590                                 con->http_status = 307;
41591 -                               
41592 +
41593                                 return HANDLER_FINISHED;
41594                         }
41595 -                       
41596 +
41597                         free(r);
41598 -                       
41599 +
41600                         /* set a new timeout */
41601 -                       if (0 != mc_set(p->conf.mc, 
41602 +                       if (0 != mc_set(p->conf.mc,
41603                                         CONST_BUF_LEN(p->tmp_buf),
41604                                         (char *)&(srv->cur_ts), sizeof(srv->cur_ts),
41605                                         p->conf.trigger_timeout, 0)) {
41606 @@ -507,13 +504,13 @@
41607                 }
41608  # endif
41609         }
41610 -       
41611 +
41612  #else
41613         UNUSED(srv);
41614         UNUSED(con);
41615         UNUSED(p_d);
41616  #endif
41617 -       
41618 +
41619         return HANDLER_GO_ON;
41620  }
41621  
41622 @@ -521,21 +518,21 @@
41623  TRIGGER_FUNC(mod_trigger_b4_dl_handle_trigger) {
41624         plugin_data *p = p_d;
41625         size_t i;
41626 -       
41627 +
41628         /* check DB each minute */
41629         if (srv->cur_ts % 60 != 0) return HANDLER_GO_ON;
41630 -       
41631 +
41632         /* cleanup */
41633         for (i = 0; i < srv->config_context->used; i++) {
41634                 plugin_config *s = p->config_storage[i];
41635                 datum key, val, okey;
41636 -               
41637 +
41638                 if (!s->db) continue;
41639 -               
41640 +
41641                 okey.dptr = NULL;
41642 -               
41643 -               /* according to the manual this loop + delete does delete all entries on its way 
41644 -                * 
41645 +
41646 +               /* according to the manual this loop + delete does delete all entries on its way
41647 +                *
41648                  * we don't care as the next round will remove them. We don't have to perfect here.
41649                  */
41650                 for (key = gdbm_firstkey(s->db); key.dptr; key = gdbm_nextkey(s->db, okey)) {
41651 @@ -544,21 +541,21 @@
41652                                 free(okey.dptr);
41653                                 okey.dptr = NULL;
41654                         }
41655 -                       
41656 +
41657                         val = gdbm_fetch(s->db, key);
41658 -                       
41659 +
41660                         last_hit = *(time_t *)(val.dptr);
41661 -                       
41662 +
41663                         free(val.dptr);
41664 -                       
41665 +
41666                         if (srv->cur_ts - last_hit > s->trigger_timeout) {
41667                                 gdbm_delete(s->db, key);
41668                         }
41669 -                       
41670 +
41671                         okey = key;
41672                 }
41673                 if (okey.dptr) free(okey.dptr);
41674 -               
41675 +
41676                 /* reorg once a day */
41677                 if ((srv->cur_ts % (60 * 60 * 24) != 0)) gdbm_reorganize(s->db);
41678         }
41679 @@ -571,7 +568,7 @@
41680  int mod_trigger_b4_dl_plugin_init(plugin *p) {
41681         p->version     = LIGHTTPD_VERSION_ID;
41682         p->name        = buffer_init_string("trigger_b4_dl");
41683 -       
41684 +
41685         p->init        = mod_trigger_b4_dl_init;
41686         p->handle_uri_clean  = mod_trigger_b4_dl_uri_handler;
41687         p->set_defaults  = mod_trigger_b4_dl_set_defaults;
41688 @@ -579,8 +576,8 @@
41689         p->handle_trigger  = mod_trigger_b4_dl_handle_trigger;
41690  #endif
41691         p->cleanup     = mod_trigger_b4_dl_free;
41692 -       
41693 +
41694         p->data        = NULL;
41695 -       
41696 +
41697         return 0;
41698  }
41699 --- ../lighttpd-1.4.11/src/mod_userdir.c        2005-10-28 16:48:28.000000000 +0300
41700 +++ lighttpd-1.4.12/src/mod_userdir.c   2006-07-16 00:26:04.000000000 +0300
41701 @@ -10,6 +10,7 @@
41702  #include "response.h"
41703  
41704  #include "plugin.h"
41705 +#include "sys-files.h"
41706  
41707  #ifdef HAVE_PWD_H
41708  #include <pwd.h>
41709 @@ -25,54 +26,54 @@
41710  
41711  typedef struct {
41712         PLUGIN_DATA;
41713 -       
41714 +
41715         buffer *username;
41716         buffer *temp_path;
41717 -       
41718 +
41719         plugin_config **config_storage;
41720 -       
41721 -       plugin_config conf; 
41722 +
41723 +       plugin_config conf;
41724  } plugin_data;
41725  
41726  /* init the plugin data */
41727  INIT_FUNC(mod_userdir_init) {
41728         plugin_data *p;
41729 -       
41730 +
41731         p = calloc(1, sizeof(*p));
41732 -       
41733 +
41734         p->username = buffer_init();
41735         p->temp_path = buffer_init();
41736 -       
41737 +
41738         return p;
41739  }
41740  
41741  /* detroy the plugin data */
41742  FREE_FUNC(mod_userdir_free) {
41743         plugin_data *p = p_d;
41744 -       
41745 +
41746         if (!p) return HANDLER_GO_ON;
41747 -       
41748 +
41749         if (p->config_storage) {
41750                 size_t i;
41751 -               
41752 +
41753                 for (i = 0; i < srv->config_context->used; i++) {
41754                         plugin_config *s = p->config_storage[i];
41755 -                       
41756 +
41757                         array_free(s->include_user);
41758                         array_free(s->exclude_user);
41759                         buffer_free(s->path);
41760                         buffer_free(s->basepath);
41761 -                       
41762 +
41763                         free(s);
41764                 }
41765                 free(p->config_storage);
41766         }
41767 -       
41768 +
41769         buffer_free(p->username);
41770         buffer_free(p->temp_path);
41771 -       
41772 +
41773         free(p);
41774 -       
41775 +
41776         return HANDLER_GO_ON;
41777  }
41778  
41779 @@ -81,81 +82,78 @@
41780  SETDEFAULTS_FUNC(mod_userdir_set_defaults) {
41781         plugin_data *p = p_d;
41782         size_t i;
41783 -       
41784 -       config_values_t cv[] = { 
41785 +
41786 +       config_values_t cv[] = {
41787                 { "userdir.path",               NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
41788                 { "userdir.exclude-user",       NULL, T_CONFIG_ARRAY,  T_CONFIG_SCOPE_CONNECTION },       /* 1 */
41789                 { "userdir.include-user",       NULL, T_CONFIG_ARRAY,  T_CONFIG_SCOPE_CONNECTION },       /* 2 */
41790                 { "userdir.basepath",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
41791                 { NULL,                         NULL, T_CONFIG_UNSET,  T_CONFIG_SCOPE_UNSET }
41792         };
41793 -       
41794 +
41795         if (!p) return HANDLER_ERROR;
41796 -       
41797 +
41798         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
41799 -       
41800 +
41801         for (i = 0; i < srv->config_context->used; i++) {
41802                 plugin_config *s;
41803 -               
41804 +
41805                 s = calloc(1, sizeof(plugin_config));
41806                 s->exclude_user = array_init();
41807                 s->include_user = array_init();
41808                 s->path = buffer_init();
41809                 s->basepath = buffer_init();
41810 -       
41811 +
41812                 cv[0].destination = s->path;
41813                 cv[1].destination = s->exclude_user;
41814                 cv[2].destination = s->include_user;
41815                 cv[3].destination = s->basepath;
41816 -               
41817 +
41818                 p->config_storage[i] = s;
41819 -       
41820 +
41821                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
41822                         return HANDLER_ERROR;
41823                 }
41824         }
41825 -       
41826 +
41827         return HANDLER_GO_ON;
41828  }
41829  
41830 -#define PATCH(x) \
41831 -       p->conf.x = s->x;
41832  static int mod_userdir_patch_connection(server *srv, connection *con, plugin_data *p) {
41833         size_t i, j;
41834         plugin_config *s = p->config_storage[0];
41835 -       
41836 -       PATCH(path);
41837 -       PATCH(exclude_user);
41838 -       PATCH(include_user);
41839 -       PATCH(basepath);
41840 -       
41841 +
41842 +       PATCH_OPTION(path);
41843 +       PATCH_OPTION(exclude_user);
41844 +       PATCH_OPTION(include_user);
41845 +       PATCH_OPTION(basepath);
41846 +
41847         /* skip the first, the global context */
41848         for (i = 1; i < srv->config_context->used; i++) {
41849                 data_config *dc = (data_config *)srv->config_context->data[i];
41850                 s = p->config_storage[i];
41851 -               
41852 +
41853                 /* condition didn't match */
41854                 if (!config_check_cond(srv, con, dc)) continue;
41855 -               
41856 +
41857                 /* merge config */
41858                 for (j = 0; j < dc->value->used; j++) {
41859                         data_unset *du = dc->value->data[j];
41860 -                       
41861 +
41862                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.path"))) {
41863 -                               PATCH(path);
41864 +                               PATCH_OPTION(path);
41865                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.exclude-user"))) {
41866 -                               PATCH(exclude_user);
41867 +                               PATCH_OPTION(exclude_user);
41868                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.include-user"))) {
41869 -                               PATCH(include_user);
41870 +                               PATCH_OPTION(include_user);
41871                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.basepath"))) {
41872 -                               PATCH(basepath);
41873 +                               PATCH_OPTION(basepath);
41874                         }
41875                 }
41876         }
41877 -       
41878 +
41879         return 0;
41880  }
41881 -#undef PATCH
41882  
41883  URIHANDLER_FUNC(mod_userdir_docroot_handler) {
41884         plugin_data *p = p_d;
41885 @@ -169,18 +167,18 @@
41886         if (con->uri.path->used == 0) return HANDLER_GO_ON;
41887  
41888         mod_userdir_patch_connection(srv, con, p);
41889 -       
41890 +
41891         uri_len = con->uri.path->used - 1;
41892 -       
41893 +
41894         /* /~user/foo.html -> /home/user/public_html/foo.html */
41895 -       
41896 +
41897         if (con->uri.path->ptr[0] != '/' ||
41898             con->uri.path->ptr[1] != '~') return HANDLER_GO_ON;
41899 -       
41900 +
41901         if (NULL == (rel_url = strchr(con->uri.path->ptr + 2, '/'))) {
41902                 /* / is missing -> redirect to .../ as we are a user - DIRECTORY ! :) */
41903                 http_response_redirect_to_directory(srv, con);
41904 -               
41905 +
41906                 return HANDLER_FINISHED;
41907         }
41908  
41909 @@ -188,10 +186,10 @@
41910         if (0 == rel_url - (con->uri.path->ptr + 2)) {
41911                 return HANDLER_GO_ON;
41912         }
41913 -       
41914 +
41915         buffer_copy_string_len(p->username, con->uri.path->ptr + 2, rel_url - (con->uri.path->ptr + 2));
41916 -       
41917 -       if (buffer_is_empty(p->conf.basepath) 
41918 +
41919 +       if (buffer_is_empty(p->conf.basepath)
41920  #ifdef HAVE_PWD_H
41921             && NULL == (pwd = getpwnam(p->username->ptr))
41922  #endif
41923 @@ -200,31 +198,31 @@
41924                 return HANDLER_GO_ON;
41925         }
41926  
41927 -       
41928 +
41929         for (k = 0; k < p->conf.exclude_user->used; k++) {
41930                 data_string *ds = (data_string *)p->conf.exclude_user->data[k];
41931 -               
41932 +
41933                 if (buffer_is_equal(ds->value, p->username)) {
41934                         /* user in exclude list */
41935                         return HANDLER_GO_ON;
41936                 }
41937         }
41938 -       
41939 +
41940         if (p->conf.include_user->used) {
41941                 int found_user = 0;
41942                 for (k = 0; k < p->conf.include_user->used; k++) {
41943                         data_string *ds = (data_string *)p->conf.include_user->data[k];
41944 -                       
41945 +
41946                         if (buffer_is_equal(ds->value, p->username)) {
41947                                 /* user in include list */
41948                                 found_user = 1;
41949                                 break;
41950                         }
41951                 }
41952 -               
41953 +
41954                 if (!found_user) return HANDLER_GO_ON;
41955         }
41956 -       
41957 +
41958         /* we build the physical path */
41959  
41960         if (buffer_is_empty(p->conf.basepath)) {
41961 @@ -252,23 +250,23 @@
41962                 }
41963  
41964                 buffer_copy_string_buffer(p->temp_path, p->conf.basepath);
41965 -               BUFFER_APPEND_SLASH(p->temp_path);
41966 +               PATHNAME_APPEND_SLASH(p->temp_path);
41967                 buffer_append_string_buffer(p->temp_path, p->username);
41968         }
41969 -       BUFFER_APPEND_SLASH(p->temp_path);
41970 -       buffer_append_string_buffer(p->temp_path, p->conf.path); 
41971 +       PATHNAME_APPEND_SLASH(p->temp_path);
41972 +       buffer_append_string_buffer(p->temp_path, p->conf.path);
41973  
41974         if (buffer_is_empty(p->conf.basepath)) {
41975                 struct stat st;
41976                 int ret;
41977 -               
41978 +
41979                 ret = stat(p->temp_path->ptr, &st);
41980                 if (ret < 0 || S_ISDIR(st.st_mode) != 1) {
41981                         return HANDLER_GO_ON;
41982 -               } 
41983 +               }
41984         }
41985  
41986 -       BUFFER_APPEND_SLASH(p->temp_path);
41987 +       PATHNAME_APPEND_SLASH(p->temp_path);
41988         buffer_append_string(p->temp_path, rel_url + 1); /* skip the / */
41989         buffer_copy_string_buffer(con->physical.path, p->temp_path);
41990  
41991 @@ -282,13 +280,13 @@
41992  int mod_userdir_plugin_init(plugin *p) {
41993         p->version     = LIGHTTPD_VERSION_ID;
41994         p->name        = buffer_init_string("userdir");
41995 -       
41996 +
41997         p->init           = mod_userdir_init;
41998         p->handle_physical = mod_userdir_docroot_handler;
41999         p->set_defaults   = mod_userdir_set_defaults;
42000         p->cleanup        = mod_userdir_free;
42001 -       
42002 +
42003         p->data        = NULL;
42004 -       
42005 +
42006         return 0;
42007  }
42008 --- ../lighttpd-1.4.11/src/mod_usertrack.c      2006-01-31 15:01:20.000000000 +0200
42009 +++ lighttpd-1.4.12/src/mod_usertrack.c 2006-07-16 00:26:04.000000000 +0300
42010 @@ -24,44 +24,44 @@
42011  
42012  typedef struct {
42013         PLUGIN_DATA;
42014 -       
42015 +
42016         plugin_config **config_storage;
42017 -       
42018 -       plugin_config conf; 
42019 +
42020 +       plugin_config conf;
42021  } plugin_data;
42022  
42023  /* init the plugin data */
42024  INIT_FUNC(mod_usertrack_init) {
42025         plugin_data *p;
42026 -       
42027 +
42028         p = calloc(1, sizeof(*p));
42029 -       
42030 +
42031         return p;
42032  }
42033  
42034  /* detroy the plugin data */
42035  FREE_FUNC(mod_usertrack_free) {
42036         plugin_data *p = p_d;
42037 -       
42038 +
42039         UNUSED(srv);
42040 -       
42041 +
42042         if (!p) return HANDLER_GO_ON;
42043 -       
42044 +
42045         if (p->config_storage) {
42046                 size_t i;
42047                 for (i = 0; i < srv->config_context->used; i++) {
42048                         plugin_config *s = p->config_storage[i];
42049 -                       
42050 +
42051                         buffer_free(s->cookie_name);
42052                         buffer_free(s->cookie_domain);
42053 -                       
42054 +
42055                         free(s);
42056                 }
42057                 free(p->config_storage);
42058         }
42059 -       
42060 +
42061         free(p);
42062 -       
42063 +
42064         return HANDLER_GO_ON;
42065  }
42066  
42067 @@ -70,38 +70,38 @@
42068  SETDEFAULTS_FUNC(mod_usertrack_set_defaults) {
42069         plugin_data *p = p_d;
42070         size_t i = 0;
42071 -       
42072 -       config_values_t cv[] = { 
42073 +
42074 +       config_values_t cv[] = {
42075                 { "usertrack.cookie-name",       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
42076                 { "usertrack.cookie-max-age",    NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 1 */
42077                 { "usertrack.cookie-domain",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
42078 -               
42079 -               { "usertrack.cookiename",        NULL, T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION },   
42080 +
42081 +               { "usertrack.cookiename",        NULL, T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION },
42082                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
42083         };
42084 -       
42085 +
42086         if (!p) return HANDLER_ERROR;
42087 -       
42088 +
42089         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
42090 -       
42091 +
42092         for (i = 0; i < srv->config_context->used; i++) {
42093                 plugin_config *s;
42094 -               
42095 +
42096                 s = calloc(1, sizeof(plugin_config));
42097                 s->cookie_name    = buffer_init();
42098                 s->cookie_domain  = buffer_init();
42099                 s->cookie_max_age = 0;
42100 -               
42101 +
42102                 cv[0].destination = s->cookie_name;
42103                 cv[1].destination = &(s->cookie_max_age);
42104                 cv[2].destination = s->cookie_domain;
42105 -               
42106 +
42107                 p->config_storage[i] = s;
42108 -       
42109 +
42110                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
42111                         return HANDLER_ERROR;
42112                 }
42113 -       
42114 +
42115                 if (buffer_is_empty(s->cookie_name)) {
42116                         buffer_copy_string(s->cookie_name, "TRACKID");
42117                 } else {
42118 @@ -109,68 +109,65 @@
42119                         for (j = 0; j < s->cookie_name->used - 1; j++) {
42120                                 char c = s->cookie_name->ptr[j] | 32;
42121                                 if (c < 'a' || c > 'z') {
42122 -                                       log_error_write(srv, __FILE__, __LINE__, "sb", 
42123 -                                                       "invalid character in usertrack.cookie-name:", 
42124 +                                       log_error_write(srv, __FILE__, __LINE__, "sb",
42125 +                                                       "invalid character in usertrack.cookie-name:",
42126                                                         s->cookie_name);
42127 -                                       
42128 +
42129                                         return HANDLER_ERROR;
42130                                 }
42131                         }
42132                 }
42133 -               
42134 +
42135                 if (!buffer_is_empty(s->cookie_domain)) {
42136                         size_t j;
42137                         for (j = 0; j < s->cookie_domain->used - 1; j++) {
42138                                 char c = s->cookie_domain->ptr[j];
42139                                 if (c <= 32 || c >= 127 || c == '"' || c == '\\') {
42140 -                                       log_error_write(srv, __FILE__, __LINE__, "sb", 
42141 -                                                       "invalid character in usertrack.cookie-domain:", 
42142 +                                       log_error_write(srv, __FILE__, __LINE__, "sb",
42143 +                                                       "invalid character in usertrack.cookie-domain:",
42144                                                         s->cookie_domain);
42145 -                                       
42146 +
42147                                         return HANDLER_ERROR;
42148                                 }
42149                         }
42150                 }
42151         }
42152 -               
42153 +
42154         return HANDLER_GO_ON;
42155  }
42156  
42157 -#define PATCH(x) \
42158 -       p->conf.x = s->x;
42159  static int mod_usertrack_patch_connection(server *srv, connection *con, plugin_data *p) {
42160         size_t i, j;
42161         plugin_config *s = p->config_storage[0];
42162 -       
42163 -       PATCH(cookie_name);
42164 -       PATCH(cookie_domain);
42165 -       PATCH(cookie_max_age);
42166 -       
42167 +
42168 +       PATCH_OPTION(cookie_name);
42169 +       PATCH_OPTION(cookie_domain);
42170 +       PATCH_OPTION(cookie_max_age);
42171 +
42172         /* skip the first, the global context */
42173         for (i = 1; i < srv->config_context->used; i++) {
42174                 data_config *dc = (data_config *)srv->config_context->data[i];
42175                 s = p->config_storage[i];
42176 -               
42177 +
42178                 /* condition didn't match */
42179                 if (!config_check_cond(srv, con, dc)) continue;
42180 -               
42181 +
42182                 /* merge config */
42183                 for (j = 0; j < dc->value->used; j++) {
42184                         data_unset *du = dc->value->data[j];
42185 -                       
42186 +
42187                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-name"))) {
42188 -                               PATCH(cookie_name);
42189 +                               PATCH_OPTION(cookie_name);
42190                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-max-age"))) {
42191 -                               PATCH(cookie_max_age);
42192 +                               PATCH_OPTION(cookie_max_age);
42193                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-domain"))) {
42194 -                               PATCH(cookie_domain);
42195 +                               PATCH_OPTION(cookie_domain);
42196                         }
42197                 }
42198         }
42199 -       
42200 +
42201         return 0;
42202  }
42203 -#undef PATCH
42204  
42205  URIHANDLER_FUNC(mod_usertrack_uri_handler) {
42206         plugin_data *p = p_d;
42207 @@ -178,38 +175,38 @@
42208         unsigned char h[16];
42209         MD5_CTX Md5Ctx;
42210         char hh[32];
42211 -       
42212 +
42213         if (con->uri.path->used == 0) return HANDLER_GO_ON;
42214 -       
42215 +
42216         mod_usertrack_patch_connection(srv, con, p);
42217 -       
42218 +
42219         if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) {
42220                 char *g;
42221                 /* we have a cookie, does it contain a valid name ? */
42222 -               
42223 -               /* parse the cookie 
42224 -                * 
42225 +
42226 +               /* parse the cookie
42227 +                *
42228                  * check for cookiename + (WS | '=')
42229 -                * 
42230 +                *
42231                  */
42232 -               
42233 +
42234                 if (NULL != (g = strstr(ds->value->ptr, p->conf.cookie_name->ptr))) {
42235                         char *nc;
42236 -                       
42237 +
42238                         /* skip WS */
42239                         for (nc = g + p->conf.cookie_name->used-1; *nc == ' ' || *nc == '\t'; nc++);
42240 -                       
42241 +
42242                         if (*nc == '=') {
42243                                 /* ok, found the key of our own cookie */
42244 -                               
42245 +
42246                                 if (strlen(nc) > 32) {
42247                                         /* i'm lazy */
42248                                         return HANDLER_GO_ON;
42249                                 }
42250                         }
42251                 }
42252 -       } 
42253 -       
42254 +       }
42255 +
42256         /* set a cookie */
42257         if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
42258                 ds = data_response_init();
42259 @@ -217,39 +214,39 @@
42260         buffer_copy_string(ds->key, "Set-Cookie");
42261         buffer_copy_string_buffer(ds->value, p->conf.cookie_name);
42262         buffer_append_string(ds->value, "=");
42263 -       
42264 +
42265  
42266         /* taken from mod_auth.c */
42267 -       
42268 +
42269         /* generate shared-secret */
42270         MD5_Init(&Md5Ctx);
42271         MD5_Update(&Md5Ctx, (unsigned char *)con->uri.path->ptr, con->uri.path->used - 1);
42272         MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
42273 -       
42274 +
42275         /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
42276         ltostr(hh, srv->cur_ts);
42277         MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
42278         ltostr(hh, rand());
42279         MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
42280 -       
42281 +
42282         MD5_Final(h, &Md5Ctx);
42283 -       
42284 +
42285         buffer_append_string_encoded(ds->value, (char *)h, 16, ENCODING_HEX);
42286         buffer_append_string(ds->value, "; Path=/");
42287         buffer_append_string(ds->value, "; Version=1");
42288 -       
42289 +
42290         if (!buffer_is_empty(p->conf.cookie_domain)) {
42291                 buffer_append_string(ds->value, "; Domain=");
42292                 buffer_append_string_encoded(ds->value, CONST_BUF_LEN(p->conf.cookie_domain), ENCODING_REL_URI);
42293         }
42294 -       
42295 +
42296         if (p->conf.cookie_max_age) {
42297                 buffer_append_string(ds->value, "; max-age=");
42298                 buffer_append_long(ds->value, p->conf.cookie_max_age);
42299         }
42300 -       
42301 +
42302         array_insert_unique(con->response.headers, (data_unset *)ds);
42303 -       
42304 +
42305         return HANDLER_GO_ON;
42306  }
42307  
42308 @@ -258,13 +255,13 @@
42309  int mod_usertrack_plugin_init(plugin *p) {
42310         p->version     = LIGHTTPD_VERSION_ID;
42311         p->name        = buffer_init_string("usertrack");
42312 -       
42313 +
42314         p->init        = mod_usertrack_init;
42315         p->handle_uri_clean  = mod_usertrack_uri_handler;
42316         p->set_defaults  = mod_usertrack_set_defaults;
42317         p->cleanup     = mod_usertrack_free;
42318 -       
42319 +
42320         p->data        = NULL;
42321 -       
42322 +
42323         return 0;
42324  }
42325 --- ../lighttpd-1.4.11/src/mod_webdav.c 2006-03-03 01:28:58.000000000 +0200
42326 +++ lighttpd-1.4.12/src/mod_webdav.c    2006-07-18 13:03:40.000000000 +0300
42327 @@ -3,13 +3,10 @@
42328  #include <ctype.h>
42329  #include <stdlib.h>
42330  #include <string.h>
42331 -#include <dirent.h>
42332  #include <errno.h>
42333 -#include <unistd.h>
42334  #include <fcntl.h>
42335  #include <stdio.h>
42336  #include <assert.h>
42337 -#include <sys/mman.h>
42338  
42339  #ifdef HAVE_CONFIG_H
42340  #include "config.h"
42341 @@ -23,6 +20,11 @@
42342  #include <sqlite3.h>
42343  #endif
42344  
42345 +#if defined(HAVE_LIBXML_H) && defined(HAVE_SQLITE3_H) && defined(HAVE_UUID_H)
42346 +#define USE_LOCKS
42347 +#include <uuid/uuid.h>
42348 +#endif
42349 +
42350  #include "base.h"
42351  #include "log.h"
42352  #include "buffer.h"
42353 @@ -33,13 +35,16 @@
42354  #include "stream.h"
42355  #include "stat_cache.h"
42356  
42357 +#include "sys-files.h"
42358 +#include "sys-mmap.h"
42359 +#include "sys-strings.h"
42360  
42361  /**
42362   * this is a webdav for a lighttpd plugin
42363   *
42364 - * at least a very basic one. 
42365 + * at least a very basic one.
42366   * - for now it is read-only and we only support PROPFIND
42367 - * 
42368 + *
42369   */
42370  
42371  
42372 @@ -58,64 +63,70 @@
42373         sqlite3_stmt *stmt_delete_prop;
42374         sqlite3_stmt *stmt_select_prop;
42375         sqlite3_stmt *stmt_select_propnames;
42376 -       
42377 +
42378         sqlite3_stmt *stmt_delete_uri;
42379         sqlite3_stmt *stmt_move_uri;
42380         sqlite3_stmt *stmt_copy_uri;
42381 +
42382 +       sqlite3_stmt *stmt_remove_lock;
42383 +       sqlite3_stmt *stmt_create_lock;
42384 +       sqlite3_stmt *stmt_read_lock;
42385 +       sqlite3_stmt *stmt_read_lock_by_uri;
42386 +       sqlite3_stmt *stmt_refresh_lock;
42387  #endif
42388  } plugin_config;
42389  
42390  typedef struct {
42391         PLUGIN_DATA;
42392 -       
42393 +
42394         buffer *tmp_buf;
42395         request_uri uri;
42396         physical physical;
42397  
42398         plugin_config **config_storage;
42399 -       
42400 -       plugin_config conf; 
42401 +
42402 +       plugin_config conf;
42403  } plugin_data;
42404  
42405  /* init the plugin data */
42406  INIT_FUNC(mod_webdav_init) {
42407         plugin_data *p;
42408 -       
42409 +
42410         p = calloc(1, sizeof(*p));
42411 -       
42412 +
42413         p->tmp_buf = buffer_init();
42414  
42415         p->uri.scheme = buffer_init();
42416         p->uri.path_raw = buffer_init();
42417         p->uri.path = buffer_init();
42418         p->uri.authority = buffer_init();
42419 -       
42420 +
42421         p->physical.path = buffer_init();
42422         p->physical.rel_path = buffer_init();
42423         p->physical.doc_root = buffer_init();
42424         p->physical.basedir = buffer_init();
42425 -       
42426 +
42427         return p;
42428  }
42429  
42430  /* detroy the plugin data */
42431  FREE_FUNC(mod_webdav_free) {
42432         plugin_data *p = p_d;
42433 -       
42434 +
42435         UNUSED(srv);
42436  
42437         if (!p) return HANDLER_GO_ON;
42438 -       
42439 +
42440         if (p->config_storage) {
42441                 size_t i;
42442                 for (i = 0; i < srv->config_context->used; i++) {
42443                         plugin_config *s = p->config_storage[i];
42444  
42445                         if (!s) continue;
42446 -       
42447 +
42448                         buffer_free(s->sqlite_db_name);
42449  #ifdef USE_PROPPATCH
42450 -                       if (s->sql) {   
42451 +                       if (s->sql) {
42452                                 sqlite3_finalize(s->stmt_delete_prop);
42453                                 sqlite3_finalize(s->stmt_delete_uri);
42454                                 sqlite3_finalize(s->stmt_copy_uri);
42455 @@ -123,9 +134,15 @@
42456                                 sqlite3_finalize(s->stmt_update_prop);
42457                                 sqlite3_finalize(s->stmt_select_prop);
42458                                 sqlite3_finalize(s->stmt_select_propnames);
42459 +
42460 +                               sqlite3_finalize(s->stmt_read_lock);
42461 +                               sqlite3_finalize(s->stmt_read_lock_by_uri);
42462 +                               sqlite3_finalize(s->stmt_create_lock);
42463 +                               sqlite3_finalize(s->stmt_remove_lock);
42464 +                               sqlite3_finalize(s->stmt_refresh_lock);
42465                                 sqlite3_close(s->sql);
42466                         }
42467 -#endif 
42468 +#endif
42469                         free(s);
42470                 }
42471                 free(p->config_storage);
42472 @@ -135,16 +152,16 @@
42473         buffer_free(p->uri.path_raw);
42474         buffer_free(p->uri.path);
42475         buffer_free(p->uri.authority);
42476 -       
42477 +
42478         buffer_free(p->physical.path);
42479         buffer_free(p->physical.rel_path);
42480         buffer_free(p->physical.doc_root);
42481         buffer_free(p->physical.basedir);
42482 -       
42483 +
42484         buffer_free(p->tmp_buf);
42485 -       
42486 +
42487         free(p);
42488 -       
42489 +
42490         return HANDLER_GO_ON;
42491  }
42492  
42493 @@ -153,32 +170,32 @@
42494  SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
42495         plugin_data *p = p_d;
42496         size_t i = 0;
42497 -       
42498 -       config_values_t cv[] = { 
42499 +
42500 +       config_values_t cv[] = {
42501                 { "webdav.activate",            NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
42502                 { "webdav.is-readonly",         NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
42503                 { "webdav.sqlite-db-name",      NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_CONNECTION },       /* 2 */
42504                 { "webdav.log-xml",             NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
42505                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
42506         };
42507 -       
42508 +
42509         if (!p) return HANDLER_ERROR;
42510 -       
42511 +
42512         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
42513 -       
42514 +
42515         for (i = 0; i < srv->config_context->used; i++) {
42516                 plugin_config *s;
42517 -               
42518 +
42519                 s = calloc(1, sizeof(plugin_config));
42520                 s->sqlite_db_name = buffer_init();
42521 -               
42522 +
42523                 cv[0].destination = &(s->enabled);
42524                 cv[1].destination = &(s->is_readonly);
42525                 cv[2].destination = s->sqlite_db_name;
42526                 cv[3].destination = &(s->log_xml);
42527 -               
42528 +
42529                 p->config_storage[i] = s;
42530 -       
42531 +
42532                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
42533                         return HANDLER_ERROR;
42534                 }
42535 @@ -193,8 +210,26 @@
42536                                 return HANDLER_ERROR;
42537                         }
42538  
42539 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42540 -                               CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"), 
42541 +                       if (SQLITE_OK != sqlite3_exec(s->sql,
42542 +                                       "CREATE TABLE properties ("
42543 +                                       "  resource TEXT NOT NULL,"
42544 +                                       "  prop TEXT NOT NULL,"
42545 +                                       "  ns TEXT NOT NULL,"
42546 +                                       "  value TEXT NOT NULL,"
42547 +                                       "  PRIMARY KEY(resource, prop, ns))",
42548 +                                       NULL, NULL, &err)) {
42549 +
42550 +                               if (0 != strcmp(err, "table properties already exists")) {
42551 +                                       log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
42552 +                                       sqlite3_free(err);
42553 +
42554 +                                       return HANDLER_ERROR;
42555 +                               }
42556 +                               sqlite3_free(err);
42557 +                       }
42558 +
42559 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42560 +                               CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
42561                                 &(s->stmt_select_prop), &next_stmt)) {
42562                                 /* prepare failed */
42563  
42564 @@ -202,8 +237,8 @@
42565                                 return HANDLER_ERROR;
42566                         }
42567  
42568 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42569 -                               CONST_STR_LEN("SELECT ns, prop FROM properties WHERE resource = ?"), 
42570 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42571 +                               CONST_STR_LEN("SELECT ns, prop FROM properties WHERE resource = ?"),
42572                                 &(s->stmt_select_propnames), &next_stmt)) {
42573                                 /* prepare failed */
42574  
42575 @@ -211,16 +246,67 @@
42576                                 return HANDLER_ERROR;
42577                         }
42578  
42579 -                       if (SQLITE_OK != sqlite3_exec(s->sql, 
42580 -                                       "CREATE TABLE properties ("
42581 +
42582 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42583 +                               CONST_STR_LEN("REPLACE INTO properties (resource, prop, ns, value) VALUES (?, ?, ?, ?)"),
42584 +                               &(s->stmt_update_prop), &next_stmt)) {
42585 +                               /* prepare failed */
42586 +
42587 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
42588 +                               return HANDLER_ERROR;
42589 +                       }
42590 +
42591 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42592 +                               CONST_STR_LEN("DELETE FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
42593 +                               &(s->stmt_delete_prop), &next_stmt)) {
42594 +                               /* prepare failed */
42595 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42596 +
42597 +                               return HANDLER_ERROR;
42598 +                       }
42599 +
42600 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42601 +                               CONST_STR_LEN("DELETE FROM properties WHERE resource = ?"),
42602 +                               &(s->stmt_delete_uri), &next_stmt)) {
42603 +                               /* prepare failed */
42604 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42605 +
42606 +                               return HANDLER_ERROR;
42607 +                       }
42608 +
42609 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42610 +                               CONST_STR_LEN("INSERT INTO properties SELECT ?, prop, ns, value FROM properties WHERE resource = ?"),
42611 +                               &(s->stmt_copy_uri), &next_stmt)) {
42612 +                               /* prepare failed */
42613 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42614 +
42615 +                               return HANDLER_ERROR;
42616 +                       }
42617 +
42618 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42619 +                               CONST_STR_LEN("UPDATE properties SET resource = ? WHERE resource = ?"),
42620 +                               &(s->stmt_move_uri), &next_stmt)) {
42621 +                               /* prepare failed */
42622 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42623 +
42624 +                               return HANDLER_ERROR;
42625 +                       }
42626 +
42627 +                       /* LOCKS */
42628 +
42629 +                       if (SQLITE_OK != sqlite3_exec(s->sql,
42630 +                                       "CREATE TABLE locks ("
42631 +                                       "  locktoken TEXT NOT NULL,"
42632                                         "  resource TEXT NOT NULL,"
42633 -                                       "  prop TEXT NOT NULL,"
42634 -                                       "  ns TEXT NOT NULL,"
42635 -                                       "  value TEXT NOT NULL,"
42636 -                                       "  PRIMARY KEY(resource, prop, ns))",
42637 +                                       "  lockscope TEXT NOT NULL,"
42638 +                                       "  locktype TEXT NOT NULL,"
42639 +                                       "  owner TEXT NOT NULL,"
42640 +                                       "  depth INT NOT NULL,"
42641 +                                       "  timeout TIMESTAMP NOT NULL,"
42642 +                                       "  PRIMARY KEY(locktoken))",
42643                                         NULL, NULL, &err)) {
42644  
42645 -                               if (0 != strcmp(err, "table properties already exists")) {
42646 +                               if (0 != strcmp(err, "table locks already exists")) {
42647                                         log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
42648                                         sqlite3_free(err);
42649  
42650 @@ -228,127 +314,138 @@
42651                                 }
42652                                 sqlite3_free(err);
42653                         }
42654 -       
42655 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42656 -                               CONST_STR_LEN("REPLACE INTO properties (resource, prop, ns, value) VALUES (?, ?, ?, ?)"), 
42657 -                               &(s->stmt_update_prop), &next_stmt)) {
42658 +
42659 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42660 +                               CONST_STR_LEN("INSERT INTO locks (locktoken, resource, lockscope, locktype, owner, depth, timeout) VALUES (?,?,?,?,?,?, CURRENT_TIME + 600)"),
42661 +                               &(s->stmt_create_lock), &next_stmt)) {
42662                                 /* prepare failed */
42663 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42664  
42665 -                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
42666                                 return HANDLER_ERROR;
42667                         }
42668  
42669 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42670 -                               CONST_STR_LEN("DELETE FROM properties WHERE resource = ? AND prop = ? AND ns = ?"), 
42671 -                               &(s->stmt_delete_prop), &next_stmt)) {
42672 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42673 +                               CONST_STR_LEN("DELETE FROM locks WHERE locktoken = ?"),
42674 +                               &(s->stmt_remove_lock), &next_stmt)) {
42675                                 /* prepare failed */
42676                                 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42677  
42678                                 return HANDLER_ERROR;
42679                         }
42680  
42681 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42682 -                               CONST_STR_LEN("DELETE FROM properties WHERE resource = ?"), 
42683 -                               &(s->stmt_delete_uri), &next_stmt)) {
42684 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42685 +                               CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout FROM locks WHERE locktoken = ?"),
42686 +                               &(s->stmt_read_lock), &next_stmt)) {
42687                                 /* prepare failed */
42688                                 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42689  
42690                                 return HANDLER_ERROR;
42691                         }
42692  
42693 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42694 -                               CONST_STR_LEN("INSERT INTO properties SELECT ?, prop, ns, value FROM properties WHERE resource = ?"), 
42695 -                               &(s->stmt_copy_uri), &next_stmt)) {
42696 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42697 +                               CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout FROM locks WHERE resource = ?"),
42698 +                               &(s->stmt_read_lock_by_uri), &next_stmt)) {
42699                                 /* prepare failed */
42700                                 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42701  
42702                                 return HANDLER_ERROR;
42703                         }
42704  
42705 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42706 -                               CONST_STR_LEN("UPDATE properties SET resource = ? WHERE resource = ?"), 
42707 -                               &(s->stmt_move_uri), &next_stmt)) {
42708 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42709 +                               CONST_STR_LEN("UPDATE locks SET timeout = CURRENT_TIME + 600 WHERE locktoken = ?"),
42710 +                               &(s->stmt_refresh_lock), &next_stmt)) {
42711                                 /* prepare failed */
42712                                 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42713  
42714                                 return HANDLER_ERROR;
42715                         }
42716 +
42717 +
42718  #else
42719                         log_error_write(srv, __FILE__, __LINE__, "s", "Sorry, no sqlite3 and libxml2 support include, compile with --with-webdav-props");
42720                         return HANDLER_ERROR;
42721  #endif
42722                 }
42723         }
42724 -       
42725 +
42726         return HANDLER_GO_ON;
42727  }
42728  
42729 -#define PATCH(x) \
42730 -       p->conf.x = s->x;
42731  static int mod_webdav_patch_connection(server *srv, connection *con, plugin_data *p) {
42732         size_t i, j;
42733         plugin_config *s = p->config_storage[0];
42734 -       
42735 -       PATCH(enabled);
42736 -       PATCH(is_readonly);
42737 -       PATCH(log_xml);
42738 -       
42739 +
42740 +       PATCH_OPTION(enabled);
42741 +       PATCH_OPTION(is_readonly);
42742 +       PATCH_OPTION(log_xml);
42743 +
42744  #ifdef USE_PROPPATCH
42745 -       PATCH(sql);
42746 -       PATCH(stmt_update_prop);
42747 -       PATCH(stmt_delete_prop);
42748 -       PATCH(stmt_select_prop);
42749 -       PATCH(stmt_select_propnames);
42750 -
42751 -       PATCH(stmt_delete_uri);
42752 -       PATCH(stmt_move_uri);
42753 -       PATCH(stmt_copy_uri);
42754 +       PATCH_OPTION(sql);
42755 +       PATCH_OPTION(stmt_update_prop);
42756 +       PATCH_OPTION(stmt_delete_prop);
42757 +       PATCH_OPTION(stmt_select_prop);
42758 +       PATCH_OPTION(stmt_select_propnames);
42759 +
42760 +       PATCH_OPTION(stmt_delete_uri);
42761 +       PATCH_OPTION(stmt_move_uri);
42762 +       PATCH_OPTION(stmt_copy_uri);
42763 +
42764 +       PATCH_OPTION(stmt_remove_lock);
42765 +       PATCH_OPTION(stmt_refresh_lock);
42766 +       PATCH_OPTION(stmt_create_lock);
42767 +       PATCH_OPTION(stmt_read_lock);
42768 +       PATCH_OPTION(stmt_read_lock_by_uri);
42769  #endif
42770         /* skip the first, the global context */
42771         for (i = 1; i < srv->config_context->used; i++) {
42772                 data_config *dc = (data_config *)srv->config_context->data[i];
42773                 s = p->config_storage[i];
42774 -               
42775 +
42776                 /* condition didn't match */
42777                 if (!config_check_cond(srv, con, dc)) continue;
42778 -               
42779 +
42780                 /* merge config */
42781                 for (j = 0; j < dc->value->used; j++) {
42782                         data_unset *du = dc->value->data[j];
42783 -                       
42784 +
42785                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.activate"))) {
42786 -                               PATCH(enabled);
42787 +                               PATCH_OPTION(enabled);
42788                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.is-readonly"))) {
42789 -                               PATCH(is_readonly);
42790 +                               PATCH_OPTION(is_readonly);
42791                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.log-xml"))) {
42792 -                               PATCH(log_xml);
42793 +                               PATCH_OPTION(log_xml);
42794                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.sqlite-db-name"))) {
42795  #ifdef USE_PROPPATCH
42796 -                               PATCH(sql);
42797 -                               PATCH(stmt_update_prop);
42798 -                               PATCH(stmt_delete_prop);
42799 -                               PATCH(stmt_select_prop);
42800 -                               PATCH(stmt_select_propnames);
42801 -                               
42802 -                               PATCH(stmt_delete_uri);
42803 -                               PATCH(stmt_move_uri);
42804 -                               PATCH(stmt_copy_uri);
42805 +                               PATCH_OPTION(sql);
42806 +                               PATCH_OPTION(stmt_update_prop);
42807 +                               PATCH_OPTION(stmt_delete_prop);
42808 +                               PATCH_OPTION(stmt_select_prop);
42809 +                               PATCH_OPTION(stmt_select_propnames);
42810 +
42811 +                               PATCH_OPTION(stmt_delete_uri);
42812 +                               PATCH_OPTION(stmt_move_uri);
42813 +                               PATCH_OPTION(stmt_copy_uri);
42814 +
42815 +                               PATCH_OPTION(stmt_remove_lock);
42816 +                               PATCH_OPTION(stmt_refresh_lock);
42817 +                               PATCH_OPTION(stmt_create_lock);
42818 +                               PATCH_OPTION(stmt_read_lock);
42819 +                               PATCH_OPTION(stmt_read_lock_by_uri);
42820  #endif
42821                         }
42822                 }
42823         }
42824 -       
42825 +
42826         return 0;
42827  }
42828 -#undef PATCH
42829  
42830  URIHANDLER_FUNC(mod_webdav_uri_handler) {
42831         plugin_data *p = p_d;
42832 -       
42833 +
42834         UNUSED(srv);
42835  
42836         if (con->uri.path->used == 0) return HANDLER_GO_ON;
42837 -       
42838 +
42839         mod_webdav_patch_connection(srv, con, p);
42840  
42841         if (!p->conf.enabled) return HANDLER_GO_ON;
42842 @@ -362,20 +459,20 @@
42843                 if (p->conf.is_readonly) {
42844                         response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND"));
42845                 } else {
42846 -                       response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH"));
42847 +                       response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH, LOCK, UNLOCK"));
42848                 }
42849                 break;
42850         default:
42851                 break;
42852         }
42853 -       
42854 +
42855         /* not found */
42856         return HANDLER_GO_ON;
42857  }
42858 -static int webdav_gen_prop_tag(server *srv, connection *con, 
42859 -               char *prop_name, 
42860 -               char *prop_ns, 
42861 -               char *value, 
42862 +static int webdav_gen_prop_tag(server *srv, connection *con,
42863 +               char *prop_name,
42864 +               char *prop_ns,
42865 +               char *value,
42866                 buffer *b) {
42867  
42868         UNUSED(srv);
42869 @@ -414,7 +511,7 @@
42870         buffer_append_string_buffer(b, dst->rel_path);
42871         buffer_append_string(b,"</D:href>\n");
42872         buffer_append_string(b,"<D:status>\n");
42873 -       
42874 +
42875         if (con->request.http_version == HTTP_VERSION_1_1) {
42876                 BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 ");
42877         } else {
42878 @@ -458,14 +555,13 @@
42879  
42880                         /* bind the values to the insert */
42881  
42882 -                       sqlite3_bind_text(stmt, 1, 
42883 -                                         dst->rel_path->ptr, 
42884 +                       sqlite3_bind_text(stmt, 1,
42885 +                                         dst->rel_path->ptr,
42886                                           dst->rel_path->used - 1,
42887                                           SQLITE_TRANSIENT);
42888 -                                                                       
42889 +
42890                         if (SQLITE_DONE != sqlite3_step(stmt)) {
42891                                 /* */
42892 -                               WP();
42893                         }
42894                 }
42895  #endif
42896 @@ -493,14 +589,14 @@
42897                             (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
42898                                 continue;
42899                                 /* ignore the parent dir */
42900 -                       } 
42901 +                       }
42902  
42903                         buffer_copy_string_buffer(d.path, dst->path);
42904 -                       BUFFER_APPEND_SLASH(d.path);
42905 +                       PATHNAME_APPEND_SLASH(d.path);
42906                         buffer_append_string(d.path, de->d_name);
42907 -                       
42908 +
42909                         buffer_copy_string_buffer(d.rel_path, dst->rel_path);
42910 -                       BUFFER_APPEND_SLASH(d.rel_path);
42911 +                       PATHNAME_APPEND_SLASH(d.rel_path);
42912                         buffer_append_string(d.rel_path, de->d_name);
42913  
42914                         /* stat and unlink afterwards */
42915 @@ -508,7 +604,7 @@
42916                                 /* don't about it yet, rmdir will fail too */
42917                         } else if (S_ISDIR(st.st_mode)) {
42918                                 have_multi_status = webdav_delete_dir(srv, con, p, &d, b);
42919 -                                       
42920 +
42921                                 /* try to unlink it */
42922                                 if (-1 == rmdir(d.path->ptr)) {
42923                                         switch(errno) {
42924 @@ -535,14 +631,13 @@
42925  
42926                                                 /* bind the values to the insert */
42927  
42928 -                                               sqlite3_bind_text(stmt, 1, 
42929 -                                                                 d.rel_path->ptr, 
42930 +                                               sqlite3_bind_text(stmt, 1,
42931 +                                                                 d.rel_path->ptr,
42932                                                                   d.rel_path->used - 1,
42933                                                                   SQLITE_TRANSIENT);
42934 -                                                                                                       
42935 +
42936                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {
42937                                                         /* */
42938 -                                                       WP();
42939                                                 }
42940                                         }
42941  #endif
42942 @@ -569,7 +664,7 @@
42943         if (stream_open(&s, src->path)) {
42944                 return 403;
42945         }
42946 -                       
42947 +
42948         if (-1 == (ofd = open(dst->path->ptr, O_WRONLY|O_TRUNC|O_CREAT|(overwrite ? 0 : O_EXCL), 0600))) {
42949                 /* opening the destination failed for some reason */
42950                 switch(errno) {
42951 @@ -601,7 +696,7 @@
42952                         break;
42953                 }
42954         }
42955 -       
42956 +
42957         stream_close(&s);
42958         close(ofd);
42959  
42960 @@ -614,19 +709,18 @@
42961                         sqlite3_reset(stmt);
42962  
42963                         /* bind the values to the insert */
42964 -                       sqlite3_bind_text(stmt, 1, 
42965 -                                         dst->rel_path->ptr, 
42966 +                       sqlite3_bind_text(stmt, 1,
42967 +                                         dst->rel_path->ptr,
42968                                           dst->rel_path->used - 1,
42969                                           SQLITE_TRANSIENT);
42970  
42971 -                       sqlite3_bind_text(stmt, 2, 
42972 -                                         src->rel_path->ptr, 
42973 +                       sqlite3_bind_text(stmt, 2,
42974 +                                         src->rel_path->ptr,
42975                                           src->rel_path->used - 1,
42976                                           SQLITE_TRANSIENT);
42977 -                                                                                                       
42978 +
42979                         if (SQLITE_DONE != sqlite3_step(stmt)) {
42980                                 /* */
42981 -                               WP();
42982                         }
42983                 }
42984         }
42985 @@ -655,21 +749,21 @@
42986                             (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
42987                                 continue;
42988                         }
42989 -                       
42990 +
42991                         buffer_copy_string_buffer(s.path, src->path);
42992 -                       BUFFER_APPEND_SLASH(s.path);
42993 +                       PATHNAME_APPEND_SLASH(s.path);
42994                         buffer_append_string(s.path, de->d_name);
42995  
42996                         buffer_copy_string_buffer(d.path, dst->path);
42997 -                       BUFFER_APPEND_SLASH(d.path);
42998 +                       PATHNAME_APPEND_SLASH(d.path);
42999                         buffer_append_string(d.path, de->d_name);
43000  
43001                         buffer_copy_string_buffer(s.rel_path, src->rel_path);
43002 -                       BUFFER_APPEND_SLASH(s.rel_path);
43003 +                       PATHNAME_APPEND_SLASH(s.rel_path);
43004                         buffer_append_string(s.rel_path, de->d_name);
43005  
43006                         buffer_copy_string_buffer(d.rel_path, dst->rel_path);
43007 -                       BUFFER_APPEND_SLASH(d.rel_path);
43008 +                       PATHNAME_APPEND_SLASH(d.rel_path);
43009                         buffer_append_string(d.rel_path, de->d_name);
43010  
43011                         if (-1 == stat(s.path->ptr, &st)) {
43012 @@ -692,19 +786,18 @@
43013                                                 sqlite3_reset(stmt);
43014  
43015                                                 /* bind the values to the insert */
43016 -                                               sqlite3_bind_text(stmt, 1, 
43017 -                                                         dst->rel_path->ptr, 
43018 +                                               sqlite3_bind_text(stmt, 1,
43019 +                                                         dst->rel_path->ptr,
43020                                                           dst->rel_path->used - 1,
43021                                                           SQLITE_TRANSIENT);
43022  
43023 -                                               sqlite3_bind_text(stmt, 2, 
43024 -                                                         src->rel_path->ptr, 
43025 +                                               sqlite3_bind_text(stmt, 2,
43026 +                                                         src->rel_path->ptr,
43027                                                           src->rel_path->used - 1,
43028                                                           SQLITE_TRANSIENT);
43029 -                                                                                                       
43030 +
43031                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {
43032                                                         /* */
43033 -                                                       WP();
43034                                                 }
43035                                         }
43036  #endif
43037 @@ -721,7 +814,7 @@
43038                 buffer_free(s.rel_path);
43039                 buffer_free(d.path);
43040                 buffer_free(d.rel_path);
43041 -               
43042 +
43043                 closedir(srcdir);
43044         }
43045  
43046 @@ -748,12 +841,12 @@
43047                         if (S_ISDIR(sce->st.st_mode)) {
43048                                 buffer_append_string(b, "<D:getcontenttype>httpd/unix-directory</D:getcontenttype>");
43049                                 found = 1;
43050 -                       } else if(S_ISREG(sce->st.st_mode)) { 
43051 +                       } else if(S_ISREG(sce->st.st_mode)) {
43052                                 for (k = 0; k < con->conf.mimetypes->used; k++) {
43053                                         data_string *ds = (data_string *)con->conf.mimetypes->data[k];
43054 -               
43055 +
43056                                         if (ds->key->used == 0) continue;
43057 -                               
43058 +
43059                                         if (buffer_is_equal_right_len(dst->path, ds->key, ds->key->used - 1)) {
43060                                                 buffer_append_string(b,"<D:getcontenttype>");
43061                                                 buffer_append_string_buffer(b, ds->value);
43062 @@ -807,23 +900,23 @@
43063  
43064                         /* bind the values to the insert */
43065  
43066 -                       sqlite3_bind_text(stmt, 1, 
43067 -                                         dst->rel_path->ptr, 
43068 +                       sqlite3_bind_text(stmt, 1,
43069 +                                         dst->rel_path->ptr,
43070                                           dst->rel_path->used - 1,
43071                                           SQLITE_TRANSIENT);
43072 -                       sqlite3_bind_text(stmt, 2, 
43073 +                       sqlite3_bind_text(stmt, 2,
43074                                           prop_name,
43075                                           strlen(prop_name),
43076                                           SQLITE_TRANSIENT);
43077 -                       sqlite3_bind_text(stmt, 3, 
43078 +                       sqlite3_bind_text(stmt, 3,
43079                                           prop_ns,
43080                                           strlen(prop_ns),
43081                                           SQLITE_TRANSIENT);
43082  
43083                         /* it is the PK */
43084 -                       while (SQLITE_ROW == sqlite3_step(p->conf.stmt_select_prop)) {
43085 +                       while (SQLITE_ROW == sqlite3_step(stmt)) {
43086                                 /* there is a row for us, we only expect a single col 'value' */
43087 -                               webdav_gen_prop_tag(srv, con, prop_name, prop_ns, (char *)sqlite3_column_text(p->conf.stmt_select_prop, 0), b);
43088 +                               webdav_gen_prop_tag(srv, con, prop_name, prop_ns, (char *)sqlite3_column_text(stmt, 0), b);
43089                                 found = 1;
43090                         }
43091                 }
43092 @@ -840,7 +933,7 @@
43093         char *prop;
43094  } webdav_property;
43095  
43096 -webdav_property live_properties[] = { 
43097 +webdav_property live_properties[] = {
43098         { "DAV:", "creationdate" },
43099         { "DAV:", "displayname" },
43100         { "DAV:", "getcontentlanguage" },
43101 @@ -871,8 +964,8 @@
43102                         webdav_property *prop;
43103  
43104                         prop = props->ptr[i];
43105 -                       
43106 -                       if (0 != webdav_get_property(srv, con, p, 
43107 +
43108 +                       if (0 != webdav_get_property(srv, con, p,
43109                                 dst, prop->prop, prop->ns, b_200)) {
43110                                 webdav_gen_prop_tag(srv, con, prop->prop, prop->ns, NULL, b_404);
43111                         }
43112 @@ -916,12 +1009,12 @@
43113                                 if (-1 == c->file.fd &&  /* open the file if not already open */
43114                                     -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
43115                                         log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
43116 -               
43117 +
43118                                         return -1;
43119                                 }
43120 -       
43121 +
43122                                 if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
43123 -                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ", 
43124 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
43125                                                         strerror(errno), c->file.name,  c->file.fd);
43126  
43127                                         return -1;
43128 @@ -938,7 +1031,7 @@
43129                         if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->file.mmap.start + c->offset, weHave, 0))) {
43130                                 log_error_write(srv, __FILE__, __LINE__, "sddd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
43131                         }
43132 -                       
43133 +
43134                         c->offset += weHave;
43135                         cq->bytes_out += weHave;
43136  
43137 @@ -956,7 +1049,7 @@
43138                         if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->mem->ptr + c->offset, weHave, 0))) {
43139                                 log_error_write(srv, __FILE__, __LINE__, "sddd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
43140                         }
43141 -                       
43142 +
43143                         c->offset += weHave;
43144                         cq->bytes_out += weHave;
43145  
43146 @@ -991,6 +1084,113 @@
43147  }
43148  #endif
43149  
43150 +int webdav_lockdiscovery(server *srv, connection *con,
43151 +               buffer *locktoken, const char *lockscope, const char *locktype, int depth) {
43152 +
43153 +       buffer *b;
43154 +
43155 +       response_header_overwrite(srv, con, CONST_STR_LEN("Lock-Token"), CONST_BUF_LEN(locktoken));
43156 +
43157 +       response_header_overwrite(srv, con,
43158 +               CONST_STR_LEN("Content-Type"),
43159 +               CONST_STR_LEN("text/xml; charset=\"utf-8\""));
43160 +
43161 +       b = chunkqueue_get_append_buffer(con->write_queue);
43162 +
43163 +       buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
43164 +
43165 +       buffer_append_string(b,"<D:prop xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n");
43166 +       buffer_append_string(b,"<D:lockdiscovery>\n");
43167 +       buffer_append_string(b,"<D:activelock>\n");
43168 +
43169 +       buffer_append_string(b,"<D:lockscope>");
43170 +       buffer_append_string(b,"<D:");
43171 +       buffer_append_string(b, lockscope);
43172 +       buffer_append_string(b, "/>");
43173 +       buffer_append_string(b,"</D:lockscope>\n");
43174 +
43175 +       buffer_append_string(b,"<D:locktype>");
43176 +       buffer_append_string(b,"<D:");
43177 +       buffer_append_string(b, locktype);
43178 +       buffer_append_string(b, "/>");
43179 +       buffer_append_string(b,"</D:locktype>\n");
43180 +
43181 +       buffer_append_string(b,"<D:depth>");
43182 +       buffer_append_string(b, depth == 0 ? "0" : "infinity");
43183 +       buffer_append_string(b,"</D:depth>\n");
43184 +
43185 +       buffer_append_string(b,"<D:timeout>");
43186 +       buffer_append_string(b, "Second-600");
43187 +       buffer_append_string(b,"</D:timeout>\n");
43188 +
43189 +       buffer_append_string(b,"<D:owner>");
43190 +       buffer_append_string(b,"</D:owner>\n");
43191 +
43192 +       buffer_append_string(b,"<D:locktoken>");
43193 +       buffer_append_string(b, "<D:href>");
43194 +       buffer_append_string_buffer(b, locktoken);
43195 +       buffer_append_string(b, "</D:href>");
43196 +       buffer_append_string(b,"</D:locktoken>\n");
43197 +
43198 +       buffer_append_string(b,"</D:activelock>\n");
43199 +       buffer_append_string(b,"</D:lockdiscovery>\n");
43200 +       buffer_append_string(b,"</D:prop>\n");
43201 +
43202 +       return 0;
43203 +}
43204 +/**
43205 + * check if resource is having the right locks to access to resource
43206 + *
43207 + *
43208 + *
43209 + */
43210 +int webdav_has_lock(server *srv, connection *con, plugin_data *p, buffer *uri) {
43211 +       int has_lock = 1;
43212 +
43213 +#ifdef USE_LOCKS
43214 +       data_string *ds;
43215 +
43216 +       /**
43217 +        * If can have
43218 +        * - <lock-token>
43219 +        * - [etag]
43220 +        *
43221 +        * there is NOT, AND and OR
43222 +        * and a list can be tagged
43223 +        *
43224 +        * (<lock-token>) is untagged
43225 +        * <tag> (<lock-token>) is tagged
43226 +        *
43227 +        * as long as we don't handle collections it is simple. :)
43228 +        *
43229 +        * X-Litmus: locks: 11 (owner_modify)
43230 +        * If: <http://127.0.0.1:1025/dav/litmus/lockme> (<opaquelocktoken:2165478d-0611-49c4-be92-e790d68a38f1>)
43231 +        *
43232 +        * X-Litmus: locks: 16 (fail_cond_put)
43233 +        * If: (<DAV:no-lock> ["-1622396671"])
43234 +        */
43235 +       if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
43236 +       } else {
43237 +               /* we didn't provided a lock-token -> */
43238 +               /* if the resource is locked -> 423 */
43239 +
43240 +               sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
43241 +
43242 +               sqlite3_reset(stmt);
43243 +
43244 +               sqlite3_bind_text(stmt, 1,
43245 +                         CONST_BUF_LEN(uri),
43246 +                         SQLITE_TRANSIENT);
43247 +
43248 +               while (SQLITE_ROW == sqlite3_step(stmt)) {
43249 +                       has_lock = 0;
43250 +               }
43251 +       }
43252 +#endif
43253 +
43254 +       return has_lock;
43255 +}
43256 +
43257  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
43258         plugin_data *p = p_d;
43259         buffer *b;
43260 @@ -1001,7 +1201,8 @@
43261         buffer *prop_200;
43262         buffer *prop_404;
43263         webdav_properties *req_props;
43264 -       
43265 +       stat_cache_entry *sce = NULL;
43266 +
43267         UNUSED(srv);
43268  
43269         if (!p->conf.enabled) return HANDLER_GO_ON;
43270 @@ -1019,7 +1220,19 @@
43271                 req_props = NULL;
43272  
43273                 /* is there a content-body ? */
43274 -       
43275 +
43276 +               switch (stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
43277 +               case HANDLER_ERROR:
43278 +                       if (errno == ENOENT) {
43279 +                               con->http_status = 404;
43280 +                               return HANDLER_FINISHED;
43281 +                       }
43282 +                       break;
43283 +               default:
43284 +                       break;
43285 +               }
43286 +
43287 +
43288  #ifdef USE_PROPPATCH
43289                 /* any special requests or just allprop ? */
43290                 if (con->request.content_length) {
43291 @@ -1087,14 +1300,13 @@
43292                                                                 /* get all property names (EMPTY) */
43293                                                                 sqlite3_reset(stmt);
43294                                                                 /* bind the values to the insert */
43295 -       
43296 -                                                               sqlite3_bind_text(stmt, 1, 
43297 -                                                                                 con->uri.path->ptr, 
43298 +
43299 +                                                               sqlite3_bind_text(stmt, 1,
43300 +                                                                                 con->uri.path->ptr,
43301                                                                                   con->uri.path->used - 1,
43302                                                                                   SQLITE_TRANSIENT);
43303 -                                               
43304 +
43305                                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {
43306 -                                                                       WP();
43307                                                                 }
43308                                                         }
43309                                                 } else if (0 == xmlStrcmp(cmd->name, BAD_CAST "allprop")) {
43310 @@ -1115,13 +1327,13 @@
43311                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
43312  
43313                 b = chunkqueue_get_append_buffer(con->write_queue);
43314 -                               
43315 +
43316                 buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
43317  
43318                 buffer_append_string(b,"<D:multistatus xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n");
43319  
43320                 /* allprop */
43321 -               
43322 +
43323                 prop_200 = buffer_init();
43324                 prop_404 = buffer_init();
43325  
43326 @@ -1129,7 +1341,7 @@
43327                 case 0:
43328                         /* Depth: 0 */
43329                         webdav_get_props(srv, con, p, &(con->physical), req_props, prop_200, prop_404);
43330 -       
43331 +
43332                         buffer_append_string(b,"<D:response>\n");
43333                         buffer_append_string(b,"<D:href>");
43334                         buffer_append_string_buffer(b, con->uri.scheme);
43335 @@ -1145,9 +1357,9 @@
43336                                 buffer_append_string_buffer(b, prop_200);
43337  
43338                                 buffer_append_string(b,"</D:prop>\n");
43339 -       
43340 +
43341                                 buffer_append_string(b,"<D:status>HTTP/1.1 200 OK</D:status>\n");
43342 -       
43343 +
43344                                 buffer_append_string(b,"</D:propstat>\n");
43345                         }
43346                         if (!buffer_is_empty(prop_404)) {
43347 @@ -1157,16 +1369,16 @@
43348                                 buffer_append_string_buffer(b, prop_404);
43349  
43350                                 buffer_append_string(b,"</D:prop>\n");
43351 -       
43352 +
43353                                 buffer_append_string(b,"<D:status>HTTP/1.1 404 Not Found</D:status>\n");
43354 -       
43355 +
43356                                 buffer_append_string(b,"</D:propstat>\n");
43357                         }
43358  
43359                         buffer_append_string(b,"</D:response>\n");
43360  
43361                         break;
43362 -               case 1: 
43363 +               case 1:
43364                         if (NULL != (dir = opendir(con->physical.path->ptr))) {
43365                                 struct dirent *de;
43366                                 physical d;
43367 @@ -1179,16 +1391,16 @@
43368                                         if (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0') {
43369                                                 continue;
43370                                                 /* ignore the parent dir */
43371 -                                       } 
43372 +                                       }
43373  
43374                                         buffer_copy_string_buffer(d.path, dst->path);
43375 -                                       BUFFER_APPEND_SLASH(d.path);
43376 +                                       PATHNAME_APPEND_SLASH(d.path);
43377  
43378                                         buffer_copy_string_buffer(d.rel_path, dst->rel_path);
43379 -                                       BUFFER_APPEND_SLASH(d.rel_path);
43380 +                                       PATHNAME_APPEND_SLASH(d.rel_path);
43381  
43382                                         if (de->d_name[0] == '.' && de->d_name[1] == '\0') {
43383 -                                               /* don't append the . */ 
43384 +                                               /* don't append the . */
43385                                         } else {
43386                                                 buffer_append_string(d.path, de->d_name);
43387                                                 buffer_append_string(d.rel_path, de->d_name);
43388 @@ -1198,7 +1410,7 @@
43389                                         buffer_reset(prop_404);
43390  
43391                                         webdav_get_props(srv, con, p, &d, req_props, prop_200, prop_404);
43392 -                                       
43393 +
43394                                         buffer_append_string(b,"<D:response>\n");
43395                                         buffer_append_string(b,"<D:href>");
43396                                         buffer_append_string_buffer(b, con->uri.scheme);
43397 @@ -1214,9 +1426,9 @@
43398                                                 buffer_append_string_buffer(b, prop_200);
43399  
43400                                                 buffer_append_string(b,"</D:prop>\n");
43401 -                       
43402 +
43403                                                 buffer_append_string(b,"<D:status>HTTP/1.1 200 OK</D:status>\n");
43404 -                       
43405 +
43406                                                 buffer_append_string(b,"</D:propstat>\n");
43407                                         }
43408                                         if (!buffer_is_empty(prop_404)) {
43409 @@ -1226,9 +1438,9 @@
43410                                                 buffer_append_string_buffer(b, prop_404);
43411  
43412                                                 buffer_append_string(b,"</D:prop>\n");
43413 -       
43414 +
43415                                                 buffer_append_string(b,"<D:status>HTTP/1.1 404 Not Found</D:status>\n");
43416 -       
43417 +
43418                                                 buffer_append_string(b,"</D:propstat>\n");
43419                                         }
43420  
43421 @@ -1275,7 +1487,7 @@
43422  
43423                         return HANDLER_FINISHED;
43424                 }
43425 -       
43426 +
43427                 /* let's create the directory */
43428  
43429                 if (-1 == mkdir(con->physical.path->ptr, 0700)) {
43430 @@ -1303,7 +1515,13 @@
43431                         con->http_status = 403;
43432                         return HANDLER_FINISHED;
43433                 }
43434 -               
43435 +
43436 +               /* does the client have a lock for this connection ? */
43437 +               if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43438 +                       con->http_status = 423;
43439 +                       return HANDLER_FINISHED;
43440 +               }
43441 +
43442                 /* stat and unlink afterwards */
43443                 if (-1 == stat(con->physical.path->ptr, &st)) {
43444                         /* don't about it yet, unlink will fail too */
43445 @@ -1323,7 +1541,7 @@
43446                                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
43447  
43448                                 b = chunkqueue_get_append_buffer(con->write_queue);
43449 -                       
43450 +
43451                                 buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
43452  
43453                                 buffer_append_string(b,"<D:multistatus xmlns:D=\"DAV:\">\n");
43454 @@ -1331,7 +1549,7 @@
43455                                 buffer_append_string_buffer(b, multi_status_resp);
43456  
43457                                 buffer_append_string(b,"</D:multistatus>\n");
43458 -                       
43459 +
43460                                 if (p->conf.log_xml) {
43461                                         log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b);
43462                                 }
43463 @@ -1340,7 +1558,7 @@
43464                                 con->file_finished = 1;
43465                         } else {
43466                                 /* everything went fine, remove the directory */
43467 -       
43468 +
43469                                 if (-1 == rmdir(con->physical.path->ptr)) {
43470                                         switch(errno) {
43471                                         case ENOENT:
43472 @@ -1375,97 +1593,174 @@
43473         case HTTP_METHOD_PUT: {
43474                 int fd;
43475                 chunkqueue *cq = con->request_content_queue;
43476 +               chunk *c;
43477 +               data_string *ds_range;
43478  
43479                 if (p->conf.is_readonly) {
43480                         con->http_status = 403;
43481                         return HANDLER_FINISHED;
43482                 }
43483  
43484 +               /* is a exclusive lock set on the source */
43485 +               if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43486 +                       con->http_status = 423;
43487 +                       return HANDLER_FINISHED;
43488 +               }
43489 +
43490 +
43491                 assert(chunkqueue_length(cq) == (off_t)con->request.content_length);
43492  
43493 -               /* taken what we have in the request-body and write it to a file */
43494 -               if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC, 0600))) {
43495 -                       /* we can't open the file */
43496 -                       con->http_status = 403;
43497 -               } else {
43498 -                       chunk *c;
43499 +               /* RFC2616 Section 9.6 PUT requires us to send 501 on all Content-* we don't support
43500 +                * - most important Content-Range
43501 +                *
43502 +                *
43503 +                * Example: Content-Range: bytes 100-1037/1038 */
43504  
43505 -                       con->http_status = 201; /* created */
43506 -                       con->file_finished = 1;
43507 +               if (NULL != (ds_range = (data_string *)array_get_element(con->request.headers, "Content-Range"))) {
43508 +                       const char *num = ds_range->value->ptr;
43509 +                       off_t offset;
43510 +                       char *err = NULL;
43511  
43512 -                       for (c = cq->first; c; c = cq->first) {
43513 -                               int r = 0; 
43514 +                       if (0 != strncmp(num, "bytes ", 6)) {
43515 +                               con->http_status = 501; /* not implemented */
43516  
43517 -                               /* copy all chunks */
43518 -                               switch(c->type) {
43519 -                               case FILE_CHUNK:
43520 -
43521 -                                       if (c->file.mmap.start == MAP_FAILED) {
43522 -                                               if (-1 == c->file.fd &&  /* open the file if not already open */
43523 -                                                   -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
43524 -                                                       log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
43525 -                                       
43526 -                                                       return -1;
43527 -                                               }
43528 -                               
43529 -                                               if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
43530 -                                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ", 
43531 -                                                                       strerror(errno), c->file.name,  c->file.fd);
43532 +                               return HANDLER_FINISHED;
43533 +                       }
43534  
43535 -                                                       return -1;
43536 -                                               }
43537 +                       /* we only support <num>- ... */
43538  
43539 -                                               c->file.mmap.length = c->file.length;
43540 +                       num += 6;
43541  
43542 -                                               close(c->file.fd);
43543 -                                               c->file.fd = -1;
43544 -       
43545 -                                               /* chunk_reset() or chunk_free() will cleanup for us */
43546 -                                       }
43547 -
43548 -                                       if ((r = write(fd, c->file.mmap.start + c->offset, c->file.length - c->offset)) < 0) {
43549 -                                               switch(errno) {
43550 -                                               case ENOSPC:
43551 -                                                       con->http_status = 507;
43552 -               
43553 -                                                       break;
43554 -                                               default:
43555 -                                                       con->http_status = 403;
43556 -                                                       break;
43557 -                                               }
43558 -                                       }
43559 -                                       break;
43560 -                               case MEM_CHUNK:
43561 -                                       if ((r = write(fd, c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) {
43562 -                                               switch(errno) {
43563 -                                               case ENOSPC:
43564 -                                                       con->http_status = 507;
43565 -               
43566 -                                                       break;
43567 -                                               default:
43568 -                                                       con->http_status = 403;
43569 -                                                       break;
43570 -                                               }
43571 -                                       }
43572 +                       /* skip WS */
43573 +                       while (*num == ' ' || *num == '\t') num++;
43574 +
43575 +                       if (*num == '\0') {
43576 +                               con->http_status = 501; /* not implemented */
43577 +
43578 +                               return HANDLER_FINISHED;
43579 +                       }
43580 +
43581 +                       offset = strtoll(num, &err, 10);
43582 +
43583 +                       if (*err != '-' || offset < 0) {
43584 +                               con->http_status = 501; /* not implemented */
43585 +
43586 +                               return HANDLER_FINISHED;
43587 +                       }
43588 +
43589 +                       if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY, 0600))) {
43590 +                               switch (errno) {
43591 +                               case ENOENT:
43592 +                                       con->http_status = 404; /* not found */
43593                                         break;
43594 -                               case UNUSED_CHUNK:
43595 +                               default:
43596 +                                       con->http_status = 403; /* not found */
43597                                         break;
43598                                 }
43599 +                               return HANDLER_FINISHED;
43600 +                       }
43601 +
43602 +                       if (-1 == lseek(fd, offset, SEEK_SET)) {
43603 +                               con->http_status = 501; /* not implemented */
43604 +
43605 +                               close(fd);
43606 +
43607 +                               return HANDLER_FINISHED;
43608 +                       }
43609 +                       con->http_status = 200; /* modified */
43610 +               } else {
43611 +                       /* take what we have in the request-body and write it to a file */
43612 +
43613 +                       /* if the file doesn't exist, create it */
43614 +                       if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_TRUNC, 0600))) {
43615 +                               if (errno == ENOENT &&
43616 +                                   -1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0600))) {
43617 +                                       /* we can't open the file */
43618 +                                       con->http_status = 403;
43619  
43620 -                               if (r > 0) {
43621 -                                       c->offset += r;
43622 -                                       cq->bytes_out += r;
43623 +                                       return HANDLER_FINISHED;
43624                                 } else {
43625 -                                       break;
43626 +                                       con->http_status = 201; /* created */
43627 +                               }
43628 +                       } else {
43629 +                               con->http_status = 200; /* modified */
43630 +                       }
43631 +               }
43632 +
43633 +               con->file_finished = 1;
43634 +
43635 +               for (c = cq->first; c; c = cq->first) {
43636 +                       int r = 0;
43637 +
43638 +                       /* copy all chunks */
43639 +                       switch(c->type) {
43640 +                       case FILE_CHUNK:
43641 +
43642 +                               if (c->file.mmap.start == MAP_FAILED) {
43643 +                                       if (-1 == c->file.fd &&  /* open the file if not already open */
43644 +                                           -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
43645 +                                               log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
43646 +
43647 +                                               return -1;
43648 +                                       }
43649 +
43650 +                                       if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
43651 +                                               log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
43652 +                                                               strerror(errno), c->file.name,  c->file.fd);
43653 +
43654 +                                               return -1;
43655 +                                       }
43656 +
43657 +                                       c->file.mmap.length = c->file.length;
43658 +
43659 +                                       close(c->file.fd);
43660 +                                       c->file.fd = -1;
43661 +
43662 +                                       /* chunk_reset() or chunk_free() will cleanup for us */
43663 +                               }
43664 +
43665 +                               if ((r = write(fd, c->file.mmap.start + c->offset, c->file.length - c->offset)) < 0) {
43666 +                                       switch(errno) {
43667 +                                       case ENOSPC:
43668 +                                               con->http_status = 507;
43669 +
43670 +                                               break;
43671 +                                       default:
43672 +                                               con->http_status = 403;
43673 +                                               break;
43674 +                                       }
43675                                 }
43676 -                               chunkqueue_remove_finished_chunks(cq);
43677 +                               break;
43678 +                       case MEM_CHUNK:
43679 +                               if ((r = write(fd, c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) {
43680 +                                       switch(errno) {
43681 +                                       case ENOSPC:
43682 +                                               con->http_status = 507;
43683 +
43684 +                                               break;
43685 +                                       default:
43686 +                                               con->http_status = 403;
43687 +                                               break;
43688 +                                       }
43689 +                               }
43690 +                               break;
43691 +                       case UNUSED_CHUNK:
43692 +                               break;
43693                         }
43694 -                       close(fd);
43695  
43696 +                       if (r > 0) {
43697 +                               c->offset += r;
43698 +                               cq->bytes_out += r;
43699 +                       } else {
43700 +                               break;
43701 +                       }
43702 +                       chunkqueue_remove_finished_chunks(cq);
43703                 }
43704 +               close(fd);
43705 +
43706                 return HANDLER_FINISHED;
43707         }
43708 -       case HTTP_METHOD_MOVE: 
43709 +       case HTTP_METHOD_MOVE:
43710         case HTTP_METHOD_COPY: {
43711                 buffer *destination = NULL;
43712                 char *sep, *start;
43713 @@ -1475,7 +1770,15 @@
43714                         con->http_status = 403;
43715                         return HANDLER_FINISHED;
43716                 }
43717 -               
43718 +
43719 +               /* is a exclusive lock set on the source */
43720 +               if (con->request.http_method == HTTP_METHOD_MOVE) {
43721 +                       if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43722 +                               con->http_status = 423;
43723 +                               return HANDLER_FINISHED;
43724 +                       }
43725 +               }
43726 +
43727                 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Destination"))) {
43728                         destination = ds->value;
43729                 } else {
43730 @@ -1549,10 +1852,10 @@
43731                 }
43732  
43733                 buffer_copy_string_buffer(p->physical.path, p->physical.doc_root);
43734 -               BUFFER_APPEND_SLASH(p->physical.path);
43735 +               PATHNAME_APPEND_SLASH(p->physical.path);
43736                 buffer_copy_string_buffer(p->physical.basedir, p->physical.path);
43737  
43738 -               /* don't add a second / */ 
43739 +               /* don't add a second / */
43740                 if (p->physical.rel_path->ptr[0] == '/') {
43741                         buffer_append_string_len(p->physical.path, p->physical.rel_path->ptr + 1, p->physical.rel_path->used - 2);
43742                 } else {
43743 @@ -1613,6 +1916,12 @@
43744                         /* it is just a file, good */
43745                         int r;
43746  
43747 +                       /* does the client have a lock for this connection ? */
43748 +                       if (!webdav_has_lock(srv, con, p, p->uri.path)) {
43749 +                               con->http_status = 423;
43750 +                               return HANDLER_FINISHED;
43751 +                       }
43752 +
43753                         /* destination exists */
43754                         if (0 == (r = stat(p->physical.path->ptr, &st))) {
43755                                 if (S_ISDIR(st.st_mode)) {
43756 @@ -1636,7 +1945,7 @@
43757                                         return HANDLER_FINISHED;
43758                                 }
43759                         } else if (overwrite == 0) {
43760 -                               /* destination exists, but overwrite is not set */ 
43761 +                               /* destination exists, but overwrite is not set */
43762                                 con->http_status = 412;
43763                                 return HANDLER_FINISHED;
43764                         } else {
43765 @@ -1655,16 +1964,16 @@
43766                                                 sqlite3_reset(stmt);
43767  
43768                                                 /* bind the values to the insert */
43769 -                                               sqlite3_bind_text(stmt, 1, 
43770 -                                                                 p->uri.path->ptr, 
43771 +                                               sqlite3_bind_text(stmt, 1,
43772 +                                                                 p->uri.path->ptr,
43773                                                                   p->uri.path->used - 1,
43774                                                                   SQLITE_TRANSIENT);
43775  
43776 -                                               sqlite3_bind_text(stmt, 2, 
43777 -                                                                 con->uri.path->ptr, 
43778 +                                               sqlite3_bind_text(stmt, 2,
43779 +                                                                 con->uri.path->ptr,
43780                                                                   con->uri.path->used - 1,
43781                                                                   SQLITE_TRANSIENT);
43782 -                                               
43783 +
43784                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {
43785                                                         log_error_write(srv, __FILE__, __LINE__, "ss", "sql-move failed:", sqlite3_errmsg(p->conf.sql));
43786                                                 }
43787 @@ -1691,12 +2000,17 @@
43788  
43789                 return HANDLER_FINISHED;
43790         }
43791 -       case HTTP_METHOD_PROPPATCH: {
43792 +       case HTTP_METHOD_PROPPATCH:
43793                 if (p->conf.is_readonly) {
43794                         con->http_status = 403;
43795                         return HANDLER_FINISHED;
43796                 }
43797  
43798 +               if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43799 +                       con->http_status = 423;
43800 +                       return HANDLER_FINISHED;
43801 +               }
43802 +
43803                 /* check if destination exists */
43804                 if (-1 == stat(con->physical.path->ptr, &st)) {
43805                         switch(errno) {
43806 @@ -1737,7 +2051,7 @@
43807  
43808                                                         sqlite3_stmt *stmt;
43809  
43810 -                                                       stmt = (0 == xmlStrcmp(cmd->name, BAD_CAST "remove")) ? 
43811 +                                                       stmt = (0 == xmlStrcmp(cmd->name, BAD_CAST "remove")) ?
43812                                                                 p->conf.stmt_delete_prop : p->conf.stmt_update_prop;
43813  
43814                                                         for (props = cmd->children; props; props = props->next) {
43815 @@ -1762,34 +2076,35 @@
43816  
43817                                                                         /* bind the values to the insert */
43818  
43819 -                                                                       sqlite3_bind_text(stmt, 1, 
43820 -                                                                                         con->uri.path->ptr, 
43821 +                                                                       sqlite3_bind_text(stmt, 1,
43822 +                                                                                         con->uri.path->ptr,
43823                                                                                           con->uri.path->used - 1,
43824                                                                                           SQLITE_TRANSIENT);
43825 -                                                                       sqlite3_bind_text(stmt, 2, 
43826 +                                                                       sqlite3_bind_text(stmt, 2,
43827                                                                                           (char *)prop->name,
43828                                                                                           strlen((char *)prop->name),
43829                                                                                           SQLITE_TRANSIENT);
43830                                                                         if (prop->ns) {
43831 -                                                                               sqlite3_bind_text(stmt, 3, 
43832 +                                                                               sqlite3_bind_text(stmt, 3,
43833                                                                                                   (char *)prop->ns->href,
43834                                                                                                   strlen((char *)prop->ns->href),
43835                                                                                                   SQLITE_TRANSIENT);
43836                                                                         } else {
43837 -                                                                               sqlite3_bind_text(stmt, 3, 
43838 +                                                                               sqlite3_bind_text(stmt, 3,
43839                                                                                                   "",
43840                                                                                                   0,
43841                                                                                                   SQLITE_TRANSIENT);
43842                                                                         }
43843                                                                         if (stmt == p->conf.stmt_update_prop) {
43844 -                                                                               sqlite3_bind_text(stmt, 4, 
43845 +                                                                               sqlite3_bind_text(stmt, 4,
43846                                                                                           (char *)xmlNodeGetContent(prop),
43847                                                                                           strlen((char *)xmlNodeGetContent(prop)),
43848                                                                                           SQLITE_TRANSIENT);
43849                                                                         }
43850 -                                                               
43851 +
43852                                                                         if (SQLITE_DONE != (r = sqlite3_step(stmt))) {
43853 -                                                                               log_error_write(srv, __FILE__, __LINE__, "ss", "sql-set failed:", sqlite3_errmsg(p->conf.sql));
43854 +                                                                               log_error_write(srv, __FILE__, __LINE__, "ss",
43855 +                                                                                               "sql-set failed:", sqlite3_errmsg(p->conf.sql));
43856                                                                         }
43857                                                                 }
43858                                                         }
43859 @@ -1804,7 +2119,7 @@
43860  
43861                                                         goto propmatch_cleanup;
43862                                                 }
43863 -       
43864 +
43865                                                 con->http_status = 400;
43866                                         } else {
43867                                                 if (SQLITE_OK != sqlite3_exec(p->conf.sql, "COMMIT", NULL, NULL, &err)) {
43868 @@ -1821,6 +2136,7 @@
43869                                 }
43870  
43871  propmatch_cleanup:
43872 +
43873                                 xmlFreeDoc(xml);
43874                         } else {
43875                                 con->http_status = 400;
43876 @@ -1830,11 +2146,307 @@
43877  #endif
43878                 con->http_status = 501;
43879                 return HANDLER_FINISHED;
43880 -       }
43881 +       case HTTP_METHOD_LOCK:
43882 +               /**
43883 +                * a mac wants to write
43884 +                *
43885 +                * LOCK /dav/expire.txt HTTP/1.1\r\n
43886 +                * User-Agent: WebDAVFS/1.3 (01308000) Darwin/8.1.0 (Power Macintosh)\r\n
43887 +                * Accept: * / *\r\n
43888 +                * Depth: 0\r\n
43889 +                * Timeout: Second-600\r\n
43890 +                * Content-Type: text/xml; charset=\"utf-8\"\r\n
43891 +                * Content-Length: 229\r\n
43892 +                * Connection: keep-alive\r\n
43893 +                * Host: 192.168.178.23:1025\r\n
43894 +                * \r\n
43895 +                * <?xml version=\"1.0\" encoding=\"utf-8\"?>\n
43896 +                * <D:lockinfo xmlns:D=\"DAV:\">\n
43897 +                *  <D:lockscope><D:exclusive/></D:lockscope>\n
43898 +                *  <D:locktype><D:write/></D:locktype>\n
43899 +                *  <D:owner>\n
43900 +                *   <D:href>http://www.apple.com/webdav_fs/</D:href>\n
43901 +                *  </D:owner>\n
43902 +                * </D:lockinfo>\n
43903 +                */
43904 +
43905 +               if (depth != 0 && depth != -1) {
43906 +                       con->http_status = 400;
43907 +
43908 +                       return HANDLER_FINISHED;
43909 +               }
43910 +
43911 +#ifdef USE_LOCKS
43912 +               if (con->request.content_length) {
43913 +                       xmlDocPtr xml;
43914 +                       buffer *hdr_if = NULL;
43915 +
43916 +                       if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
43917 +                               hdr_if = ds->value;
43918 +                       }
43919 +
43920 +                       /* we don't support Depth: Infinity on locks */
43921 +                       if (hdr_if == NULL && depth == -1) {
43922 +                               con->http_status = 409; /* Conflict */
43923 +
43924 +                               return HANDLER_FINISHED;
43925 +                       }
43926 +
43927 +                       if (1 == webdav_parse_chunkqueue(srv, con, p, con->request_content_queue, &xml)) {
43928 +                               xmlNode *rootnode = xmlDocGetRootElement(xml);
43929 +
43930 +                               assert(rootnode);
43931 +
43932 +                               if (0 == xmlStrcmp(rootnode->name, BAD_CAST "lockinfo")) {
43933 +                                       xmlNode *lockinfo;
43934 +                                       const xmlChar *lockscope = NULL, *locktype = NULL, *owner = NULL;
43935 +
43936 +                                       for (lockinfo = rootnode->children; lockinfo; lockinfo = lockinfo->next) {
43937 +                                               if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "lockscope")) {
43938 +                                                       xmlNode *value;
43939 +                                                       for (value = lockinfo->children; value; value = value->next) {
43940 +                                                               if ((0 == xmlStrcmp(value->name, BAD_CAST "exclusive")) ||
43941 +                                                                   (0 == xmlStrcmp(value->name, BAD_CAST "shared"))) {
43942 +                                                                       lockscope = value->name;
43943 +                                                               } else {
43944 +                                                                       con->http_status = 400;
43945 +
43946 +                                                                       xmlFreeDoc(xml);
43947 +                                                                       return HANDLER_FINISHED;
43948 +                                                               }
43949 +                                                       }
43950 +                                               } else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "locktype")) {
43951 +                                                       xmlNode *value;
43952 +                                                       for (value = lockinfo->children; value; value = value->next) {
43953 +                                                               if ((0 == xmlStrcmp(value->name, BAD_CAST "write"))) {
43954 +                                                                       locktype = value->name;
43955 +                                                               } else {
43956 +                                                                       con->http_status = 400;
43957 +
43958 +                                                                       xmlFreeDoc(xml);
43959 +                                                                       return HANDLER_FINISHED;
43960 +                                                               }
43961 +                                                       }
43962 +
43963 +                                               } else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "owner")) {
43964 +                                               }
43965 +                                       }
43966 +
43967 +                                       if (lockscope && locktype) {
43968 +                                               sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
43969 +
43970 +                                               /* is this resourse already locked ? */
43971 +
43972 +                                               /* SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout
43973 +                                                *   FROM locks
43974 +                                                *  WHERE resource = ? */
43975 +
43976 +                                               if (stmt) {
43977 +
43978 +                                                       sqlite3_reset(stmt);
43979 +
43980 +                                                       sqlite3_bind_text(stmt, 1,
43981 +                                                                         p->uri.path->ptr,
43982 +                                                                         p->uri.path->used - 1,
43983 +                                                                         SQLITE_TRANSIENT);
43984 +
43985 +                                                       /* it is the PK */
43986 +                                                       while (SQLITE_ROW == sqlite3_step(stmt)) {
43987 +                                                               /* we found a lock
43988 +                                                                * 1. is it compatible ?
43989 +                                                                * 2. is it ours */
43990 +                                                               char *sql_lockscope = (char *)sqlite3_column_text(stmt, 2);
43991 +
43992 +                                                               if (strcmp(sql_lockscope, "exclusive")) {
43993 +                                                                       con->http_status = 423;
43994 +                                                               } else if (0 == xmlStrcmp(lockscope, BAD_CAST "exclusive")) {
43995 +                                                                       /* resourse is locked with a shared lock
43996 +                                                                        * client wants exclusive */
43997 +                                                                       con->http_status = 423;
43998 +                                                               }
43999 +                                                       }
44000 +                                                       if (con->http_status == 423) {
44001 +                                                               xmlFreeDoc(xml);
44002 +                                                               return HANDLER_FINISHED;
44003 +                                                       }
44004 +                                               }
44005 +
44006 +                                               stmt = p->conf.stmt_create_lock;
44007 +                                               if (stmt) {
44008 +                                                       /* create a lock-token */
44009 +                                                       uuid_t id;
44010 +                                                       char uuid[37] /* 36 + \0 */;
44011 +
44012 +                                                       uuid_generate(id);
44013 +                                                       uuid_unparse(id, uuid);
44014 +
44015 +                                                       buffer_copy_string(p->tmp_buf, "opaquelocktoken:");
44016 +                                                       buffer_append_string(p->tmp_buf, uuid);
44017 +
44018 +                                                       /* "CREATE TABLE locks ("
44019 +                                                        * "  locktoken TEXT NOT NULL,"
44020 +                                                        * "  resource TEXT NOT NULL,"
44021 +                                                        * "  lockscope TEXT NOT NULL,"
44022 +                                                        * "  locktype TEXT NOT NULL,"
44023 +                                                        * "  owner TEXT NOT NULL,"
44024 +                                                        * "  depth INT NOT NULL,"
44025 +                                                        */
44026 +
44027 +                                                       sqlite3_reset(stmt);
44028 +
44029 +                                                       sqlite3_bind_text(stmt, 1,
44030 +                                                                         CONST_BUF_LEN(p->tmp_buf),
44031 +                                                                         SQLITE_TRANSIENT);
44032 +
44033 +                                                       sqlite3_bind_text(stmt, 2,
44034 +                                                                         CONST_BUF_LEN(con->uri.path),
44035 +                                                                         SQLITE_TRANSIENT);
44036 +
44037 +                                                       sqlite3_bind_text(stmt, 3,
44038 +                                                                         lockscope,
44039 +                                                                         xmlStrlen(lockscope),
44040 +                                                                         SQLITE_TRANSIENT);
44041 +
44042 +                                                       sqlite3_bind_text(stmt, 4,
44043 +                                                                         locktype,
44044 +                                                                         xmlStrlen(locktype),
44045 +                                                                         SQLITE_TRANSIENT);
44046 +
44047 +                                                       /* owner */
44048 +                                                       sqlite3_bind_text(stmt, 5,
44049 +                                                                         "",
44050 +                                                                         0,
44051 +                                                                         SQLITE_TRANSIENT);
44052 +
44053 +                                                       /* depth */
44054 +                                                       sqlite3_bind_int(stmt, 6,
44055 +                                                                        depth);
44056 +
44057 +
44058 +                                                       if (SQLITE_DONE != sqlite3_step(stmt)) {
44059 +                                                               log_error_write(srv, __FILE__, __LINE__, "ss",
44060 +                                                                               "create lock:", sqlite3_errmsg(p->conf.sql));
44061 +                                                       }
44062 +
44063 +                                                       /* looks like we survived */
44064 +                                                       webdav_lockdiscovery(srv, con, p->tmp_buf, lockscope, locktype, depth);
44065 +
44066 +                                                       con->http_status = 201;
44067 +                                                       con->file_finished = 1;
44068 +                                               }
44069 +                                       }
44070 +                               }
44071 +
44072 +                               xmlFreeDoc(xml);
44073 +                               return HANDLER_FINISHED;
44074 +                       } else {
44075 +                               con->http_status = 400;
44076 +                               return HANDLER_FINISHED;
44077 +                       }
44078 +               } else {
44079 +
44080 +                       if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
44081 +                               buffer *locktoken = ds->value;
44082 +                               sqlite3_stmt *stmt = p->conf.stmt_refresh_lock;
44083 +
44084 +                               /* remove the < > around the token */
44085 +                               if (locktoken->used < 6) {
44086 +                                       con->http_status = 400;
44087 +
44088 +                                       return HANDLER_FINISHED;
44089 +                               }
44090 +
44091 +                               buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 2, locktoken->used - 5);
44092 +
44093 +                               sqlite3_reset(stmt);
44094 +
44095 +                               sqlite3_bind_text(stmt, 1,
44096 +                                         CONST_BUF_LEN(p->tmp_buf),
44097 +                                         SQLITE_TRANSIENT);
44098 +
44099 +                               if (SQLITE_DONE != sqlite3_step(stmt)) {
44100 +                                       log_error_write(srv, __FILE__, __LINE__, "ss",
44101 +                                               "refresh lock:", sqlite3_errmsg(p->conf.sql));
44102 +                               }
44103 +
44104 +                               webdav_lockdiscovery(srv, con, p->tmp_buf, "exclusive", "write", 0);
44105 +
44106 +                               con->http_status = 200;
44107 +                               con->file_finished = 1;
44108 +                               return HANDLER_FINISHED;
44109 +                       } else {
44110 +                               /* we need a lock-token to refresh */
44111 +                               con->http_status = 400;
44112 +
44113 +                               return HANDLER_FINISHED;
44114 +                       }
44115 +               }
44116 +               break;
44117 +#else
44118 +               con->http_status = 501;
44119 +               return HANDLER_FINISHED;
44120 +#endif
44121 +       case HTTP_METHOD_UNLOCK:
44122 +#ifdef USE_LOCKS
44123 +               if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Lock-Token"))) {
44124 +                       buffer *locktoken = ds->value;
44125 +                       sqlite3_stmt *stmt = p->conf.stmt_remove_lock;
44126 +
44127 +                       /* remove the < > around the token */
44128 +                       if (locktoken->used < 4) {
44129 +                               con->http_status = 400;
44130 +
44131 +                               return HANDLER_FINISHED;
44132 +                       }
44133 +
44134 +                       /**
44135 +                        * FIXME:
44136 +                        *
44137 +                        * if the resourse is locked:
44138 +                        * - by us: unlock
44139 +                        * - by someone else: 401
44140 +                        * if the resource is not locked:
44141 +                        * - 412
44142 +                        *  */
44143 +
44144 +                       buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 1, locktoken->used - 3);
44145 +
44146 +                       sqlite3_reset(stmt);
44147 +
44148 +                       sqlite3_bind_text(stmt, 1,
44149 +                                 CONST_BUF_LEN(p->tmp_buf),
44150 +                                 SQLITE_TRANSIENT);
44151 +
44152 +                       sqlite3_bind_text(stmt, 2,
44153 +                                 CONST_BUF_LEN(con->uri.path),
44154 +                                 SQLITE_TRANSIENT);
44155 +
44156 +                       if (SQLITE_DONE != sqlite3_step(stmt)) {
44157 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
44158 +                                       "remove lock:", sqlite3_errmsg(p->conf.sql));
44159 +                       }
44160 +
44161 +                       if (0 == sqlite3_changes(p->conf.sql)) {
44162 +                               con->http_status = 401;
44163 +                       } else {
44164 +                               con->http_status = 204;
44165 +                       }
44166 +                       return HANDLER_FINISHED;
44167 +               } else {
44168 +                       /* we need a lock-token to unlock */
44169 +                       con->http_status = 400;
44170 +
44171 +                       return HANDLER_FINISHED;
44172 +               }
44173 +               break;
44174 +#else
44175 +               con->http_status = 501;
44176 +               return HANDLER_FINISHED;
44177 +#endif
44178         default:
44179                 break;
44180         }
44181 -       
44182 +
44183         /* not found */
44184         return HANDLER_GO_ON;
44185  }
44186 @@ -1845,14 +2457,14 @@
44187  int mod_webdav_plugin_init(plugin *p) {
44188         p->version     = LIGHTTPD_VERSION_ID;
44189         p->name        = buffer_init_string("webdav");
44190 -       
44191 +
44192         p->init        = mod_webdav_init;
44193         p->handle_uri_clean  = mod_webdav_uri_handler;
44194         p->handle_physical   = mod_webdav_subrequest_handler;
44195         p->set_defaults  = mod_webdav_set_defaults;
44196         p->cleanup     = mod_webdav_free;
44197 -       
44198 +
44199         p->data        = NULL;
44200 -       
44201 +
44202         return 0;
44203  }
44204 --- ../lighttpd-1.4.11/src/network.c    2006-03-04 16:45:46.000000000 +0200
44205 +++ lighttpd-1.4.12/src/network.c       2006-07-18 13:03:40.000000000 +0300
44206 @@ -1,14 +1,14 @@
44207  #include <sys/types.h>
44208  #include <sys/stat.h>
44209 -#include <sys/time.h>
44210  
44211  #include <errno.h>
44212  #include <fcntl.h>
44213 -#include <unistd.h>
44214  #include <string.h>
44215  #include <stdlib.h>
44216  #include <assert.h>
44217  
44218 +#include <stdio.h>
44219 +
44220  #include "network.h"
44221  #include "fdevent.h"
44222  #include "log.h"
44223 @@ -19,11 +19,12 @@
44224  #include "network_backends.h"
44225  #include "sys-mmap.h"
44226  #include "sys-socket.h"
44227 +#include "sys-files.h"
44228  
44229  #ifdef USE_OPENSSL
44230 -# include <openssl/ssl.h> 
44231 -# include <openssl/err.h> 
44232 -# include <openssl/rand.h> 
44233 +# include <openssl/ssl.h>
44234 +# include <openssl/err.h>
44235 +# include <openssl/rand.h>
44236  #endif
44237  
44238  handler_t network_server_handle_fdevent(void *s, void *context, int revents) {
44239 @@ -31,25 +32,25 @@
44240         server_socket *srv_socket = (server_socket *)context;
44241         connection *con;
44242         int loops = 0;
44243 -       
44244 +
44245         UNUSED(context);
44246 -       
44247 +
44248         if (revents != FDEVENT_IN) {
44249 -               log_error_write(srv, __FILE__, __LINE__, "sdd", 
44250 +               log_error_write(srv, __FILE__, __LINE__, "sdd",
44251                                 "strange event for server socket",
44252 -                               srv_socket->fd,
44253 +                               srv_socket->sock->fd,
44254                                 revents);
44255                 return HANDLER_ERROR;
44256         }
44257  
44258         /* accept()s at most 100 connections directly
44259          *
44260 -        * we jump out after 100 to give the waiting connections a chance */    
44261 +        * we jump out after 100 to give the waiting connections a chance */
44262         for (loops = 0; loops < 100 && NULL != (con = connection_accept(srv, srv_socket)); loops++) {
44263                 handler_t r;
44264 -               
44265 +
44266                 connection_state_machine(srv, con);
44267 -               
44268 +
44269                 switch(r = plugins_call_handle_joblist(srv, con)) {
44270                 case HANDLER_FINISHED:
44271                 case HANDLER_GO_ON:
44272 @@ -72,18 +73,18 @@
44273         buffer *b;
44274         int is_unix_domain_socket = 0;
44275         int fd;
44276 -       
44277 +
44278  #ifdef SO_ACCEPTFILTER
44279         struct accept_filter_arg afa;
44280  #endif
44281  
44282 -#ifdef __WIN32
44283 +#ifdef _WIN32
44284         WORD wVersionRequested;
44285         WSADATA wsaData;
44286         int err;
44287 -        
44288 +
44289         wVersionRequested = MAKEWORD( 2, 2 );
44290 -        
44291 +
44292         err = WSAStartup( wVersionRequested, &wsaData );
44293         if ( err != 0 ) {
44294                     /* Tell the user that we could not find a usable */
44295 @@ -91,37 +92,37 @@
44296                     return -1;
44297         }
44298  #endif
44299 -       
44300 +
44301         srv_socket = calloc(1, sizeof(*srv_socket));
44302 -       srv_socket->fd = -1;
44303 -       
44304 +       srv_socket->sock = iosocket_init();
44305 +
44306         srv_socket->srv_token = buffer_init();
44307         buffer_copy_string_buffer(srv_socket->srv_token, host_token);
44308 -       
44309 +
44310         b = buffer_init();
44311         buffer_copy_string_buffer(b, host_token);
44312 -       
44313 -       /* ipv4:port 
44314 +
44315 +       /* ipv4:port
44316          * [ipv6]:port
44317          */
44318         if (NULL == (sp = strrchr(b->ptr, ':'))) {
44319                 log_error_write(srv, __FILE__, __LINE__, "sb", "value of $SERVER[\"socket\"] has to be \"ip:port\".", b);
44320 -               
44321 +
44322                 return -1;
44323         }
44324 -       
44325 +
44326         host = b->ptr;
44327 -       
44328 +
44329         /* check for [ and ] */
44330         if (b->ptr[0] == '[' && *(sp-1) == ']') {
44331                 *(sp-1) = '\0';
44332                 host++;
44333 -               
44334 +
44335                 s->use_ipv6 = 1;
44336         }
44337 -       
44338 +
44339         *(sp++) = '\0';
44340 -       
44341 +
44342         port = strtol(sp, NULL, 10);
44343  
44344         if (host[0] == '/') {
44345 @@ -129,18 +130,18 @@
44346                 is_unix_domain_socket = 1;
44347         } else if (port == 0 || port > 65535) {
44348                 log_error_write(srv, __FILE__, __LINE__, "sd", "port out of range:", port);
44349 -       
44350 +
44351                 return -1;
44352         }
44353 -       
44354 +
44355         if (*host == '\0') host = NULL;
44356  
44357         if (is_unix_domain_socket) {
44358  #ifdef HAVE_SYS_UN_H
44359  
44360                 srv_socket->addr.plain.sa_family = AF_UNIX;
44361 -               
44362 -               if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
44363 +
44364 +               if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
44365                         log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
44366                         return -1;
44367                 }
44368 @@ -154,32 +155,32 @@
44369  #ifdef HAVE_IPV6
44370         if (s->use_ipv6) {
44371                 srv_socket->addr.plain.sa_family = AF_INET6;
44372 -               
44373 -               if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44374 +
44375 +               if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44376                         log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
44377                         return -1;
44378                 }
44379                 srv_socket->use_ipv6 = 1;
44380         }
44381  #endif
44382 -                               
44383 -       if (srv_socket->fd == -1) {
44384 +
44385 +       if (srv_socket->sock->fd == -1) {
44386                 srv_socket->addr.plain.sa_family = AF_INET;
44387 -               if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44388 +               if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44389                         log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
44390                         return -1;
44391                 }
44392         }
44393 -       
44394 +
44395         /* */
44396 -       srv->cur_fds = srv_socket->fd;
44397 -       
44398 +       srv->cur_fds = srv_socket->sock->fd;
44399 +
44400         val = 1;
44401 -       if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
44402 +       if (setsockopt(srv_socket->sock->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
44403                 log_error_write(srv, __FILE__, __LINE__, "ss", "socketsockopt failed:", strerror(errno));
44404                 return -1;
44405         }
44406 -       
44407 +
44408         switch(srv_socket->addr.plain.sa_family) {
44409  #ifdef HAVE_IPV6
44410         case AF_INET6:
44411 @@ -190,23 +191,23 @@
44412                 } else {
44413                         struct addrinfo hints, *res;
44414                         int r;
44415 -                       
44416 +
44417                         memset(&hints, 0, sizeof(hints));
44418 -                       
44419 +
44420                         hints.ai_family   = AF_INET6;
44421                         hints.ai_socktype = SOCK_STREAM;
44422                         hints.ai_protocol = IPPROTO_TCP;
44423 -                       
44424 +
44425                         if (0 != (r = getaddrinfo(host, NULL, &hints, &res))) {
44426 -                               log_error_write(srv, __FILE__, __LINE__, 
44427 -                                               "sssss", "getaddrinfo failed: ", 
44428 +                               log_error_write(srv, __FILE__, __LINE__,
44429 +                                               "sssss", "getaddrinfo failed: ",
44430                                                 gai_strerror(r), "'", host, "'");
44431 -                               
44432 +
44433                                 return -1;
44434                         }
44435 -                       
44436 +
44437                         memcpy(&(srv_socket->addr), res->ai_addr, res->ai_addrlen);
44438 -                       
44439 +
44440                         freeaddrinfo(res);
44441                 }
44442                 srv_socket->addr.ipv6.sin6_port = htons(port);
44443 @@ -221,33 +222,34 @@
44444                 } else {
44445                         struct hostent *he;
44446                         if (NULL == (he = gethostbyname(host))) {
44447 -                               log_error_write(srv, __FILE__, __LINE__, 
44448 -                                               "sds", "gethostbyname failed: ", 
44449 +                               log_error_write(srv, __FILE__, __LINE__,
44450 +                                               "sds", "gethostbyname failed: ",
44451                                                 h_errno, host);
44452                                 return -1;
44453                         }
44454 -                       
44455 +
44456                         if (he->h_addrtype != AF_INET) {
44457                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
44458                                 return -1;
44459                         }
44460 -                       
44461 +
44462                         if (he->h_length != sizeof(struct in_addr)) {
44463                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
44464                                 return -1;
44465                         }
44466 -                       
44467 +
44468                         memcpy(&(srv_socket->addr.ipv4.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
44469                 }
44470                 srv_socket->addr.ipv4.sin_port = htons(port);
44471 -               
44472 +
44473                 addr_len = sizeof(struct sockaddr_in);
44474 -               
44475 +
44476                 break;
44477 +#ifndef _WIN32
44478         case AF_UNIX:
44479                 srv_socket->addr.un.sun_family = AF_UNIX;
44480                 strcpy(srv_socket->addr.un.sun_path, host);
44481 -               
44482 +
44483  #ifdef SUN_LEN
44484                 addr_len = SUN_LEN(&srv_socket->addr.un);
44485  #else
44486 @@ -256,11 +258,11 @@
44487  #endif
44488  
44489                 /* check if the socket exists and try to connect to it. */
44490 -               if (-1 != (fd = connect(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {
44491 +               if (-1 != (fd = connect(srv_socket->sock->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {
44492                         close(fd);
44493  
44494 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
44495 -                               "server socket is still in use:", 
44496 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
44497 +                               "server socket is still in use:",
44498                                 host);
44499  
44500  
44501 @@ -275,88 +277,89 @@
44502                 case ENOENT:
44503                         break;
44504                 default:
44505 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
44506 -                               "testing socket failed:", 
44507 +                       log_error_write(srv, __FILE__, __LINE__, "sds",
44508 +                               "testing socket failed:",
44509                                 host, strerror(errno));
44510  
44511                         return -1;
44512                 }
44513  
44514                 break;
44515 +#endif
44516         default:
44517                 addr_len = 0;
44518 -               
44519 +
44520                 return -1;
44521         }
44522 -       
44523 -       if (0 != bind(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
44524 +
44525 +       if (0 != bind(srv_socket->sock->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
44526                 switch(srv_socket->addr.plain.sa_family) {
44527                 case AF_UNIX:
44528 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
44529 -                                       "can't bind to socket:", 
44530 +                       log_error_write(srv, __FILE__, __LINE__, "sds",
44531 +                                       "can't bind to socket:",
44532                                         host, strerror(errno));
44533                         break;
44534                 default:
44535 -                       log_error_write(srv, __FILE__, __LINE__, "ssds", 
44536 -                                       "can't bind to port:", 
44537 +                       log_error_write(srv, __FILE__, __LINE__, "ssds",
44538 +                                       "can't bind to port:",
44539                                         host, port, strerror(errno));
44540                         break;
44541                 }
44542                 return -1;
44543         }
44544 -       
44545 -       if (-1 == listen(srv_socket->fd, 128 * 8)) {
44546 +
44547 +       if (-1 == listen(srv_socket->sock->fd, 128 * 8)) {
44548                 log_error_write(srv, __FILE__, __LINE__, "ss", "listen failed: ", strerror(errno));
44549                 return -1;
44550         }
44551 -       
44552 +
44553         if (s->is_ssl) {
44554  #ifdef USE_OPENSSL
44555                 if (srv->ssl_is_init == 0) {
44556                         SSL_load_error_strings();
44557                         SSL_library_init();
44558                         srv->ssl_is_init = 1;
44559 -                       
44560 +
44561                         if (0 == RAND_status()) {
44562 -                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
44563 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44564                                                 "not enough entropy in the pool");
44565                                 return -1;
44566                         }
44567                 }
44568 -               
44569 +
44570                 if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {
44571 -                       log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
44572 +                       log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44573                                         ERR_error_string(ERR_get_error(), NULL));
44574                         return -1;
44575                 }
44576 -               
44577 +
44578                 if (buffer_is_empty(s->ssl_pemfile)) {
44579                         log_error_write(srv, __FILE__, __LINE__, "s", "ssl.pemfile has to be set");
44580                         return -1;
44581                 }
44582 -               
44583 +
44584                 if (!buffer_is_empty(s->ssl_ca_file)) {
44585                         if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s->ssl_ca_file->ptr, NULL)) {
44586 -                               log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", 
44587 +                               log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44588                                                 ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);
44589                                 return -1;
44590                         }
44591                 }
44592 -               
44593 +
44594                 if (SSL_CTX_use_certificate_file(s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
44595 -                       log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", 
44596 +                       log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44597                                         ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
44598                         return -1;
44599                 }
44600 -               
44601 +
44602                 if (SSL_CTX_use_PrivateKey_file (s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
44603 -                       log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", 
44604 +                       log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44605                                         ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
44606                         return -1;
44607                 }
44608 -               
44609 +
44610                 if (SSL_CTX_check_private_key(s->ssl_ctx) != 1) {
44611 -                       log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:", 
44612 +                       log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:",
44613                                         "Private key does not match the certificate public key, reason:",
44614                                         ERR_error_string(ERR_get_error(), NULL),
44615                                         s->ssl_pemfile);
44616 @@ -364,15 +367,15 @@
44617                 }
44618                 srv_socket->ssl_ctx = s->ssl_ctx;
44619  #else
44620 -               
44621 +
44622                 buffer_free(srv_socket->srv_token);
44623                 free(srv_socket);
44624 -               
44625 +
44626                 buffer_free(b);
44627 -               
44628 -               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
44629 +
44630 +               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44631                                 "ssl requested but openssl support is not compiled in");
44632 -               
44633 +
44634                 return -1;
44635  #endif
44636         } else {
44637 @@ -383,17 +386,16 @@
44638                  */
44639                 memset(&afa, 0, sizeof(afa));
44640                 strcpy(afa.af_name, "httpready");
44641 -               if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
44642 +               if (setsockopt(srv_socket->sock->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
44643                         if (errno != ENOENT) {
44644                                 log_error_write(srv, __FILE__, __LINE__, "ss", "can't set accept-filter 'httpready': ", strerror(errno));
44645                         }
44646                 }
44647  #endif
44648         }
44649 -       
44650 +
44651         srv_socket->is_ssl = s->is_ssl;
44652 -       srv_socket->fde_ndx = -1;
44653 -       
44654 +
44655         if (srv->srv_sockets.size == 0) {
44656                 srv->srv_sockets.size = 4;
44657                 srv->srv_sockets.used = 0;
44658 @@ -402,11 +404,10 @@
44659                 srv->srv_sockets.size += 4;
44660                 srv->srv_sockets.ptr = realloc(srv->srv_sockets.ptr, srv->srv_sockets.size * sizeof(server_socket));
44661         }
44662 -       
44663 +
44664         srv->srv_sockets.ptr[srv->srv_sockets.used++] = srv_socket;
44665 -       
44666         buffer_free(b);
44667 -       
44668 +
44669         return 0;
44670  }
44671  
44672 @@ -414,45 +415,60 @@
44673         size_t i;
44674         for (i = 0; i < srv->srv_sockets.used; i++) {
44675                 server_socket *srv_socket = srv->srv_sockets.ptr[i];
44676 -               
44677 -               if (srv_socket->fd != -1) {
44678 +
44679 +               if (srv_socket->sock->fd != -1) {
44680                         /* check if server fd are already registered */
44681 -                       if (srv_socket->fde_ndx != -1) {
44682 -                               fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
44683 -                               fdevent_unregister(srv->ev, srv_socket->fd);
44684 +                       if (srv_socket->sock->fde_ndx != -1) {
44685 +                               fdevent_event_del(srv->ev, srv_socket->sock);
44686 +                               fdevent_unregister(srv->ev, srv_socket->sock);
44687                         }
44688 -               
44689 -                       close(srv_socket->fd);
44690 +
44691 +                       closesocket(srv_socket->sock->fd);
44692 +               }
44693 +
44694 +               if (srv_socket->is_ssl) {
44695 +#ifdef USE_OPENSSL
44696 +                       SSL_CTX_free(srv_socket->ssl_ctx);
44697 +#endif
44698                 }
44699 -               
44700 +
44701 +               iosocket_free(srv_socket->sock);
44702 +
44703                 buffer_free(srv_socket->srv_token);
44704 -               
44705 +
44706                 free(srv_socket);
44707         }
44708 -       
44709 +
44710 +#ifdef USE_OPENSSL
44711 +       ERR_free_strings();
44712 +#endif
44713         free(srv->srv_sockets.ptr);
44714 -       
44715 +
44716         return 0;
44717  }
44718  
44719  typedef enum {
44720         NETWORK_BACKEND_UNSET,
44721 +
44722         NETWORK_BACKEND_WRITE,
44723         NETWORK_BACKEND_WRITEV,
44724         NETWORK_BACKEND_LINUX_SENDFILE,
44725         NETWORK_BACKEND_FREEBSD_SENDFILE,
44726 -       NETWORK_BACKEND_SOLARIS_SENDFILEV
44727 +       NETWORK_BACKEND_SOLARIS_SENDFILEV,
44728 +
44729 +    NETWORK_BACKEND_WIN32_SEND,
44730 +    NETWORK_BACKEND_WIN32_TRANSMITFILE,
44731  } network_backend_t;
44732  
44733  int network_init(server *srv) {
44734         buffer *b;
44735         size_t i;
44736         network_backend_t backend;
44737 -       
44738 -       struct nb_map { 
44739 -               network_backend_t nb; 
44740 -               const char *name; 
44741 -       } network_backends[] = { 
44742 +
44743 +       struct nb_map {
44744 +               network_backend_t nb;
44745 +               const char *name;
44746 +       } network_backends[] = {
44747                 /* lowest id wins */
44748  #if defined USE_LINUX_SENDFILE
44749                 { NETWORK_BACKEND_LINUX_SENDFILE,       "linux-sendfile" },
44750 @@ -466,21 +482,30 @@
44751  #if defined USE_WRITEV
44752                 { NETWORK_BACKEND_WRITEV,               "writev" },
44753  #endif
44754 +#if defined USE_WRITE
44755                 { NETWORK_BACKEND_WRITE,                "write" },
44756 +#endif
44757 +#if defined USE_WIN32_TRANSMITFILE
44758 +               { NETWORK_BACKEND_WIN32_TRANSMITFILE,   "win32-transmitfile" },
44759 +#endif
44760 +#if defined USE_WIN32_SEND
44761 +               { NETWORK_BACKEND_WIN32_SEND,           "win32-send" },
44762 +#endif
44763 +
44764                 { NETWORK_BACKEND_UNSET,                NULL }
44765         };
44766 -       
44767 +
44768         b = buffer_init();
44769 -               
44770 +
44771         buffer_copy_string_buffer(b, srv->srvconf.bindhost);
44772         buffer_append_string(b, ":");
44773         buffer_append_long(b, srv->srvconf.port);
44774 -       
44775 +
44776         if (0 != network_server_init(srv, b, srv->config_storage[0])) {
44777                 return -1;
44778         }
44779         buffer_free(b);
44780 -               
44781 +
44782  #ifdef USE_OPENSSL
44783         srv->network_ssl_backend_write = network_write_chunkqueue_openssl;
44784  #endif
44785 @@ -500,54 +525,80 @@
44786                 if (NULL == network_backends[i].name) {
44787                         /* we don't know it */
44788  
44789 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
44790 -                                       "server.network-backend has a unknown value:", 
44791 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
44792 +                                       "server.network-backend has a unknown value:",
44793                                         srv->srvconf.network_backend);
44794  
44795                         return -1;
44796                 }
44797         }
44798  
44799 +#define SET_NETWORK_BACKEND(read, write) \
44800 +    srv->network_backend_write = network_write_chunkqueue_##write;\
44801 +    srv->network_backend_read = network_read_chunkqueue_##read
44802 +
44803 +#define SET_NETWORK_BACKEND_SSL(read, write) \
44804 +    srv->network_ssl_backend_write = network_write_chunkqueue_##write;\
44805 +    srv->network_ssl_backend_read = network_read_chunkqueue_##read
44806 +
44807         switch(backend) {
44808 +
44809 +#ifdef USE_WIN32_SEND
44810 +       case NETWORK_BACKEND_WIN32_SEND:
44811 +        SET_NETWORK_BACKEND(win32recv, win32send);
44812 +               break;
44813 +#ifdef USE_WIN32_TRANSMITFILE
44814 +       case NETWORK_BACKEND_WIN32_TRANSMITFILE:
44815 +        SET_NETWORK_BACKEND(win32recv, win32transmitfile);
44816 +               break;
44817 +#endif
44818 +#endif
44819 +
44820 +#ifdef USE_WRITE
44821         case NETWORK_BACKEND_WRITE:
44822 -               srv->network_backend_write = network_write_chunkqueue_write;
44823 +        SET_NETWORK_BACKEND(read, write);
44824                 break;
44825 +
44826  #ifdef USE_WRITEV
44827         case NETWORK_BACKEND_WRITEV:
44828 -               srv->network_backend_write = network_write_chunkqueue_writev;
44829 +        SET_NETWORK_BACKEND(read, writev);
44830                 break;
44831  #endif
44832  #ifdef USE_LINUX_SENDFILE
44833         case NETWORK_BACKEND_LINUX_SENDFILE:
44834 -               srv->network_backend_write = network_write_chunkqueue_linuxsendfile; 
44835 +        SET_NETWORK_BACKEND(read, linuxsendfile);
44836                 break;
44837  #endif
44838  #ifdef USE_FREEBSD_SENDFILE
44839         case NETWORK_BACKEND_FREEBSD_SENDFILE:
44840 -               srv->network_backend_write = network_write_chunkqueue_freebsdsendfile; 
44841 +        SET_NETWORK_BACKEND(read, freebsdsendfile);
44842                 break;
44843  #endif
44844  #ifdef USE_SOLARIS_SENDFILEV
44845         case NETWORK_BACKEND_SOLARIS_SENDFILEV:
44846 -               srv->network_backend_write = network_write_chunkqueue_solarissendfilev; 
44847 +        SET_NETWORK_BACKEND(read, solarissendfilev);
44848                 break;
44849  #endif
44850 +#endif
44851         default:
44852                 return -1;
44853         }
44854 +#ifdef USE_OPENSSL
44855 +        SET_NETWORK_BACKEND_SSL(openssl, openssl);
44856 +#endif
44857  
44858         /* check for $SERVER["socket"] */
44859         for (i = 1; i < srv->config_context->used; i++) {
44860                 data_config *dc = (data_config *)srv->config_context->data[i];
44861                 specific_config *s = srv->config_storage[i];
44862                 size_t j;
44863 -               
44864 +
44865                 /* not our stage */
44866                 if (COMP_SERVER_SOCKET != dc->comp) continue;
44867 -               
44868 +
44869                 if (dc->cond != CONFIG_COND_EQ) {
44870                         log_error_write(srv, __FILE__, __LINE__, "s", "only == is allowed for $SERVER[\"socket\"].");
44871 -                       
44872 +
44873                         return -1;
44874                 }
44875  
44876 @@ -558,36 +609,47 @@
44877                                 break;
44878                         }
44879                 }
44880 -               
44881 +
44882                 if (j == srv->srv_sockets.used) {
44883                         if (0 != network_server_init(srv, dc->string, s)) return -1;
44884                 }
44885         }
44886 -       
44887 +
44888         return 0;
44889  }
44890  
44891  int network_register_fdevents(server *srv) {
44892         size_t i;
44893 -       
44894         if (-1 == fdevent_reset(srv->ev)) {
44895                 return -1;
44896         }
44897 -       
44898         /* register fdevents after reset */
44899         for (i = 0; i < srv->srv_sockets.used; i++) {
44900                 server_socket *srv_socket = srv->srv_sockets.ptr[i];
44901 -               
44902 -               fdevent_register(srv->ev, srv_socket->fd, network_server_handle_fdevent, srv_socket);
44903 -               fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
44904 +               fdevent_register(srv->ev, srv_socket->sock, network_server_handle_fdevent, srv_socket);
44905 +               fdevent_event_add(srv->ev, srv_socket->sock, FDEVENT_IN);
44906         }
44907         return 0;
44908  }
44909  
44910 -int network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
44911 -       int ret = -1;
44912 +network_status_t network_read_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
44913 +       server_socket *srv_socket = con->srv_socket;
44914 +
44915 +       if (srv_socket->is_ssl) {
44916 +#ifdef USE_OPENSSL
44917 +               return srv->network_ssl_backend_read(srv, con, con->sock, cq);
44918 +#else
44919 +               return NETWORK_STATUS_FATAL_ERROR;
44920 +#endif
44921 +       } else {
44922 +               return srv->network_backend_read(srv, con, con->sock, cq);
44923 +       }
44924 +}
44925 +
44926 +network_status_t network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
44927 +       network_status_t ret = NETWORK_STATUS_UNSET;
44928         off_t written = 0;
44929 -#ifdef TCP_CORK        
44930 +#ifdef TCP_CORK
44931         int corked = 0;
44932  #endif
44933         server_socket *srv_socket = con->srv_socket;
44934 @@ -600,37 +662,42 @@
44935                 joblist_append(srv, con);
44936  
44937                 return 1;
44938 -       }  
44939 +       }
44940  
44941         written = cq->bytes_out;
44942  
44943 -#ifdef TCP_CORK        
44944 +#ifdef TCP_CORK
44945         /* Linux: put a cork into the socket as we want to combine the write() calls
44946          * but only if we really have multiple chunks
44947          */
44948         if (cq->first && cq->first->next) {
44949                 corked = 1;
44950 -               setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
44951 +               setsockopt(con->sock->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
44952         }
44953  #endif
44954 -       
44955 +
44956         if (srv_socket->is_ssl) {
44957  #ifdef USE_OPENSSL
44958 -               ret = srv->network_ssl_backend_write(srv, con, con->ssl, cq);
44959 +               ret = srv->network_ssl_backend_write(srv, con, con->sock, cq);
44960  #endif
44961         } else {
44962 -               ret = srv->network_backend_write(srv, con, con->fd, cq);
44963 +               ret = srv->network_backend_write(srv, con, con->sock, cq);
44964         }
44965 -       
44966 -       if (ret >= 0) {
44967 +
44968 +    switch (ret) {
44969 +    case NETWORK_STATUS_WAIT_FOR_EVENT:
44970 +    case NETWORK_STATUS_SUCCESS:
44971                 chunkqueue_remove_finished_chunks(cq);
44972 -               ret = chunkqueue_is_empty(cq) ? 0 : 1;
44973 +
44974 +        break;
44975 +    default:
44976 +        break;
44977         }
44978 -       
44979 +
44980  #ifdef TCP_CORK
44981         if (corked) {
44982                 corked = 0;
44983 -               setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
44984 +               setsockopt(con->sock->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
44985         }
44986  #endif
44987  
44988 @@ -639,13 +706,13 @@
44989         con->bytes_written_cur_second += written;
44990  
44991         *(con->conf.global_bytes_per_second_cnt_ptr) += written;
44992 -       
44993 +
44994         if (con->conf.kbytes_per_second &&
44995             (con->bytes_written_cur_second > con->conf.kbytes_per_second * 1024)) {
44996                 /* we reached the traffic limit */
44997  
44998                 con->traffic_limit_reached = 1;
44999                 joblist_append(srv, con);
45000 -       }  
45001 +       }
45002         return ret;
45003  }
45004 --- ../lighttpd-1.4.11/src/network.h    2005-08-11 01:26:42.000000000 +0300
45005 +++ lighttpd-1.4.12/src/network.h       2006-07-18 13:03:40.000000000 +0300
45006 @@ -3,11 +3,13 @@
45007  
45008  #include "server.h"
45009  
45010 -int network_write_chunkqueue(server *srv, connection *con, chunkqueue *c);
45011 +network_status_t network_write_chunkqueue(server *srv, connection *con, chunkqueue *c);
45012 +network_status_t network_read_chunkqueue(server *srv, connection *con, chunkqueue *c);
45013  
45014  int network_init(server *srv);
45015  int network_close(server *srv);
45016  
45017  int network_register_fdevents(server *srv);
45018 +handler_t network_server_handle_fdevent(void *s, void *context, int revents);
45019  
45020  #endif
45021 --- ../lighttpd-1.4.11/src/network_backends.h   2005-10-24 15:13:51.000000000 +0300
45022 +++ lighttpd-1.4.12/src/network_backends.h      2006-07-18 13:03:40.000000000 +0300
45023 @@ -43,16 +43,47 @@
45024  # define USE_AIX_SENDFILE
45025  #endif
45026  
45027 +/**
45028 +* unix can use read/write or recv/send on sockets
45029 +* win32 only recv/send
45030 +*/
45031 +#ifdef _WIN32
45032 +# define USE_WIN32_SEND
45033 +/* wait for async-io support
45034 +# define USE_WIN32_TRANSMITFILE
45035 +*/
45036 +#else
45037 +# define USE_WRITE
45038 +#endif
45039 +
45040  #include "base.h"
45041 +#include "network.h"
45042 +
45043 +#define NETWORK_BACKEND_WRITE_CHUNK(x) \
45044 +    network_status_t network_write_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq, chunk *c)
45045 +
45046 +#define NETWORK_BACKEND_WRITE(x) \
45047 +    network_status_t network_write_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq)
45048 +#define NETWORK_BACKEND_READ(x) \
45049 +    network_status_t network_read_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq)
45050 +
45051 +NETWORK_BACKEND_WRITE_CHUNK(writev_mem);
45052 +
45053 +NETWORK_BACKEND_WRITE(write);
45054 +NETWORK_BACKEND_WRITE(writev);
45055 +NETWORK_BACKEND_WRITE(linuxsendfile);
45056 +NETWORK_BACKEND_WRITE(freebsdsendfile);
45057 +NETWORK_BACKEND_WRITE(solarissendfilev);
45058 +
45059 +NETWORK_BACKEND_WRITE(win32transmitfile);
45060 +NETWORK_BACKEND_WRITE(win32send);
45061  
45062 +NETWORK_BACKEND_READ(read);
45063 +NETWORK_BACKEND_READ(win32recv);
45064  
45065 -int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq);
45066 -int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq);
45067 -int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq);
45068 -int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq);
45069 -int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq);
45070  #ifdef USE_OPENSSL
45071 -int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq);
45072 +NETWORK_BACKEND_WRITE(openssl);
45073 +NETWORK_BACKEND_READ(openssl);
45074  #endif
45075  
45076  #endif
45077 --- ../lighttpd-1.4.11/src/network_freebsd_sendfile.c   2005-10-22 12:28:18.000000000 +0300
45078 +++ lighttpd-1.4.12/src/network_freebsd_sendfile.c      2006-07-16 00:26:04.000000000 +0300
45079 @@ -26,142 +26,61 @@
45080  
45081  #ifndef UIO_MAXIOV
45082  # ifdef __FreeBSD__
45083 -/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */ 
45084 +/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */
45085  #  define UIO_MAXIOV 1024
45086  # endif
45087  #endif
45088  
45089 -int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq) {
45090 +NETWORK_BACKEND_WRITE(freebsdsendfile) {
45091         chunk *c;
45092         size_t chunks_written = 0;
45093 -       
45094 +
45095         for(c = cq->first; c; c = c->next, chunks_written++) {
45096                 int chunk_finished = 0;
45097 -               
45098 +               network_status_t ret;
45099 +
45100                 switch(c->type) {
45101 -               case MEM_CHUNK: {
45102 -                       char * offset;
45103 -                       size_t toSend;
45104 -                       ssize_t r;
45105 -                       
45106 -                       size_t num_chunks, i;
45107 -                       struct iovec chunks[UIO_MAXIOV];
45108 -                       chunk *tc;
45109 -                       size_t num_bytes = 0;
45110 -                       
45111 -                       /* we can't send more then SSIZE_MAX bytes in one chunk */
45112 -                       
45113 -                       /* build writev list 
45114 -                        * 
45115 -                        * 1. limit: num_chunks < UIO_MAXIOV
45116 -                        * 2. limit: num_bytes < SSIZE_MAX
45117 -                        */
45118 -                       for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
45119 -                       
45120 -                       for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
45121 -                               if (tc->mem->used == 0) {
45122 -                                       chunks[i].iov_base = tc->mem->ptr;
45123 -                                       chunks[i].iov_len  = 0;
45124 -                               } else {
45125 -                                       offset = tc->mem->ptr + tc->offset;
45126 -                                       toSend = tc->mem->used - 1 - tc->offset;
45127 -                                       
45128 -                                       chunks[i].iov_base = offset;
45129 -                                       
45130 -                                       /* protect the return value of writev() */
45131 -                                       if (toSend > SSIZE_MAX ||
45132 -                                           num_bytes + toSend > SSIZE_MAX) {
45133 -                                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
45134 -                                               
45135 -                                               num_chunks = i + 1;
45136 -                                               break;
45137 -                                       } else {
45138 -                                               chunks[i].iov_len = toSend;
45139 -                                       }
45140 -                                
45141 -                                       num_bytes += toSend;
45142 -                               }
45143 -                       }
45144 -                       
45145 -                       if ((r = writev(fd, chunks, num_chunks)) < 0) {
45146 -                               switch (errno) {
45147 -                               case EAGAIN:
45148 -                               case EINTR:
45149 -                                       r = 0;
45150 -                                       break;
45151 -                               case EPIPE:
45152 -                               case ECONNRESET:
45153 -                                       return -2;
45154 -                               default:
45155 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
45156 -                                                       "writev failed:", strerror(errno), fd);
45157 -                                       
45158 -                                       return -1;
45159 -                               }
45160 +               case MEM_CHUNK:
45161 +                       ret = network_write_chunkqueue_writev_mem(srv, con, fd, cq, &c);
45162  
45163 -                               r = 0;
45164 -                       }
45165 -                       
45166 -                       /* check which chunks have been written */
45167 -                       cq->bytes_out += r;
45168 -                       
45169 -                       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
45170 -                               if (r >= (ssize_t)chunks[i].iov_len) {
45171 -                                       /* written */
45172 -                                       r -= chunks[i].iov_len;
45173 -                                       tc->offset += chunks[i].iov_len;
45174 -                                       
45175 -                                       if (chunk_finished) {
45176 -                                               /* skip the chunks from further touches */
45177 -                                               chunks_written++;
45178 -                                               c = c->next;
45179 -                                       } else {
45180 -                                               /* chunks_written + c = c->next is done in the for()*/
45181 -                                               chunk_finished++;
45182 -                                       }
45183 -                               } else {
45184 -                                       /* partially written */
45185 -                                       
45186 -                                       tc->offset += r;
45187 -                                       chunk_finished = 0;
45188 -                                       
45189 -                                       break;
45190 -                               }
45191 +                       if (ret != NETWORK_STATUS_SUCCESS) {
45192 +                               return ret;
45193                         }
45194 -                       
45195 +
45196 +                       chunk_finished = 1;
45197 +
45198                         break;
45199 -               }
45200                 case FILE_CHUNK: {
45201                         off_t offset, r;
45202                         size_t toSend;
45203                         stat_cache_entry *sce = NULL;
45204                         int ifd;
45205 -                       
45206 +
45207                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
45208                                 log_error_write(srv, __FILE__, __LINE__, "sb",
45209                                                 strerror(errno), c->file.name);
45210 -                               return -1;
45211 +                               return NETWORK_STATUS_FATAL_ERROR;
45212                         }
45213 -                       
45214 +
45215                         offset = c->file.start + c->offset;
45216                         /* limit the toSend to 2^31-1 bytes in a chunk */
45217 -                       toSend = c->file.length - c->offset > ((1 << 30) - 1) ? 
45218 +                       toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
45219                                 ((1 << 30) - 1) : c->file.length - c->offset;
45220 -                               
45221 +
45222                         if (offset > sce->st.st_size) {
45223                                 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
45224 -                               
45225 -                               return -1;
45226 +
45227 +                               return NETWORK_STATUS_FATAL_ERROR;
45228                         }
45229 -                       
45230 +
45231                         if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
45232                                 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
45233 -                               
45234 -                               return -1;
45235 +
45236 +                               return NETWORK_STATUS_FATAL_ERROR;
45237                         }
45238 -                       
45239 +
45240                         r = 0;
45241 -                       
45242 +
45243                         /* FreeBSD sendfile() */
45244                         if (-1 == sendfile(ifd, fd, offset, toSend, NULL, &r, 0)) {
45245                                 switch(errno) {
45246 @@ -169,39 +88,39 @@
45247                                         break;
45248                                 case ENOTCONN:
45249                                         close(ifd);
45250 -                                       return -2;
45251 +                                       return NETWORK_STATUS_CONNECTION_CLOSE;
45252                                 default:
45253                                         log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
45254                                         close(ifd);
45255 -                                       return -1;
45256 +                                       return NETWORK_STATUS_FATAL_ERROR;
45257                                 }
45258                         }
45259                         close(ifd);
45260 -                       
45261 +
45262                         c->offset += r;
45263                         cq->bytes_out += r;
45264 -                       
45265 +
45266                         if (c->offset == c->file.length) {
45267                                 chunk_finished = 1;
45268                         }
45269 -                       
45270 +
45271                         break;
45272                 }
45273                 default:
45274 -                       
45275 +
45276                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
45277 -                       
45278 +
45279                         return -1;
45280                 }
45281 -               
45282 +
45283                 if (!chunk_finished) {
45284                         /* not finished yet */
45285 -                       
45286 +
45287                         break;
45288                 }
45289         }
45290  
45291 -       return chunks_written;
45292 +       return NETWORK_STATUS_SUCCESS;
45293  }
45294  
45295  #endif
45296 --- ../lighttpd-1.4.11/src/network_linux_sendfile.c     2006-02-15 20:02:36.000000000 +0200
45297 +++ lighttpd-1.4.12/src/network_linux_sendfile.c        2006-07-18 13:03:40.000000000 +0300
45298 @@ -26,122 +26,54 @@
45299  /* on linux 2.4.29 + debian/ubuntu we have crashes if this is enabled */
45300  #undef HAVE_POSIX_FADVISE
45301  
45302 -int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq) {
45303 -       chunk *c;
45304 +NETWORK_BACKEND_WRITE(linuxsendfile) {
45305 +       chunk *c, *tc;
45306         size_t chunks_written = 0;
45307 -       
45308 +
45309         for(c = cq->first; c; c = c->next, chunks_written++) {
45310                 int chunk_finished = 0;
45311 -               
45312 +               network_status_t ret;
45313 +
45314                 switch(c->type) {
45315 -               case MEM_CHUNK: {
45316 -                       char * offset;
45317 -                       size_t toSend;
45318 -                       ssize_t r;
45319 -                       
45320 -                       size_t num_chunks, i;
45321 -                       struct iovec chunks[UIO_MAXIOV];
45322 -                       chunk *tc;
45323 -                       size_t num_bytes = 0;
45324 -                       
45325 -                       /* we can't send more then SSIZE_MAX bytes in one chunk */
45326 -                       
45327 -                       /* build writev list 
45328 -                        * 
45329 -                        * 1. limit: num_chunks < UIO_MAXIOV
45330 -                        * 2. limit: num_bytes < SSIZE_MAX
45331 -                        */
45332 -                       for (num_chunks = 0, tc = c; 
45333 -                            tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; 
45334 -                            tc = tc->next, num_chunks++);
45335 -                       
45336 -                       for (tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
45337 -                               if (tc->mem->used == 0) {
45338 -                                       chunks[i].iov_base = tc->mem->ptr;
45339 -                                       chunks[i].iov_len  = 0;
45340 -                               } else {
45341 -                                       offset = tc->mem->ptr + tc->offset;
45342 -                                       toSend = tc->mem->used - 1 - tc->offset;
45343 -                               
45344 -                                       chunks[i].iov_base = offset;
45345 -                                       
45346 -                                       /* protect the return value of writev() */
45347 -                                       if (toSend > SSIZE_MAX ||
45348 -                                           num_bytes + toSend > SSIZE_MAX) {
45349 -                                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
45350 -                                               
45351 -                                               num_chunks = i + 1;
45352 -                                               break;
45353 -                                       } else {
45354 -                                               chunks[i].iov_len = toSend;
45355 -                                       }
45356 -                                
45357 -                                       num_bytes += toSend;
45358 -                               }
45359 -                       }
45360 -                       
45361 -                       if ((r = writev(fd, chunks, num_chunks)) < 0) {
45362 -                               switch (errno) {
45363 -                               case EAGAIN:
45364 -                               case EINTR:
45365 -                                       r = 0;
45366 -                                       break;
45367 -                               case EPIPE:
45368 -                               case ECONNRESET:
45369 -                                       return -2;
45370 -                               default:
45371 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
45372 -                                                       "writev failed:", strerror(errno), fd);
45373 -                               
45374 -                                       return -1;
45375 -                               }
45376 -                       }
45377 -                       
45378 -                       /* check which chunks have been written */
45379 -                       cq->bytes_out += r;
45380 +               case MEM_CHUNK:
45381 +                       ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
45382  
45383 -                       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
45384 -                               if (r >= (ssize_t)chunks[i].iov_len) {
45385 -                                       /* written */
45386 -                                       r -= chunks[i].iov_len;
45387 -                                       tc->offset += chunks[i].iov_len;
45388 -                                       
45389 +                       /* check which chunks are finished now */
45390 +                       for (tc = c; tc; tc = tc->next) {
45391 +                               /* finished the chunk */
45392 +                               if (tc->offset == tc->mem->used - 1) {
45393 +                                       /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
45394                                         if (chunk_finished) {
45395 -                                               /* skip the chunks from further touches */
45396 -                                               chunks_written++;
45397                                                 c = c->next;
45398                                         } else {
45399 -                                               /* chunks_written + c = c->next is done in the for()*/
45400 -                                               chunk_finished++;
45401 +                                               chunk_finished = 1;
45402                                         }
45403                                 } else {
45404 -                                       /* partially written */
45405 -                                       
45406 -                                       tc->offset += r;
45407 -                                       chunk_finished = 0;
45408 -                                       
45409                                         break;
45410                                 }
45411                         }
45412 -                       
45413 +
45414 +                       if (ret != NETWORK_STATUS_SUCCESS) {
45415 +                               return ret;
45416 +                       }
45417 +
45418                         break;
45419 -               }
45420                 case FILE_CHUNK: {
45421                         ssize_t r;
45422                         off_t offset;
45423                         size_t toSend;
45424                         stat_cache_entry *sce = NULL;
45425 -                       
45426 +
45427                         offset = c->file.start + c->offset;
45428                         /* limit the toSend to 2^31-1 bytes in a chunk */
45429 -                       toSend = c->file.length - c->offset > ((1 << 30) - 1) ? 
45430 +                       toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
45431                                 ((1 << 30) - 1) : c->file.length - c->offset;
45432 -                               
45433 -                       /* open file if not already opened */   
45434 +
45435 +                       /* open file if not already opened */
45436                         if (-1 == c->file.fd) {
45437                                 if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
45438                                         log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
45439 -                               
45440 +
45441                                         return -1;
45442                                 }
45443  #ifdef FD_CLOEXEC
45444 @@ -151,14 +83,14 @@
45445                                 /* tell the kernel that we want to stream the file */
45446                                 if (-1 == posix_fadvise(c->file.fd, 0, 0, POSIX_FADV_SEQUENTIAL)) {
45447                                         if (ENOSYS != errno) {
45448 -                                               log_error_write(srv, __FILE__, __LINE__, "ssd", 
45449 +                                               log_error_write(srv, __FILE__, __LINE__, "ssd",
45450                                                         "posix_fadvise failed:", strerror(errno), c->file.fd);
45451                                         }
45452                                 }
45453  #endif
45454                         }
45455  
45456 -                       if (-1 == (r = sendfile(fd, c->file.fd, &offset, toSend))) {
45457 +                       if (-1 == (r = sendfile(sock->fd, c->file.fd, &offset, toSend))) {
45458                                 switch (errno) {
45459                                 case EAGAIN:
45460                                 case EINTR:
45461 @@ -166,11 +98,11 @@
45462                                         break;
45463                                 case EPIPE:
45464                                 case ECONNRESET:
45465 -                                       return -2;
45466 +                                       return NETWORK_STATUS_CONNECTION_CLOSE;
45467                                 default:
45468 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
45469 -                                                       "sendfile failed:", strerror(errno), fd);
45470 -                                       return -1;
45471 +                                       log_error_write(srv, __FILE__, __LINE__, "ssd",
45472 +                                                       "sendfile failed:", strerror(errno), sock->fd);
45473 +                                       return NETWORK_STATUS_FATAL_ERROR;
45474                                 }
45475                         }
45476  
45477 @@ -179,39 +111,39 @@
45478                                  *
45479                                  * - the file shrinked -> error
45480                                  * - the remote side closed inbetween -> remote-close */
45481 -       
45482 +
45483                                 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
45484                                         /* file is gone ? */
45485 -                                       return -1;
45486 +                                       return NETWORK_STATUS_FATAL_ERROR;
45487                                 }
45488  
45489                                 if (offset > sce->st.st_size) {
45490                                         /* file shrinked, close the connection */
45491 -                                       return -1;
45492 +                                       return NETWORK_STATUS_FATAL_ERROR;
45493                                 }
45494  
45495 -                               return -2;
45496 +                               return NETWORK_STATUS_CONNECTION_CLOSE;
45497                         }
45498  
45499  #ifdef HAVE_POSIX_FADVISE
45500  #if 0
45501  #define K * 1024
45502 -#define M * 1024 K     
45503 +#define M * 1024 K
45504  #define READ_AHEAD 4 M
45505                         /* check if we need a new chunk */
45506                         if ((c->offset & ~(READ_AHEAD - 1)) != ((c->offset + r) & ~(READ_AHEAD - 1))) {
45507                                 /* tell the kernel that we want to stream the file */
45508                                 if (-1 == posix_fadvise(c->file.fd, (c->offset + r) & ~(READ_AHEAD - 1), READ_AHEAD, POSIX_FADV_NOREUSE)) {
45509 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
45510 +                                       log_error_write(srv, __FILE__, __LINE__, "ssd",
45511                                                 "posix_fadvise failed:", strerror(errno), c->file.fd);
45512                                 }
45513                         }
45514  #endif
45515  #endif
45516 -                       
45517 +
45518                         c->offset += r;
45519                         cq->bytes_out += r;
45520 -                       
45521 +
45522                         if (c->offset == c->file.length) {
45523                                 chunk_finished = 1;
45524  
45525 @@ -222,24 +154,24 @@
45526                                         c->file.fd = -1;
45527                                 }
45528                         }
45529 -                       
45530 +
45531                         break;
45532                 }
45533                 default:
45534 -                       
45535 +
45536                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
45537 -                       
45538 -                       return -1;
45539 +
45540 +                       return NETWORK_STATUS_FATAL_ERROR;
45541                 }
45542 -               
45543 +
45544                 if (!chunk_finished) {
45545                         /* not finished yet */
45546 -                       
45547 -                       break;
45548 +
45549 +                       return NETWORK_STATUS_WAIT_FOR_EVENT;
45550                 }
45551         }
45552  
45553 -       return chunks_written;
45554 +       return NETWORK_STATUS_SUCCESS;
45555  }
45556  
45557  #endif
45558 --- ../lighttpd-1.4.11/src/network_openssl.c    2005-11-17 14:53:29.000000000 +0200
45559 +++ lighttpd-1.4.12/src/network_openssl.c       2006-07-18 13:03:40.000000000 +0300
45560 @@ -23,17 +23,87 @@
45561  #include "log.h"
45562  #include "stat_cache.h"
45563  
45564 -# include <openssl/ssl.h> 
45565 -# include <openssl/err.h> 
45566 +# include <openssl/ssl.h>
45567 +# include <openssl/err.h>
45568  
45569 -int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq) {
45570 +NETWORK_BACKEND_READ(openssl) {
45571 +       buffer *b;
45572 +       off_t len;
45573 +
45574 +       b = chunkqueue_get_append_buffer(cq);
45575 +       buffer_prepare_copy(b, 8192);
45576 +       len = SSL_read(sock->ssl, b->ptr, b->size - 1);
45577 +
45578 +       log_error_write(srv, __FILE__, __LINE__, "so", "SSL:", len);
45579 +
45580 +       if (len < 0) {
45581 +               int r, ssl_err;
45582 +
45583 +               switch ((r = SSL_get_error(sock->ssl, len))) {
45584 +               case SSL_ERROR_WANT_READ:
45585 +                       return NETWORK_STATUS_WAIT_FOR_EVENT;
45586 +               case SSL_ERROR_SYSCALL:
45587 +                       /**
45588 +                        * man SSL_get_error()
45589 +                        *
45590 +                        * SSL_ERROR_SYSCALL
45591 +                        *   Some I/O error occurred.  The OpenSSL error queue may contain more
45592 +                        *   information on the error.  If the error queue is empty (i.e.
45593 +                        *   ERR_get_error() returns 0), ret can be used to find out more about
45594 +                        *   the error: If ret == 0, an EOF was observed that violates the
45595 +                        *   protocol.  If ret == -1, the underlying BIO reported an I/O error
45596 +                        *   (for socket I/O on Unix systems, consult errno for details).
45597 +                        *
45598 +                        */
45599 +                       while((ssl_err = ERR_get_error())) {
45600 +                               /* get all errors from the error-queue */
45601 +                               log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
45602 +                                               r, ERR_error_string(ssl_err, NULL));
45603 +                       }
45604 +
45605 +                       switch(errno) {
45606 +                       default:
45607 +                               log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
45608 +                                               len, r, errno,
45609 +                                               strerror(errno));
45610 +                               break;
45611 +                       }
45612 +
45613 +                       break;
45614 +               case SSL_ERROR_ZERO_RETURN:
45615 +                       /* clean shutdown on the remote side */
45616 +
45617 +                       if (r == 0) {
45618 +                               /* FIXME: later */
45619 +                       }
45620 +
45621 +                       /* fall thourgh */
45622 +               default:
45623 +                       while((ssl_err = ERR_get_error())) {
45624 +                               /* get all errors from the error-queue */
45625 +                               log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
45626 +                                               r, ERR_error_string(ssl_err, NULL));
45627 +                       }
45628 +                       break;
45629 +               }
45630 +       }
45631 +
45632 +       assert(len > 0);
45633 +       b->used += len;
45634 +       b->ptr[b->used - 1] = '\0';
45635 +
45636 +       return NETWORK_STATUS_SUCCESS;
45637 +}
45638 +
45639 +
45640 +NETWORK_BACKEND_WRITE(openssl) {
45641         int ssl_r;
45642         chunk *c;
45643         size_t chunks_written = 0;
45644  
45645         /* this is a 64k sendbuffer
45646          *
45647 -        * it has to stay at the same location all the time to satisfy the needs 
45648 +        * it has to stay at the same location all the time to satisfy the needs
45649          * of SSL_write to pass the SAME parameter in case of a _WANT_WRITE
45650          *
45651          * the buffer is allocated once, is NOT realloced and is NOT freed at shutdown
45652 @@ -43,59 +113,61 @@
45653          * In reality we would like to use mmap() but we don't have a guarantee that
45654          * we get the same mmap() address for each call. On openbsd the mmap() address
45655          * even randomized.
45656 -        *   That means either we keep the mmap() open or we do a read() into a 
45657 -        * constant buffer 
45658 +        *   That means either we keep the mmap() open or we do a read() into a
45659 +        * constant buffer
45660          * */
45661  #define LOCAL_SEND_BUFSIZE (64 * 1024)
45662         static char *local_send_buffer = NULL;
45663  
45664         /* the remote side closed the connection before without shutdown request
45665 -        * - IE 
45666 +        * - IE
45667          * - wget
45668          * if keep-alive is disabled */
45669  
45670         if (con->keep_alive == 0) {
45671 -               SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
45672 +               SSL_set_shutdown(sock->ssl, SSL_RECEIVED_SHUTDOWN);
45673         }
45674  
45675         for(c = cq->first; c; c = c->next) {
45676                 int chunk_finished = 0;
45677 -               
45678 +
45679                 switch(c->type) {
45680                 case MEM_CHUNK: {
45681                         char * offset;
45682                         size_t toSend;
45683 -                       ssize_t r;
45684 -                       
45685 +                       ssize_t r = 0;
45686 +
45687                         if (c->mem->used == 0) {
45688                                 chunk_finished = 1;
45689                                 break;
45690                         }
45691 -                       
45692 +
45693                         offset = c->mem->ptr + c->offset;
45694                         toSend = c->mem->used - 1 - c->offset;
45695 -                       
45696 +
45697                         /**
45698                          * SSL_write man-page
45699 -                        * 
45700 +                        *
45701                          * WARNING
45702                          *        When an SSL_write() operation has to be repeated because of
45703                          *        SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be
45704                          *        repeated with the same arguments.
45705 -                        * 
45706 +                        *
45707 +                        * SSL_write(..., 0) return 0 which is handle as an error (Success)
45708 +                        * checking toSend and not calling SSL_write() is simpler
45709                          */
45710 -                       
45711 -                       if ((r = SSL_write(ssl, offset, toSend)) <= 0) {
45712 +
45713 +                       if (toSend != 0 && (r = SSL_write(sock->ssl, offset, toSend)) <= 0) {
45714                                 unsigned long err;
45715  
45716 -                               switch ((ssl_r = SSL_get_error(ssl, r))) {
45717 +                               switch ((ssl_r = SSL_get_error(sock->ssl, r))) {
45718                                 case SSL_ERROR_WANT_WRITE:
45719                                         break;
45720                                 case SSL_ERROR_SYSCALL:
45721                                         /* perhaps we have error waiting in our error-queue */
45722                                         if (0 != (err = ERR_get_error())) {
45723                                                 do {
45724 -                                                       log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", 
45725 +                                                       log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45726                                                                         ssl_r, r,
45727                                                                         ERR_error_string(err, NULL));
45728                                                 } while((err = ERR_get_error()));
45729 @@ -105,43 +177,43 @@
45730                                                 case EPIPE:
45731                                                         return -2;
45732                                                 default:
45733 -                                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", 
45734 +                                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
45735                                                                         ssl_r, r, errno,
45736                                                                         strerror(errno));
45737                                                         break;
45738                                                 }
45739                                         } else {
45740                                                 /* neither error-queue nor errno ? */
45741 -                                               log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):", 
45742 +                                               log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
45743                                                                 ssl_r, r, errno,
45744                                                                 strerror(errno));
45745                                         }
45746 -                                       
45747 +
45748                                         return  -1;
45749                                 case SSL_ERROR_ZERO_RETURN:
45750                                         /* clean shutdown on the remote side */
45751 -                                       
45752 +
45753                                         if (r == 0) return -2;
45754 -                                       
45755 +
45756                                         /* fall through */
45757                                 default:
45758                                         while((err = ERR_get_error())) {
45759 -                                               log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", 
45760 +                                               log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45761                                                                 ssl_r, r,
45762                                                                 ERR_error_string(err, NULL));
45763                                         }
45764 -                                       
45765 +
45766                                         return  -1;
45767                                 }
45768                         } else {
45769                                 c->offset += r;
45770                                 cq->bytes_out += r;
45771                         }
45772 -                       
45773 +
45774                         if (c->offset == (off_t)c->mem->used - 1) {
45775                                 chunk_finished = 1;
45776                         }
45777 -                       
45778 +
45779                         break;
45780                 }
45781                 case FILE_CHUNK: {
45782 @@ -150,7 +222,7 @@
45783                         stat_cache_entry *sce = NULL;
45784                         int ifd;
45785                         int write_wait = 0;
45786 -                       
45787 +
45788                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
45789                                 log_error_write(srv, __FILE__, __LINE__, "sb",
45790                                                 strerror(errno), c->file.name);
45791 @@ -164,13 +236,13 @@
45792  
45793                         do {
45794                                 off_t offset = c->file.start + c->offset;
45795 -                               off_t toSend = c->file.length - c->offset; 
45796 +                               off_t toSend = c->file.length - c->offset;
45797  
45798                                 if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE;
45799 -                       
45800 +
45801                                 if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
45802                                         log_error_write(srv, __FILE__, __LINE__, "ss", "open failed:", strerror(errno));
45803 -                               
45804 +
45805                                         return -1;
45806                                 }
45807  
45808 @@ -183,13 +255,13 @@
45809                                 }
45810  
45811                                 s = local_send_buffer;
45812 -                       
45813 +
45814                                 close(ifd);
45815 -                       
45816 -                               if ((r = SSL_write(ssl, s, toSend)) <= 0) {
45817 +
45818 +                               if ((r = SSL_write(sock->ssl, s, toSend)) <= 0) {
45819                                         unsigned long err;
45820  
45821 -                                       switch ((ssl_r = SSL_get_error(ssl, r))) {
45822 +                                       switch ((ssl_r = SSL_get_error(sock->ssl, r))) {
45823                                         case SSL_ERROR_WANT_WRITE:
45824                                                 write_wait = 1;
45825                                                 break;
45826 @@ -197,7 +269,7 @@
45827                                                 /* perhaps we have error waiting in our error-queue */
45828                                                 if (0 != (err = ERR_get_error())) {
45829                                                         do {
45830 -                                                               log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", 
45831 +                                                               log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45832                                                                                 ssl_r, r,
45833                                                                                 ERR_error_string(err, NULL));
45834                                                         } while((err = ERR_get_error()));
45835 @@ -207,62 +279,62 @@
45836                                                         case EPIPE:
45837                                                                 return -2;
45838                                                         default:
45839 -                                                               log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", 
45840 +                                                               log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
45841                                                                                 ssl_r, r, errno,
45842                                                                                 strerror(errno));
45843                                                                 break;
45844                                                         }
45845                                                 } else {
45846                                                         /* neither error-queue nor errno ? */
45847 -                                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):", 
45848 +                                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
45849                                                                         ssl_r, r, errno,
45850                                                                         strerror(errno));
45851                                                 }
45852 -                                       
45853 +
45854                                                 return  -1;
45855                                         case SSL_ERROR_ZERO_RETURN:
45856                                                 /* clean shutdown on the remote side */
45857 -                                       
45858 +
45859                                                 if (r == 0)  return -2;
45860 -                                       
45861 +
45862                                                 /* fall thourgh */
45863                                         default:
45864                                                 while((err = ERR_get_error())) {
45865 -                                                       log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", 
45866 +                                                       log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45867                                                                         ssl_r, r,
45868                                                                         ERR_error_string(err, NULL));
45869                                                 }
45870 -                                       
45871 +
45872                                                 return -1;
45873                                         }
45874                                 } else {
45875                                         c->offset += r;
45876                                         cq->bytes_out += r;
45877                                 }
45878 -                       
45879 +
45880                                 if (c->offset == c->file.length) {
45881                                         chunk_finished = 1;
45882                                 }
45883                         } while(!chunk_finished && !write_wait);
45884 -                       
45885 +
45886                         break;
45887                 }
45888                 default:
45889                         log_error_write(srv, __FILE__, __LINE__, "s", "type not known");
45890 -                       
45891 +
45892                         return -1;
45893                 }
45894 -                       
45895 +
45896                 if (!chunk_finished) {
45897                         /* not finished yet */
45898 -                       
45899 +
45900                         break;
45901                 }
45902 -                       
45903 +
45904                 chunks_written++;
45905         }
45906  
45907 -       return chunks_written;
45908 +       return NETWORK_STATUS_SUCCESS;
45909  }
45910  #endif
45911  
45912 --- ../lighttpd-1.4.11/src/network_solaris_sendfilev.c  2005-10-22 12:28:27.000000000 +0300
45913 +++ lighttpd-1.4.12/src/network_solaris_sendfilev.c     2006-07-16 00:26:04.000000000 +0300
45914 @@ -29,114 +29,34 @@
45915  #endif
45916  
45917  /**
45918 - * a very simple sendfilev() interface for solaris which can be optimised a lot more 
45919 + * a very simple sendfilev() interface for solaris which can be optimised a lot more
45920   * as solaris sendfilev() supports 'sending everythin in one syscall()'
45921 - * 
45922 - * If you want such an interface and need the performance, just give me an account on 
45923 - * a solaris box. 
45924 + *
45925 + * If you want such an interface and need the performance, just give me an account on
45926 + * a solaris box.
45927   *   - jan@kneschke.de
45928   */
45929  
45930  
45931 -int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq) {
45932 +NETWORK_BACKEND_WRITE(solarissendfilev) {
45933         chunk *c;
45934         size_t chunks_written = 0;
45935 -       
45936 +
45937         for(c = cq->first; c; c = c->next, chunks_written++) {
45938                 int chunk_finished = 0;
45939 -               
45940 +               network_status_t ret;
45941 +
45942                 switch(c->type) {
45943 -               case MEM_CHUNK: {
45944 -                       char * offset;
45945 -                       size_t toSend;
45946 -                       ssize_t r;
45947 -                       
45948 -                       size_t num_chunks, i;
45949 -                       struct iovec chunks[UIO_MAXIOV];
45950 -                       chunk *tc;
45951 -                       
45952 -                       size_t num_bytes = 0;
45953 -                       
45954 -                       /* we can't send more then SSIZE_MAX bytes in one chunk */
45955 -                       
45956 -                       /* build writev list 
45957 -                        * 
45958 -                        * 1. limit: num_chunks < UIO_MAXIOV
45959 -                        * 2. limit: num_bytes < SSIZE_MAX
45960 -                        */
45961 -                       for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
45962 -                       
45963 -                       for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
45964 -                               if (tc->mem->used == 0) {
45965 -                                       chunks[i].iov_base = tc->mem->ptr;
45966 -                                       chunks[i].iov_len  = 0;
45967 -                               } else {
45968 -                                       offset = tc->mem->ptr + tc->offset;
45969 -                                       toSend = tc->mem->used - 1 - tc->offset;
45970 -                               
45971 -                                       chunks[i].iov_base = offset;
45972 -                                       
45973 -                                       /* protect the return value of writev() */
45974 -                                       if (toSend > SSIZE_MAX ||
45975 -                                           num_bytes + toSend > SSIZE_MAX) {
45976 -                                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
45977 -                                               
45978 -                                               num_chunks = i + 1;
45979 -                                               break;
45980 -                                       } else {
45981 -                                               chunks[i].iov_len = toSend;
45982 -                                       }
45983 -                                       
45984 -                                       num_bytes += toSend;
45985 -                               }
45986 -                       }
45987 -                       
45988 -                       if ((r = writev(fd, chunks, num_chunks)) < 0) {
45989 -                               switch (errno) {
45990 -                               case EAGAIN:
45991 -                               case EINTR:
45992 -                                       r = 0;
45993 -                                       break;
45994 -                               case EPIPE:
45995 -                               case ECONNRESET:
45996 -                                       return -2;
45997 -                               default:
45998 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
45999 -                                                       "writev failed:", strerror(errno), fd);
46000 -                               
46001 -                                       return -1;
46002 -                               }
46003 -                       }
46004 -                       
46005 -                       /* check which chunks have been written */
46006 -                       cq->bytes_out += r;
46007 -                       
46008 -                       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
46009 -                               if (r >= (ssize_t)chunks[i].iov_len) {
46010 -                                       /* written */
46011 -                                       r -= chunks[i].iov_len;
46012 -                                       tc->offset += chunks[i].iov_len;
46013 -                                       
46014 -                                       if (chunk_finished) {
46015 -                                               /* skip the chunks from further touches */
46016 -                                               chunks_written++;
46017 -                                               c = c->next;
46018 -                                       } else {
46019 -                                               /* chunks_written + c = c->next is done in the for()*/
46020 -                                               chunk_finished++;
46021 -                                       }
46022 -                               } else {
46023 -                                       /* partially written */
46024 -                                       
46025 -                                       tc->offset += r;
46026 -                                       chunk_finished = 0;
46027 -                                       
46028 -                                       break;
46029 -                               }
46030 +               case MEM_CHUNK:
46031 +                       ret = network_write_chunkqueue_writev_mem(srv, con, fd, cq, &c);
46032 +
46033 +                       if (ret != NETWORK_STATUS_SUCCESS) {
46034 +                               return ret;
46035                         }
46036 -                       
46037 +
46038 +                       chunk_finished = 1;
46039 +
46040                         break;
46041 -               }
46042                 case FILE_CHUNK: {
46043                         ssize_t r;
46044                         off_t offset;
46045 @@ -144,25 +64,25 @@
46046                         sendfilevec_t fvec;
46047                         stat_cache_entry *sce = NULL;
46048                         int ifd;
46049 -                       
46050 +
46051                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
46052                                 log_error_write(srv, __FILE__, __LINE__, "sb",
46053                                                 strerror(errno), c->file.name);
46054                                 return -1;
46055                         }
46056 -                                       
46057 +
46058                         offset = c->file.start + c->offset;
46059                         toSend = c->file.length - c->offset;
46060 -                       
46061 +
46062                         if (offset > sce->st.st_size) {
46063                                 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
46064 -                               
46065 +
46066                                 return -1;
46067                         }
46068  
46069                         if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
46070                                 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
46071 -                               
46072 +
46073                                 return -1;
46074                         }
46075  
46076 @@ -170,44 +90,43 @@
46077                         fvec.sfv_flag = 0;
46078                         fvec.sfv_off = offset;
46079                         fvec.sfv_len = toSend;
46080 -                       
46081 +
46082                         /* Solaris sendfilev() */
46083                         if (-1 == (r = sendfilev(fd, &fvec, 1, &written))) {
46084                                 if (errno != EAGAIN) {
46085                                         log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
46086 -                                       
46087 +
46088                                         close(ifd);
46089 -                                       return -1;
46090 +                                       return NETWORK_STATUS_FATAL_ERROR;
46091                                 }
46092 -                               
46093 +
46094                                 r = 0;
46095                         }
46096 -                       
46097 +
46098                         close(ifd);
46099                         c->offset += written;
46100                         cq->bytes_out += written;
46101 -                       
46102 +
46103                         if (c->offset == c->file.length) {
46104                                 chunk_finished = 1;
46105                         }
46106 -                       
46107 +
46108                         break;
46109                 }
46110                 default:
46111 -                       
46112                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
46113 -                       
46114 -                       return -1;
46115 +
46116 +                       return NETWORK_STATUS_FATAL_ERROR;
46117                 }
46118 -               
46119 +
46120                 if (!chunk_finished) {
46121                         /* not finished yet */
46122 -                       
46123 +
46124                         break;
46125                 }
46126         }
46127  
46128 -       return chunks_written;
46129 +       return NETWORK_STATUS_SUCCESS;
46130  }
46131  
46132  #endif
46133 --- ../lighttpd-1.4.11/src/network_write.c      2005-10-22 12:27:56.000000000 +0300
46134 +++ lighttpd-1.4.12/src/network_write.c 2006-07-18 13:03:40.000000000 +0300
46135 @@ -1,11 +1,11 @@
46136  #include <sys/types.h>
46137  #include <sys/stat.h>
46138 -#include <sys/time.h>
46139 +
46140  #include <errno.h>
46141  #include <fcntl.h>
46142 -#include <unistd.h>
46143  #include <string.h>
46144  #include <stdlib.h>
46145 +#include <assert.h>
46146  
46147  #include "network.h"
46148  #include "fdevent.h"
46149 @@ -13,9 +13,12 @@
46150  #include "stat_cache.h"
46151  
46152  #include "sys-socket.h"
46153 +#include "sys-files.h"
46154  
46155  #include "network_backends.h"
46156  
46157 +#ifdef USE_WRITE
46158 +
46159  #ifdef HAVE_SYS_FILIO_H
46160  # include <sys/filio.h>
46161  #endif
46162 @@ -24,47 +27,92 @@
46163  #include <sys/resource.h>
46164  #endif
46165  
46166 -int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq) {
46167 +
46168 +/**
46169 +* fill the chunkqueue will all the data that we can get
46170 +*
46171 +* this might be optimized into a readv() which uses the chunks
46172 +* as vectors
46173 +*/
46174 +NETWORK_BACKEND_READ(read) {
46175 +       int toread;
46176 +       buffer *b;
46177 +       off_t r;
46178 +
46179 +       /**
46180 +        * a EAGAIN is a successful read if we already read something to the chunkqueue
46181 +        */
46182 +       int read_something = 0;
46183 +
46184 +       /* use a chunk-size of 8k */
46185 +       do {
46186 +               toread = 8192;
46187 +
46188 +               b = chunkqueue_get_append_buffer(cq);
46189 +
46190 +               buffer_prepare_copy(b, toread);
46191 +
46192 +               if (-1 == (r = read(sock->fd, b->ptr, toread))) {
46193 +                       switch (errno) {
46194 +                       case EAGAIN:
46195 +                               /* remove the last chunk from the chunkqueue */
46196 +                               chunkqueue_remove_empty_last_chunk(cq);
46197 +                               return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_WAIT_FOR_EVENT;
46198 +                       default:
46199 +                               ERROR("oops, read from fd=%d failed: %s (%d)", sock->fd, strerror(errno), errno );
46200 +
46201 +                               return NETWORK_STATUS_FATAL_ERROR;
46202 +                       }
46203 +               }
46204 +
46205 +               if (r == 0) {
46206 +                       chunkqueue_remove_empty_last_chunk(cq);
46207 +                       return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_CONNECTION_CLOSE;
46208 +               }
46209 +
46210 +               read_something = 1;
46211 +
46212 +               b->used = r;
46213 +               b->ptr[b->used++] = '\0';
46214 +       } while (r == toread); 
46215 +
46216 +       return NETWORK_STATUS_SUCCESS;
46217 +}
46218 +
46219 +NETWORK_BACKEND_WRITE(write) {
46220         chunk *c;
46221         size_t chunks_written = 0;
46222 -       
46223 +
46224         for(c = cq->first; c; c = c->next) {
46225                 int chunk_finished = 0;
46226 -               
46227 +
46228                 switch(c->type) {
46229                 case MEM_CHUNK: {
46230                         char * offset;
46231                         size_t toSend;
46232                         ssize_t r;
46233 -                       
46234 +
46235                         if (c->mem->used == 0) {
46236                                 chunk_finished = 1;
46237                                 break;
46238                         }
46239 -                       
46240 +
46241                         offset = c->mem->ptr + c->offset;
46242                         toSend = c->mem->used - 1 - c->offset;
46243 -#ifdef __WIN32 
46244 -                       if ((r = send(fd, offset, toSend, 0)) < 0) {
46245 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd);
46246 -                               
46247 -                               return -1;
46248 -                       }
46249 -#else
46250 -                       if ((r = write(fd, offset, toSend)) < 0) {
46251 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd);
46252 -                               
46253 -                               return -1;
46254 +
46255 +                       if ((r = write(sock->fd, offset, toSend)) < 0) {
46256 +                               log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), sock->fd);
46257 +
46258 +                               return NETWORK_STATUS_FATAL_ERROR;
46259                         }
46260 -#endif
46261 -                       
46262 +
46263                         c->offset += r;
46264                         cq->bytes_out += r;
46265 -                       
46266 +
46267                         if (c->offset == (off_t)c->mem->used - 1) {
46268                                 chunk_finished = 1;
46269                         }
46270 -                       
46271 +
46272                         break;
46273                 }
46274                 case FILE_CHUNK: {
46275 @@ -76,93 +124,89 @@
46276                         size_t toSend;
46277                         stat_cache_entry *sce = NULL;
46278                         int ifd;
46279 -                       
46280 +
46281                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
46282                                 log_error_write(srv, __FILE__, __LINE__, "sb",
46283                                                 strerror(errno), c->file.name);
46284 -                               return -1;
46285 +                               return NETWORK_STATUS_FATAL_ERROR;
46286                         }
46287 -                       
46288 +
46289                         offset = c->file.start + c->offset;
46290                         toSend = c->file.length - c->offset;
46291 -                       
46292 +
46293                         if (offset > sce->st.st_size) {
46294                                 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
46295 -                               
46296 -                               return -1;
46297 +
46298 +                               return NETWORK_STATUS_FATAL_ERROR;
46299                         }
46300  
46301                         if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
46302                                 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
46303 -                               
46304 -                               return -1;
46305 +
46306 +                               return NETWORK_STATUS_FATAL_ERROR;
46307                         }
46308 -                       
46309 +
46310  #if defined USE_MMAP
46311                         if (MAP_FAILED == (p = mmap(0, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
46312                                 log_error_write(srv, __FILE__, __LINE__, "ss", "mmap failed: ", strerror(errno));
46313  
46314                                 close(ifd);
46315 -                               
46316 -                               return -1;
46317 +
46318 +                               return NETWORK_STATUS_FATAL_ERROR;
46319                         }
46320                         close(ifd);
46321  
46322 -                       if ((r = write(fd, p + offset, toSend)) <= 0) {
46323 +                       if ((r = write(sock->fd, p + offset, toSend)) <= 0) {
46324                                 log_error_write(srv, __FILE__, __LINE__, "ss", "write failed: ", strerror(errno));
46325                                 munmap(p, sce->st.st_size);
46326 -                               return -1;
46327 +                               return NETWORK_STATUS_FATAL_ERROR;
46328                         }
46329 -                       
46330 +
46331                         munmap(p, sce->st.st_size);
46332  #else
46333                         buffer_prepare_copy(srv->tmp_buf, toSend);
46334 -                       
46335 +
46336                         lseek(ifd, offset, SEEK_SET);
46337                         if (-1 == (toSend = read(ifd, srv->tmp_buf->ptr, toSend))) {
46338                                 log_error_write(srv, __FILE__, __LINE__, "ss", "read: ", strerror(errno));
46339                                 close(ifd);
46340 -                               
46341 -                               return -1;
46342 +
46343 +                               return NETWORK_STATUS_FATAL_ERROR;
46344                         }
46345                         close(ifd);
46346  
46347 -                       if (-1 == (r = send(fd, srv->tmp_buf->ptr, toSend, 0))) {
46348 +                       if (-1 == (r = send(sock->fd, srv->tmp_buf->ptr, toSend, 0))) {
46349                                 log_error_write(srv, __FILE__, __LINE__, "ss", "write: ", strerror(errno));
46350 -                               
46351 -                               return -1;
46352 +
46353 +                               return NETWORK_STATUS_FATAL_ERROR;
46354                         }
46355  #endif
46356                         c->offset += r;
46357                         cq->bytes_out += r;
46358 -                       
46359 +
46360                         if (c->offset == c->file.length) {
46361                                 chunk_finished = 1;
46362                         }
46363 -                       
46364 +
46365                         break;
46366                 }
46367                 default:
46368 -                       
46369 +
46370                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
46371 -                       
46372 -                       return -1;
46373 +
46374 +                       return NETWORK_STATUS_FATAL_ERROR;
46375                 }
46376 -               
46377 +
46378                 if (!chunk_finished) {
46379                         /* not finished yet */
46380 -                       
46381 +
46382                         break;
46383                 }
46384 -               
46385 +
46386                 chunks_written++;
46387         }
46388  
46389 -       return chunks_written;
46390 +       return NETWORK_STATUS_SUCCESS;
46391  }
46392  
46393 -#if 0
46394 -network_write_init(void) {
46395 -       p->write = network_write_write_chunkset;
46396 -}
46397  #endif
46398 --- ../lighttpd-1.4.11/src/network_writev.c     2006-02-15 01:02:36.000000000 +0200
46399 +++ lighttpd-1.4.12/src/network_writev.c        2006-07-18 13:03:40.000000000 +0300
46400 @@ -28,10 +28,10 @@
46401  
46402  #ifndef UIO_MAXIOV
46403  # if defined(__FreeBSD__) || defined(__APPLE__) || defined(__NetBSD__)
46404 -/* FreeBSD 4.7 defines it in sys/uio.h only if _KERNEL is specified */ 
46405 +/* FreeBSD 4.7 defines it in sys/uio.h only if _KERNEL is specified */
46406  #  define UIO_MAXIOV 1024
46407  # elif defined(__sgi)
46408 -/* IRIX 6.5 has sysconf(_SC_IOV_MAX) which might return 512 or bigger */ 
46409 +/* IRIX 6.5 has sysconf(_SC_IOV_MAX) which might return 512 or bigger */
46410  #  define UIO_MAXIOV 512
46411  # elif defined(__sun)
46412  /* Solaris (and SunOS?) defines IOV_MAX instead */
46413 @@ -51,105 +51,121 @@
46414  #define LOCAL_BUFFERING 1
46415  #endif
46416  
46417 -int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq) {
46418 -       chunk *c;
46419 +NETWORK_BACKEND_WRITE_CHUNK(writev_mem) {
46420 +       char * offset;
46421 +       size_t toSend;
46422 +       ssize_t r;
46423 +
46424 +       size_t num_chunks, i;
46425 +       struct iovec chunks[UIO_MAXIOV];
46426 +       chunk *tc; /* transfer chunks */
46427 +       size_t num_bytes = 0;
46428 +
46429 +       /* we can't send more then SSIZE_MAX bytes in one chunk */
46430 +
46431 +       /* build writev list
46432 +        *
46433 +        * 1. limit: num_chunks < UIO_MAXIOV
46434 +        * 2. limit: num_bytes < SSIZE_MAX
46435 +        */
46436 +       for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
46437 +
46438 +       for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
46439 +               if (tc->mem->used == 0) {
46440 +                       chunks[i].iov_base = tc->mem->ptr;
46441 +                       chunks[i].iov_len  = 0;
46442 +               } else {
46443 +                       offset = tc->mem->ptr + tc->offset;
46444 +                       toSend = tc->mem->used - 1 - tc->offset;
46445 +
46446 +                       chunks[i].iov_base = offset;
46447 +
46448 +                       /* protect the return value of writev() */
46449 +                       if (toSend > SSIZE_MAX ||
46450 +                           num_bytes + toSend > SSIZE_MAX) {
46451 +                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
46452 +
46453 +                               num_chunks = i + 1;
46454 +                               break;
46455 +                       } else {
46456 +                               chunks[i].iov_len = toSend;
46457 +                       }
46458 +
46459 +                       num_bytes += toSend;
46460 +               }
46461 +       }
46462 +
46463 +       if ((r = writev(sock->fd, chunks, num_chunks)) < 0) {
46464 +               switch (errno) {
46465 +               case EAGAIN:
46466 +                       return NETWORK_STATUS_WAIT_FOR_EVENT;
46467 +               case EINTR:
46468 +                       return NETWORK_STATUS_INTERRUPTED;
46469 +               case EPIPE:
46470 +               case ECONNRESET:
46471 +                       return NETWORK_STATUS_CONNECTION_CLOSE;
46472 +               default:
46473 +                       log_error_write(srv, __FILE__, __LINE__, "ssd",
46474 +                                       "writev failed:", strerror(errno), sock->fd);
46475 +
46476 +                       return NETWORK_STATUS_FATAL_ERROR;
46477 +               }
46478 +       }
46479 +
46480 +       cq->bytes_out += r;
46481 +
46482 +       /* check which chunks have been written */
46483 +
46484 +       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
46485 +               if (r >= (ssize_t)chunks[i].iov_len) {
46486 +                       /* written */
46487 +                       r -= chunks[i].iov_len;
46488 +                       tc->offset += chunks[i].iov_len;
46489 +               } else {
46490 +                       /* partially written */
46491 +
46492 +                       tc->offset += r;
46493 +
46494 +                       return NETWORK_STATUS_WAIT_FOR_EVENT;
46495 +               }
46496 +       }
46497 +
46498 +       /* all chunks have been pushed out */
46499 +       return NETWORK_STATUS_SUCCESS;
46500 +}
46501 +
46502 +NETWORK_BACKEND_WRITE(writev) {
46503 +       chunk *c, *tc;
46504         size_t chunks_written = 0;
46505 -       
46506 +
46507         for(c = cq->first; c; c = c->next) {
46508                 int chunk_finished = 0;
46509 -               
46510 +               network_status_t ret;
46511 +
46512                 switch(c->type) {
46513 -               case MEM_CHUNK: {
46514 -                       char * offset;
46515 -                       size_t toSend;
46516 -                       ssize_t r;
46517 -                       
46518 -                       size_t num_chunks, i;
46519 -                       struct iovec chunks[UIO_MAXIOV];
46520 -                       chunk *tc;
46521 -                       size_t num_bytes = 0;
46522 -                       
46523 -                       /* we can't send more then SSIZE_MAX bytes in one chunk */
46524 -                       
46525 -                       /* build writev list 
46526 -                        * 
46527 -                        * 1. limit: num_chunks < UIO_MAXIOV
46528 -                        * 2. limit: num_bytes < SSIZE_MAX
46529 -                        */
46530 -                       for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
46531 -                       
46532 -                       for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
46533 -                               if (tc->mem->used == 0) {
46534 -                                       chunks[i].iov_base = tc->mem->ptr;
46535 -                                       chunks[i].iov_len  = 0;
46536 -                               } else {
46537 -                                       offset = tc->mem->ptr + tc->offset;
46538 -                                       toSend = tc->mem->used - 1 - tc->offset;
46539 -                               
46540 -                                       chunks[i].iov_base = offset;
46541 -                                       
46542 -                                       /* protect the return value of writev() */
46543 -                                       if (toSend > SSIZE_MAX ||
46544 -                                           num_bytes + toSend > SSIZE_MAX) {
46545 -                                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
46546 -                                               
46547 -                                               num_chunks = i + 1;
46548 -                                               break;
46549 -                                       } else {
46550 -                                               chunks[i].iov_len = toSend;
46551 -                                       }
46552 -                                       
46553 -                                       num_bytes += toSend;
46554 -                               }
46555 -                       }
46556 -                       
46557 -                       if ((r = writev(fd, chunks, num_chunks)) < 0) {
46558 -                               switch (errno) {
46559 -                               case EAGAIN:
46560 -                               case EINTR:
46561 -                                       r = 0;
46562 -                                       break;
46563 -                               case EPIPE:
46564 -                               case ECONNRESET:
46565 -                                       return -2;
46566 -                               default:
46567 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
46568 -                                                       "writev failed:", strerror(errno), fd);
46569 -                               
46570 -                                       return -1;
46571 -                               }
46572 -                       }
46573 -                       
46574 -                       cq->bytes_out += r;
46575 +               case MEM_CHUNK:
46576 +                       ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
46577  
46578 -                       /* check which chunks have been written */
46579 -                       
46580 -                       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
46581 -                               if (r >= (ssize_t)chunks[i].iov_len) {
46582 -                                       /* written */
46583 -                                       r -= chunks[i].iov_len;
46584 -                                       tc->offset += chunks[i].iov_len;
46585 -                                       
46586 +                       /* check which chunks are finished now */
46587 +                       for (tc = c; tc; tc = tc->next) {
46588 +                               /* finished the chunk */
46589 +                               if (tc->offset == tc->mem->used - 1) {
46590 +                                       /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
46591                                         if (chunk_finished) {
46592 -                                               /* skip the chunks from further touches */
46593 -                                               chunks_written++;
46594                                                 c = c->next;
46595                                         } else {
46596 -                                               /* chunks_written + c = c->next is done in the for()*/
46597 -                                               chunk_finished++;
46598 +                                               chunk_finished = 1;
46599                                         }
46600                                 } else {
46601 -                                       /* partially written */
46602 -                                       
46603 -                                       tc->offset += r;
46604 -                                       chunk_finished = 0;
46605 -
46606                                         break;
46607                                 }
46608                         }
46609 -                       
46610 +
46611 +                       if (ret != NETWORK_STATUS_SUCCESS) {
46612 +                               return ret;
46613 +                       }
46614 +
46615                         break;
46616 -               }
46617                 case FILE_CHUNK: {
46618                         ssize_t r;
46619                         off_t abs_offset;
46620 @@ -159,26 +175,26 @@
46621  #define KByte * 1024
46622  #define MByte * 1024 KByte
46623  #define GByte * 1024 MByte
46624 -                       const off_t we_want_to_mmap = 512 KByte; 
46625 +                       const off_t we_want_to_mmap = 512 KByte;
46626                         char *start = NULL;
46627  
46628                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
46629                                 log_error_write(srv, __FILE__, __LINE__, "sb",
46630                                                 strerror(errno), c->file.name);
46631 -                               return -1;
46632 +                               return NETWORK_STATUS_FATAL_ERROR;
46633                         }
46634  
46635                         abs_offset = c->file.start + c->offset;
46636 -                       
46637 +
46638                         if (abs_offset > sce->st.st_size) {
46639 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
46640 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
46641                                                 "file was shrinked:", c->file.name);
46642 -                               
46643 -                               return -1;
46644 +
46645 +                               return NETWORK_STATUS_FATAL_ERROR;
46646                         }
46647  
46648 -                       /* mmap the buffer 
46649 -                        * - first mmap 
46650 +                       /* mmap the buffer
46651 +                        * - first mmap
46652                          * - new mmap as the we are at the end of the last one */
46653                         if (c->file.mmap.start == MAP_FAILED ||
46654                             abs_offset == (off_t)(c->file.mmap.offset + c->file.mmap.length)) {
46655 @@ -188,7 +204,7 @@
46656                                  * adaptive mem-mapping
46657                                  *   the problem:
46658                                  *     we mmap() the whole file. If someone has alot large files and 32bit
46659 -                                *     machine the virtual address area will be unrun and we will have a failing 
46660 +                                *     machine the virtual address area will be unrun and we will have a failing
46661                                  *     mmap() call.
46662                                  *   solution:
46663                                  *     only mmap 16M in one chunk and move the window as soon as we have finished
46664 @@ -234,8 +250,8 @@
46665                                 if (-1 == c->file.fd) {  /* open the file if not already open */
46666                                         if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
46667                                                 log_error_write(srv, __FILE__, __LINE__, "sbs", "open failed for:", c->file.name, strerror(errno));
46668 -                               
46669 -                                               return -1;
46670 +
46671 +                                               return NETWORK_STATUS_FATAL_ERROR;
46672                                         }
46673  #ifdef FD_CLOEXEC
46674                                         fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
46675 @@ -245,10 +261,10 @@
46676                                 if (MAP_FAILED == (c->file.mmap.start = mmap(0, to_mmap, PROT_READ, MAP_SHARED, c->file.fd, c->file.mmap.offset))) {
46677                                         /* close it here, otherwise we'd have to set FD_CLOEXEC */
46678  
46679 -                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:", 
46680 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:",
46681                                                         strerror(errno), c->file.name, c->file.fd);
46682  
46683 -                                       return -1;
46684 +                                       return NETWORK_STATUS_FATAL_ERROR;
46685                                 }
46686  
46687                                 c->file.mmap.length = to_mmap;
46688 @@ -258,7 +274,7 @@
46689  #ifdef HAVE_MADVISE
46690                                 /* don't advise files < 64Kb */
46691                                 if (c->file.mmap.length > (64 KByte)) {
46692 -                                       /* darwin 7 is returning EINVAL all the time and I don't know how to 
46693 +                                       /* darwin 7 is returning EINVAL all the time and I don't know how to
46694                                          * detect this at runtime.i
46695                                          *
46696                                          * ignore the return value for now */
46697 @@ -274,12 +290,12 @@
46698                         toSend = (c->file.mmap.offset + c->file.mmap.length) - (abs_offset);
46699  
46700                         if (toSend < 0) {
46701 -                               log_error_write(srv, __FILE__, __LINE__, "soooo", 
46702 +                               log_error_write(srv, __FILE__, __LINE__, "soooo",
46703                                                 "toSend is negative:",
46704                                                 toSend,
46705                                                 c->file.mmap.length,
46706                                                 abs_offset,
46707 -                                               c->file.mmap.offset); 
46708 +                                               c->file.mmap.offset);
46709                                 assert(toSend < 0);
46710                         }
46711  
46712 @@ -289,7 +305,7 @@
46713                         start = c->file.mmap.start;
46714  #endif
46715  
46716 -                       if ((r = write(fd, start + (abs_offset - c->file.mmap.offset), toSend)) < 0) {
46717 +                       if ((r = write(sock->fd, start + (abs_offset - c->file.mmap.offset), toSend)) < 0) {
46718                                 switch (errno) {
46719                                 case EAGAIN:
46720                                 case EINTR:
46721 @@ -297,18 +313,18 @@
46722                                         break;
46723                                 case EPIPE:
46724                                 case ECONNRESET:
46725 -                                       return -2;
46726 +                                       return NETWORK_STATUS_CONNECTION_CLOSE;
46727                                 default:
46728 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
46729 -                                                       "write failed:", strerror(errno), fd);
46730 -                                       
46731 -                                       return -1;
46732 +                                       log_error_write(srv, __FILE__, __LINE__, "ssd",
46733 +                                                       "write failed:", strerror(errno), sock->fd);
46734 +
46735 +                                       return NETWORK_STATUS_FATAL_ERROR;
46736                                 }
46737                         }
46738 -                       
46739 +
46740                         c->offset += r;
46741                         cq->bytes_out += r;
46742 -                       
46743 +
46744                         if (c->offset == c->file.length) {
46745                                 chunk_finished = 1;
46746  
46747 @@ -318,26 +334,26 @@
46748                                         c->file.mmap.start = MAP_FAILED;
46749                                 }
46750                         }
46751 -                       
46752 +
46753                         break;
46754                 }
46755                 default:
46756 -                       
46757 +
46758                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
46759 -                       
46760 -                       return -1;
46761 +
46762 +                       return NETWORK_STATUS_FATAL_ERROR;
46763                 }
46764 -               
46765 +
46766                 if (!chunk_finished) {
46767                         /* not finished yet */
46768 -                       
46769 +
46770                         break;
46771                 }
46772 -               
46773 +
46774                 chunks_written++;
46775         }
46776  
46777 -       return chunks_written;
46778 +       return NETWORK_STATUS_SUCCESS;
46779  }
46780  
46781  #endif
46782 --- ../lighttpd-1.4.11/src/plugin.c     2006-02-08 14:00:54.000000000 +0200
46783 +++ lighttpd-1.4.12/src/plugin.c        2006-07-16 00:26:04.000000000 +0300
46784 @@ -13,27 +13,27 @@
46785  #include <valgrind/valgrind.h>
46786  #endif
46787  
46788 -#ifndef __WIN32
46789 +#ifndef _WIN32
46790  #include <dlfcn.h>
46791  #endif
46792  /*
46793 - * 
46794 + *
46795   * if you change this enum to add a new callback, be sure
46796   * - that PLUGIN_FUNC_SIZEOF is the last entry
46797   * - that you add PLUGIN_TO_SLOT twice:
46798 - *   1. as callback-dispatcher 
46799 + *   1. as callback-dispatcher
46800   *   2. in plugins_call_init()
46801 - * 
46802 + *
46803   */
46804  
46805  typedef struct {
46806         PLUGIN_DATA;
46807  } plugin_data;
46808  
46809 -typedef enum { 
46810 +typedef enum {
46811         PLUGIN_FUNC_UNSET,
46812 -               PLUGIN_FUNC_HANDLE_URI_CLEAN, 
46813 -               PLUGIN_FUNC_HANDLE_URI_RAW, 
46814 +               PLUGIN_FUNC_HANDLE_URI_CLEAN,
46815 +               PLUGIN_FUNC_HANDLE_URI_RAW,
46816                 PLUGIN_FUNC_HANDLE_REQUEST_DONE,
46817                 PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE,
46818                 PLUGIN_FUNC_HANDLE_TRIGGER,
46819 @@ -44,38 +44,42 @@
46820                 PLUGIN_FUNC_HANDLE_DOCROOT,
46821                 PLUGIN_FUNC_HANDLE_PHYSICAL,
46822                 PLUGIN_FUNC_CONNECTION_RESET,
46823 -               PLUGIN_FUNC_INIT, 
46824 +               PLUGIN_FUNC_INIT,
46825                 PLUGIN_FUNC_CLEANUP,
46826                 PLUGIN_FUNC_SET_DEFAULTS,
46827 -               
46828 +
46829                 PLUGIN_FUNC_SIZEOF
46830  } plugin_t;
46831  
46832  static plugin *plugin_init(void) {
46833         plugin *p;
46834 -       
46835 +
46836         p = calloc(1, sizeof(*p));
46837 -       
46838 +
46839 +       p->required_plugins = array_init();
46840 +
46841         return p;
46842  }
46843  
46844  static void plugin_free(plugin *p) {
46845         int use_dlclose = 1;
46846         if (p->name) buffer_free(p->name);
46847 +
46848 +       array_free(p->required_plugins);
46849  #ifdef HAVE_VALGRIND_VALGRIND_H
46850         /*if (RUNNING_ON_VALGRIND) use_dlclose = 0;*/
46851  #endif
46852  
46853  #ifndef LIGHTTPD_STATIC
46854 -       if (use_dlclose && p->lib) {    
46855 -#ifdef __WIN32
46856 +       if (use_dlclose && p->lib) {
46857 +#ifdef _WIN32
46858                 FreeLibrary(p->lib);
46859  #else
46860                 dlclose(p->lib);
46861  #endif
46862         }
46863  #endif
46864 -               
46865 +
46866         free(p);
46867  }
46868  
46869 @@ -89,17 +93,17 @@
46870                 srv->plugins.size += 4;
46871                 srv->plugins.ptr   = realloc(srv->plugins.ptr, srv->plugins.size * sizeof(*ps));
46872         }
46873 -       
46874 +
46875         ps = srv->plugins.ptr;
46876         ps[srv->plugins.used++] = p;
46877 -       
46878 +
46879         return 0;
46880  }
46881  
46882  /**
46883 - * 
46884 - * 
46885 - * 
46886 + *
46887 + *
46888 + *
46889   */
46890  
46891  #ifdef LIGHTTPD_STATIC
46892 @@ -121,30 +125,35 @@
46893  #else
46894  int plugins_load(server *srv) {
46895         plugin *p;
46896 +#ifdef _WIN32
46897 +    FARPROC init;
46898 +#else
46899         int (*init)(plugin *pl);
46900 +#endif
46901 +
46902         const char *error;
46903 -       size_t i;
46904 -       
46905 +       size_t i, j, k;
46906 +
46907         for (i = 0; i < srv->srvconf.modules->used; i++) {
46908                 data_string *d = (data_string *)srv->srvconf.modules->data[i];
46909                 char *modules = d->value->ptr;
46910 -       
46911 +
46912                 buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.modules_dir);
46913  
46914                 buffer_append_string(srv->tmp_buf, "/");
46915                 buffer_append_string(srv->tmp_buf, modules);
46916 -#if defined(__WIN32) || defined(__CYGWIN__)
46917 +#if defined(_WIN32) || defined(__CYGWIN__)
46918                 buffer_append_string(srv->tmp_buf, ".dll");
46919  #else
46920                 buffer_append_string(srv->tmp_buf, ".so");
46921  #endif
46922 -       
46923 +
46924                 p = plugin_init();
46925 -#ifdef __WIN32
46926 +#ifdef _WIN32
46927                 if (NULL == (p->lib = LoadLibrary(srv->tmp_buf->ptr))) {
46928                         LPVOID lpMsgBuf;
46929                         FormatMessage(
46930 -                               FORMAT_MESSAGE_ALLOCATE_BUFFER | 
46931 +                               FORMAT_MESSAGE_ALLOCATE_BUFFER |
46932                                 FORMAT_MESSAGE_FROM_SYSTEM,
46933                                 NULL,
46934                                 GetLastError(),
46935 @@ -152,36 +161,36 @@
46936                                 (LPTSTR) &lpMsgBuf,
46937                                 0, NULL );
46938  
46939 -                       log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed", 
46940 +                       log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
46941                                         lpMsgBuf, srv->tmp_buf);
46942 -                       
46943 +
46944                         plugin_free(p);
46945 -                       
46946 +
46947                         return -1;
46948  
46949                 }
46950 -#else  
46951 +#else
46952                 if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_LAZY))) {
46953 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:", 
46954 +                       log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:",
46955                                         srv->tmp_buf, dlerror());
46956 -                       
46957 +
46958                         plugin_free(p);
46959 -                       
46960 +
46961                         return -1;
46962                 }
46963 -               
46964 +
46965  #endif
46966                 buffer_reset(srv->tmp_buf);
46967                 buffer_copy_string(srv->tmp_buf, modules);
46968                 buffer_append_string(srv->tmp_buf, "_plugin_init");
46969  
46970 -#ifdef __WIN32
46971 +#ifdef _WIN32
46972                 init = GetProcAddress(p->lib, srv->tmp_buf->ptr);
46973  
46974                 if (init == NULL)  {
46975                         LPVOID lpMsgBuf;
46976                         FormatMessage(
46977 -                               FORMAT_MESSAGE_ALLOCATE_BUFFER | 
46978 +                               FORMAT_MESSAGE_ALLOCATE_BUFFER |
46979                                 FORMAT_MESSAGE_FROM_SYSTEM,
46980                                 NULL,
46981                                 GetLastError(),
46982 @@ -190,7 +199,7 @@
46983                                 0, NULL );
46984  
46985                         log_error_write(srv, __FILE__, __LINE__, "sbs", "getprocaddress failed:", srv->tmp_buf, lpMsgBuf);
46986 -                       
46987 +
46988                         plugin_free(p);
46989                         return -1;
46990                 }
46991 @@ -203,24 +212,43 @@
46992  #endif
46993                 if ((error = dlerror()) != NULL)  {
46994                         log_error_write(srv, __FILE__, __LINE__, "s", error);
46995 -                       
46996 +
46997                         plugin_free(p);
46998                         return -1;
46999                 }
47000 -       
47001 +
47002  #endif
47003                 if ((*init)(p)) {
47004                         log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin init failed" );
47005 -                       
47006 +
47007                         plugin_free(p);
47008                         return -1;
47009                 }
47010  #if 0
47011                 log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin loaded" );
47012  #endif
47013 +               /* check if the required plugin is loaded */
47014 +               for (k = 0; k < p->required_plugins->used; k++) {
47015 +                       data_string *req = (data_string *)p->required_plugins->data[k];
47016 +
47017 +                       for (j = 0; j < i; j++) {
47018 +                               data_string *mod = (data_string *)srv->srvconf.modules->data[j];
47019 +
47020 +                               if (buffer_is_equal(req->value, mod->value)) break;
47021 +                       }
47022 +
47023 +                       if (j == i) {
47024 +                               /* not found */
47025 +                               log_error_write(srv, __FILE__, __LINE__, "ssbs", modules, "failed to load. required plugin", req->value, "was not loaded" );
47026 +
47027 +                               plugin_free(p);
47028 +                       
47029 +                               return -1;
47030 +                       }
47031 +               }
47032                 plugins_register(srv, p);
47033         }
47034 -       
47035 +
47036         return 0;
47037  }
47038  #endif
47039 @@ -253,8 +281,8 @@
47040         }
47041  
47042  /**
47043 - * plugins that use 
47044 - * 
47045 + * plugins that use
47046 + *
47047   * - server *srv
47048   * - connection *con
47049   * - void *p_d (plugin_data *)
47050 @@ -301,12 +329,12 @@
47051         }
47052  
47053  /**
47054 - * plugins that use 
47055 - * 
47056 + * plugins that use
47057 + *
47058   * - server *srv
47059   * - void *p_d (plugin_data *)
47060   */
47061 -                                                                       
47062 +
47063  PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger)
47064  PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup)
47065  PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup)
47066 @@ -314,18 +342,18 @@
47067  
47068  #undef PLUGIN_TO_SLOT
47069  
47070 -#if 0                                                                  
47071 +#if 0
47072  /**
47073 - * 
47074 + *
47075   * special handler
47076 - * 
47077 + *
47078   */
47079  handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) {
47080         size_t i;
47081         plugin **ps;
47082 -       
47083 +
47084         ps = srv->plugins.ptr;
47085 -       
47086 +
47087         for (i = 0; i < srv->plugins.used; i++) {
47088                 plugin *p = ps[i];
47089                 if (p->handle_fdevent) {
47090 @@ -344,34 +372,34 @@
47091                         }
47092                 }
47093         }
47094 -       
47095 +
47096         return HANDLER_GO_ON;
47097  }
47098  #endif
47099  /**
47100 - * 
47101 + *
47102   * - call init function of all plugins to init the plugin-internals
47103   * - added each plugin that supports has callback to the corresponding slot
47104 - * 
47105 + *
47106   * - is only called once.
47107   */
47108  
47109  handler_t plugins_call_init(server *srv) {
47110         size_t i;
47111         plugin **ps;
47112 -       
47113 +
47114         ps = srv->plugins.ptr;
47115 -       
47116 +
47117         /* fill slots */
47118 -       
47119 +
47120         srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps));
47121 -       
47122 +
47123         for (i = 0; i < srv->plugins.used; i++) {
47124                 size_t j;
47125                 /* check which calls are supported */
47126 -               
47127 +
47128                 plugin *p = ps[i];
47129 -               
47130 +
47131  #define PLUGIN_TO_SLOT(x, y) \
47132         if (p->y) { \
47133                 plugin **slot = ((plugin ***)(srv->plugin_slots))[x]; \
47134 @@ -384,11 +412,11 @@
47135                         slot[j] = p;\
47136                         break;\
47137                 }\
47138 -       } 
47139 -               
47140 -               
47141 -               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean); 
47142 -               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw); 
47143 +       }
47144 +
47145 +
47146 +               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean);
47147 +               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw);
47148                 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done);
47149                 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close);
47150                 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger);
47151 @@ -402,19 +430,19 @@
47152                 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup);
47153                 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults);
47154  #undef PLUGIN_TO_SLOT
47155 -               
47156 +
47157                 if (p->init) {
47158                         if (NULL == (p->data = p->init())) {
47159 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
47160 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
47161                                                 "plugin-init failed for module", p->name);
47162                                 return HANDLER_ERROR;
47163                         }
47164 -                       
47165 +
47166                         /* used for con->mode, DIRECT == 0, plugins above that */
47167                         ((plugin_data *)(p->data))->id = i + 1;
47168 -                       
47169 +
47170                         if (p->version != LIGHTTPD_VERSION_ID) {
47171 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
47172 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
47173                                                 "plugin-version doesn't match lighttpd-version for", p->name);
47174                                 return HANDLER_ERROR;
47175                         }
47176 @@ -422,29 +450,46 @@
47177                         p->data = NULL;
47178                 }
47179         }
47180 -       
47181 +
47182         return HANDLER_GO_ON;
47183  }
47184  
47185 +/**
47186 + * get the config-storage of the named plugin 
47187 + */
47188 +void *plugin_get_config(server *srv, const char *name) {
47189 +       size_t i;
47190 +
47191 +       for (i = 0; i < srv->plugins.used; i++) {
47192 +               plugin *p = ((plugin **)srv->plugins.ptr)[i];
47193 +
47194 +               if (buffer_is_equal_string(p->name, name, strlen(name))) {
47195 +                       return p->data;
47196 +               }
47197 +       }
47198 +
47199 +       return NULL;
47200 +}
47201 +
47202  void plugins_free(server *srv) {
47203         size_t i;
47204         plugins_call_cleanup(srv);
47205 -       
47206 +
47207         for (i = 0; i < srv->plugins.used; i++) {
47208                 plugin *p = ((plugin **)srv->plugins.ptr)[i];
47209 -               
47210 +
47211                 plugin_free(p);
47212         }
47213 -       
47214 +
47215         for (i = 0; srv->plugin_slots && i < PLUGIN_FUNC_SIZEOF; i++) {
47216                 plugin **slot = ((plugin ***)(srv->plugin_slots))[i];
47217 -               
47218 +
47219                 if (slot) free(slot);
47220         }
47221 -       
47222 +
47223         free(srv->plugin_slots);
47224         srv->plugin_slots = NULL;
47225 -       
47226 +
47227         free(srv->plugins.ptr);
47228         srv->plugins.ptr = NULL;
47229         srv->plugins.used = 0;
47230 --- ../lighttpd-1.4.11/src/plugin.h     2005-08-15 12:28:56.000000000 +0300
47231 +++ lighttpd-1.4.12/src/plugin.h        2006-07-16 00:26:04.000000000 +0300
47232 @@ -12,6 +12,12 @@
47233  
47234  #define INIT_FUNC(x) \
47235                 static void *x()
47236 +/*
47237 + * The PATCH_OPTION() macro is used in the patch_connection() functions
47238 + * of the modules to update the config object for the current request.
47239 + */
47240 +#define PATCH_OPTION(x) \
47241 +               p->conf.x = s->x
47242  
47243  #define FREE_FUNC          SERVER_FUNC
47244  #define TRIGGER_FUNC       SERVER_FUNC
47245 @@ -25,19 +31,19 @@
47246  #define URIHANDLER_FUNC    CONNECTION_FUNC
47247  
47248  #define PLUGIN_DATA        size_t id
47249 -                                                                                                                                               
47250 +
47251  typedef struct {
47252         size_t version;
47253 -       
47254 +
47255         buffer *name; /* name of the plugin */
47256 -       
47257 +
47258         void *(* init)                       ();
47259         handler_t (* set_defaults)           (server *srv, void *p_d);
47260         handler_t (* cleanup)                (server *srv, void *p_d);
47261                                                                                            /* is called ... */
47262         handler_t (* handle_trigger)         (server *srv, void *p_d);                     /* once a second */
47263         handler_t (* handle_sighup)          (server *srv, void *p_d);                     /* at a signup */
47264 -       
47265 +
47266         handler_t (* handle_uri_raw)         (server *srv, connection *con, void *p_d);    /* after uri_raw is set */
47267         handler_t (* handle_uri_clean)       (server *srv, connection *con, void *p_d);    /* after uri is set */
47268         handler_t (* handle_docroot)         (server *srv, connection *con, void *p_d);    /* getting the document-root */
47269 @@ -45,20 +51,22 @@
47270         handler_t (* handle_request_done)    (server *srv, connection *con, void *p_d);    /* at the end of a request */
47271         handler_t (* handle_connection_close)(server *srv, connection *con, void *p_d);    /* at the end of a connection */
47272         handler_t (* handle_joblist)         (server *srv, connection *con, void *p_d);    /* after all events are handled */
47273 -       
47274 -       
47275 -       
47276 -       handler_t (* handle_subrequest_start)(server *srv, connection *con, void *p_d);   
47277 -       
47278 -                                                                                          /* when a handler for the request 
47279 +
47280 +
47281 +
47282 +       handler_t (* handle_subrequest_start)(server *srv, connection *con, void *p_d);
47283 +
47284 +                                                                                          /* when a handler for the request
47285                                                                                             * has to be found
47286                                                                                             */
47287         handler_t (* handle_subrequest)      (server *srv, connection *con, void *p_d);    /* */
47288         handler_t (* connection_reset)       (server *srv, connection *con, void *p_d);    /* */
47289         void *data;
47290 -       
47291 +
47292         /* dlopen handle */
47293         void *lib;
47294 +
47295 +       array *required_plugins;
47296  } plugin;
47297  
47298  int plugins_load(server *srv);
47299 @@ -88,5 +96,8 @@
47300  int config_patch_connection(server *srv, connection *con, comp_key_t comp);
47301  int config_check_cond(server *srv, connection *con, data_config *dc);
47302  int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n);
47303 +int config_exec_pcre_keyvalue_buffer(connection *con, pcre_keyvalue_buffer *kvb, data_config *context, buffer *match_buf, buffer *result);
47304 +
47305 +void *plugin_get_config(server *srv, const char *name);
47306  
47307  #endif
47308 --- ../lighttpd-1.4.11/src/proc_open.c  2005-08-11 01:26:39.000000000 +0300
47309 +++ lighttpd-1.4.12/src/proc_open.c     2006-07-16 00:26:04.000000000 +0300
47310 @@ -13,13 +13,13 @@
47311  #endif
47312  
47313  
47314 -#ifdef WIN32
47315 +#ifdef _WIN32
47316  /* {{{ win32 stuff */
47317  # define SHELLENV "ComSpec"
47318  # define SECURITY_DC , SECURITY_ATTRIBUTES *security
47319  # define SECURITY_CC , security
47320  # define pipe(pair) (CreatePipe(&pair[0], &pair[1], security, 2048L) ? 0 : -1)
47321 -static inline HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig)
47322 +static HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig)
47323  {
47324         HANDLE copy, self = GetCurrentProcess();
47325  
47326 @@ -148,11 +148,14 @@
47327         STARTUPINFO si;
47328         BOOL procok;
47329         SECURITY_ATTRIBUTES security;
47330 -       const char *shell;
47331 +       const char *shell = NULL;
47332 +       const char *windir = NULL;
47333         buffer *cmdline;
47334  
47335 -       if (NULL == (shell = getenv(SHELLENV))) {
47336 -               fprintf(stderr, "env %s is required", SHELLENV);
47337 +       if (NULL == (shell = getenv(SHELLENV)) &&
47338 +                       NULL == (windir = getenv("SystemRoot")) &&
47339 +                       NULL == (windir = getenv("windir"))) {
47340 +               fprintf(stderr, "One of %s,%%SystemRoot,%%windir is required", SHELLENV);
47341                 return -1;
47342         }
47343  
47344 @@ -177,17 +180,23 @@
47345         memset(&pi, 0, sizeof(pi));
47346  
47347         cmdline = buffer_init();
47348 -       buffer_append_string(cmdline, shell);
47349 +       if (shell) {
47350 +               buffer_append_string(cmdline, shell);
47351 +       } else {
47352 +               buffer_append_string(cmdline, windir);
47353 +               buffer_append_string(cmdline, "\\system32\\cmd.exe");
47354 +       }
47355         buffer_append_string_len(cmdline, CONST_STR_LEN(" /c "));
47356         buffer_append_string(cmdline, command);
47357         procok = CreateProcess(NULL, cmdline->ptr, &security, &security, TRUE,
47358                         NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
47359 -       buffer_free(cmdline);
47360  
47361         if (FALSE == procok) {
47362 -               fprintf(stderr, "failed to CreateProcess");
47363 +               fprintf(stderr, "failed to CreateProcess: %s", cmdline->ptr);
47364 +               buffer_free(cmdline);
47365                 return -1;
47366         }
47367 +       buffer_free(cmdline);
47368  
47369         proc->child = pi.hProcess;
47370         CloseHandle(pi.hThread);
47371 @@ -226,8 +235,7 @@
47372         const char *shell;
47373  
47374         if (NULL == (shell = getenv(SHELLENV))) {
47375 -               fprintf(stderr, "env %s is required", SHELLENV);
47376 -               return -1;
47377 +               shell = "/bin/sh";
47378         }
47379  
47380         if (proc_open_pipes(proc) != 0) {
47381 @@ -262,11 +270,11 @@
47382         }
47383  }
47384  /* }}} */
47385 -#endif /* WIN32 */
47386 +#endif /* _WIN32 */
47387  
47388  /* {{{ proc_read_fd_to_buffer */
47389  static void proc_read_fd_to_buffer(int fd, buffer *b) {
47390 -       ssize_t s;
47391 +       int s; /* win32 has not ssize_t */
47392  
47393         for (;;) {
47394                 buffer_prepare_append(b, 512);
47395 --- ../lighttpd-1.4.11/src/proc_open.h  2005-08-11 01:26:39.000000000 +0300
47396 +++ lighttpd-1.4.12/src/proc_open.h     2006-07-16 00:26:04.000000000 +0300
47397 @@ -1,7 +1,7 @@
47398  
47399  #include "buffer.h"
47400  
47401 -#ifdef WIN32
47402 +#ifdef _WIN32
47403  #include <windows.h>
47404  typedef HANDLE descriptor_t;
47405  typedef HANDLE proc_pid_t;
47406 --- ../lighttpd-1.4.11/src/request.c    2006-03-05 11:58:09.000000000 +0200
47407 +++ lighttpd-1.4.12/src/request.c       2006-07-18 13:03:40.000000000 +0300
47408 @@ -10,15 +10,17 @@
47409  #include "keyvalue.h"
47410  #include "log.h"
47411  
47412 +#include "sys-strings.h"
47413 +
47414  static int request_check_hostname(server *srv, connection *con, buffer *host) {
47415         enum { DOMAINLABEL, TOPLABEL } stage = TOPLABEL;
47416         size_t i;
47417         int label_len = 0;
47418         size_t host_len;
47419         char *colon;
47420 -       int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */ 
47421 +       int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */
47422         int level = 0;
47423 -       
47424 +
47425         UNUSED(srv);
47426         UNUSED(con);
47427  
47428 @@ -32,17 +34,17 @@
47429          *       IPv6address   = "[" ... "]"
47430          *       port          = *digit
47431          */
47432 -       
47433 +
47434         /* no Host: */
47435         if (!host || host->used == 0) return 0;
47436 -       
47437 +
47438         host_len = host->used - 1;
47439 -       
47440 +
47441         /* IPv6 adress */
47442         if (host->ptr[0] == '[') {
47443                 char *c = host->ptr + 1;
47444                 int colon_cnt = 0;
47445 -               
47446 +
47447                 /* check portnumber */
47448                 for (; *c && *c != ']'; c++) {
47449                         if (*c == ':') {
47450 @@ -53,12 +55,12 @@
47451                                 return -1;
47452                         }
47453                 }
47454 -               
47455 +
47456                 /* missing ] */
47457                 if (!*c) {
47458                         return -1;
47459                 }
47460 -               
47461 +
47462                 /* check port */
47463                 if (*(c+1) == ':') {
47464                         for (c += 2; *c; c++) {
47465 @@ -69,39 +71,39 @@
47466                 }
47467                 return 0;
47468         }
47469 -       
47470 +
47471         if (NULL != (colon = memchr(host->ptr, ':', host_len))) {
47472                 char *c = colon + 1;
47473 -               
47474 +
47475                 /* check portnumber */
47476                 for (; *c; c++) {
47477                         if (!light_isdigit(*c)) return -1;
47478                 }
47479 -               
47480 +
47481                 /* remove the port from the host-len */
47482                 host_len = colon - host->ptr;
47483         }
47484 -       
47485 +
47486         /* Host is empty */
47487         if (host_len == 0) return -1;
47488 -       
47489 +
47490         /* scan from the right and skip the \0 */
47491         for (i = host_len - 1; i + 1 > 0; i--) {
47492                 const char c = host->ptr[i];
47493  
47494                 switch (stage) {
47495 -               case TOPLABEL: 
47496 +               case TOPLABEL:
47497                         if (c == '.') {
47498                                 /* only switch stage, if this is not the last character */
47499                                 if (i != host_len - 1) {
47500                                         if (label_len == 0) {
47501                                                 return -1;
47502                                         }
47503 -                                       
47504 +
47505                                         /* check the first character at right of the dot */
47506                                         if (is_ip == 0) {
47507                                                 if (!light_isalpha(host->ptr[i+1])) {
47508 -                                                       return -1; 
47509 +                                                       return -1;
47510                                                 }
47511                                         } else if (!light_isdigit(host->ptr[i+1])) {
47512                                                 is_ip = 0;
47513 @@ -111,9 +113,9 @@
47514                                                 /* just digits */
47515                                                 is_ip = 1;
47516                                         }
47517 -                                               
47518 +
47519                                         stage = DOMAINLABEL;
47520 -                                       
47521 +
47522                                         label_len = 0;
47523                                         level++;
47524                                 } else if (i == 0) {
47525 @@ -135,7 +137,7 @@
47526                                 }
47527                                 label_len++;
47528                         }
47529 -                       
47530 +
47531                         break;
47532                 case DOMAINLABEL:
47533                         if (is_ip == 1) {
47534 @@ -143,7 +145,7 @@
47535                                         if (label_len == 0) {
47536                                                 return -1;
47537                                         }
47538 -                                       
47539 +
47540                                         label_len = 0;
47541                                         level++;
47542                                 } else if (!light_isdigit(c)) {
47543 @@ -156,12 +158,12 @@
47544                                         if (label_len == 0) {
47545                                                 return -1;
47546                                         }
47547 -                                       
47548 +
47549                                         /* c is either - or alphanum here */
47550                                         if ('-' == host->ptr[i+1]) {
47551                                                 return -1;
47552                                         }
47553 -                                       
47554 +
47555                                         label_len = 0;
47556                                         level++;
47557                                 } else if (i == 0) {
47558 @@ -176,20 +178,20 @@
47559                                         label_len++;
47560                                 }
47561                         }
47562 -                       
47563 +
47564                         break;
47565                 }
47566         }
47567 -       
47568 +
47569         /* a IP has to consist of 4 parts */
47570         if (is_ip == 1 && level != 3) {
47571                 return -1;
47572         }
47573 -       
47574 +
47575         if (label_len == 0) {
47576                 return -1;
47577         }
47578 -       
47579 +
47580         return 0;
47581  }
47582  
47583 @@ -201,53 +203,53 @@
47584         char *s;
47585         size_t i;
47586         int state = 0;
47587 -       /*  
47588 -        * parse 
47589 -        * 
47590 +       /*
47591 +        * parse
47592 +        *
47593          * val1, val2, val3, val4
47594 -        * 
47595 +        *
47596          * into a array (more or less a explode() incl. striping of whitespaces
47597          */
47598 -       
47599 +
47600         if (b->used == 0) return 0;
47601 -       
47602 +
47603         s = b->ptr;
47604 -       
47605 +
47606         for (i =0; i < b->used - 1; ) {
47607                 char *start = NULL, *end = NULL;
47608                 data_string *ds;
47609 -               
47610 +
47611                 switch (state) {
47612                 case 0: /* ws */
47613 -                       
47614 +
47615                         /* skip ws */
47616                         for (; (*s == ' ' || *s == '\t') && i < b->used - 1; i++, s++);
47617 -                       
47618 -                       
47619 +
47620 +
47621                         state = 1;
47622                         break;
47623                 case 1: /* value */
47624                         start = s;
47625 -                       
47626 +
47627                         for (; *s != ',' && i < b->used - 1; i++, s++);
47628                         end = s - 1;
47629 -                       
47630 +
47631                         for (; (*end == ' ' || *end == '\t') && end > start; end--);
47632 -                       
47633 +
47634                         if (NULL == (ds = (data_string *)array_get_unused_element(vals, TYPE_STRING))) {
47635                                 ds = data_string_init();
47636                         }
47637  
47638                         buffer_copy_string_len(ds->value, start, end-start+1);
47639                         array_insert_unique(vals, (data_unset *)ds);
47640 -                       
47641 +
47642                         if (*s == ',') {
47643                                 state = 0;
47644                                 i++;
47645                                 s++;
47646                         } else {
47647                                 /* end of string */
47648 -                               
47649 +
47650                                 state = 2;
47651                         }
47652                         break;
47653 @@ -263,7 +265,7 @@
47654         if (c <= 32) return 0;
47655         if (c == 127) return 0;
47656         if (c == 255) return 0;
47657 -       
47658 +
47659         return 1;
47660  }
47661  
47662 @@ -271,28 +273,28 @@
47663         char *uri = NULL, *proto = NULL, *method = NULL, con_length_set;
47664         int is_key = 1, key_len = 0, is_ws_after_key = 0, in_folding;
47665         char *value = NULL, *key = NULL;
47666 -       
47667 +
47668         enum { HTTP_CONNECTION_UNSET, HTTP_CONNECTION_KEEPALIVE, HTTP_CONNECTION_CLOSE } keep_alive_set = HTTP_CONNECTION_UNSET;
47669 -       
47670 +
47671         int line = 0;
47672 -       
47673 +
47674         int request_line_stage = 0;
47675         size_t i, first;
47676 -       
47677 +
47678         int done = 0;
47679 -       
47680 +
47681         data_string *ds = NULL;
47682 -       
47683 -       /* 
47684 -        * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$" 
47685 -        * Option : "^([-a-zA-Z]+): (.+)$"                    
47686 +
47687 +       /*
47688 +        * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$"
47689 +        * Option : "^([-a-zA-Z]+): (.+)$"
47690          * End    : "^$"
47691          */
47692  
47693         if (con->conf.log_request_header) {
47694 -               log_error_write(srv, __FILE__, __LINE__, "sdsdSb", 
47695 -                               "fd:", con->fd, 
47696 -                               "request-len:", con->request.request->used, 
47697 +               log_error_write(srv, __FILE__, __LINE__, "sdsdSb",
47698 +                               "fd:", con->sock->fd,
47699 +                               "request-len:", con->request.request->used,
47700                                 "\n", con->request.request);
47701         }
47702  
47703 @@ -300,13 +302,13 @@
47704             con->request.request->ptr[0] == '\r' &&
47705             con->request.request->ptr[1] == '\n') {
47706                 /* we are in keep-alive and might get \r\n after a previous POST request.*/
47707 -               
47708 +
47709                 buffer_copy_string_len(con->parse_request, con->request.request->ptr + 2, con->request.request->used - 1 - 2);
47710         } else {
47711                 /* fill the local request buffer */
47712                 buffer_copy_string_buffer(con->parse_request, con->request.request);
47713         }
47714 -       
47715 +
47716         keep_alive_set = 0;
47717         con_length_set = 0;
47718  
47719 @@ -318,25 +320,25 @@
47720          * */
47721         for (i = 0, first = 0; i < con->parse_request->used && line == 0; i++) {
47722                 char *cur = con->parse_request->ptr + i;
47723 -               
47724 +
47725                 switch(*cur) {
47726 -               case '\r': 
47727 +               case '\r':
47728                         if (con->parse_request->ptr[i+1] == '\n') {
47729                                 http_method_t r;
47730                                 char *nuri = NULL;
47731                                 size_t j;
47732 -                               
47733 +
47734                                 /* \r\n -> \0\0 */
47735                                 con->parse_request->ptr[i] = '\0';
47736                                 con->parse_request->ptr[i+1] = '\0';
47737 -                               
47738 +
47739                                 buffer_copy_string_len(con->request.request_line, con->parse_request->ptr, i);
47740 -                               
47741 +
47742                                 if (request_line_stage != 2) {
47743                                         con->http_status = 400;
47744                                         con->response.keep_alive = 0;
47745                                         con->keep_alive = 0;
47746 -                                       
47747 +
47748                                         if (srv->srvconf.log_request_header_on_error) {
47749                                                 log_error_write(srv, __FILE__, __LINE__, "s", "incomplete request line -> 400");
47750                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
47751 @@ -345,36 +347,36 @@
47752                                         }
47753                                         return 0;
47754                                 }
47755 -                               
47756 +
47757                                 proto = con->parse_request->ptr + first;
47758 -                               
47759 +
47760                                 *(uri - 1) = '\0';
47761                                 *(proto - 1) = '\0';
47762 -                               
47763 +
47764                                 /* we got the first one :) */
47765                                 if (-1 == (r = get_http_method_key(method))) {
47766                                         con->http_status = 501;
47767                                         con->response.keep_alive = 0;
47768                                         con->keep_alive = 0;
47769 -                                       
47770 +
47771                                         if (srv->srvconf.log_request_header_on_error) {
47772                                                 log_error_write(srv, __FILE__, __LINE__, "s", "unknown http-method -> 501");
47773                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
47774                                                                 "request-header:\n",
47775                                                                 con->request.request);
47776                                         }
47777 -                               
47778 +
47779                                         return 0;
47780                                 }
47781 -                               
47782 +
47783                                 con->request.http_method = r;
47784 -                       
47785 -                               /* 
47786 +
47787 +                               /*
47788                                  * RFC2616 says:
47789                                  *
47790                                  * HTTP-Version   = "HTTP" "/" 1*DIGIT "." 1*DIGIT
47791                                  *
47792 -                                * */   
47793 +                                * */
47794                                 if (0 == strncmp(proto, "HTTP/", sizeof("HTTP/") - 1)) {
47795                                         char * major = proto + sizeof("HTTP/") - 1;
47796                                         char * minor = strchr(major, '.');
47797 @@ -413,10 +415,10 @@
47798                                         }
47799  
47800                                         if (major_num == 1 && minor_num == 1) {
47801 -                                               con->request.http_version = con->conf.allow_http11 ? HTTP_VERSION_1_1 : HTTP_VERSION_1_0;
47802 +                                               con->request.http_version = HTTP_VERSION_1_1;
47803                                         } else if (major_num == 1 && minor_num == 0) {
47804                                                 con->request.http_version = HTTP_VERSION_1_0;
47805 -                                       } else { 
47806 +                                       } else {
47807                                                 con->http_status = 505;
47808  
47809                                                 if (srv->srvconf.log_request_header_on_error) {
47810 @@ -439,30 +441,30 @@
47811                                         }
47812                                         return 0;
47813                                 }
47814 -                               
47815 +
47816                                 if (0 == strncmp(uri, "http://", 7) &&
47817                                     NULL != (nuri = strchr(uri + 7, '/'))) {
47818                                         /* ignore the host-part */
47819 -                                       
47820 +
47821                                         buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
47822                                 } else {
47823                                         /* everything looks good so far */
47824                                         buffer_copy_string_len(con->request.uri, uri, proto - uri - 1);
47825                                 }
47826 -                               
47827 +
47828                                 /* check uri for invalid characters */
47829                                 for (j = 0; j < con->request.uri->used - 1; j++) {
47830                                         if (!request_uri_is_valid_char(con->request.uri->ptr[j])) {
47831                                                 unsigned char buf[2];
47832                                                 con->http_status = 400;
47833                                                 con->keep_alive = 0;
47834 -                                               
47835 +
47836                                                 if (srv->srvconf.log_request_header_on_error) {
47837                                                         buf[0] = con->request.uri->ptr[j];
47838                                                         buf[1] = '\0';
47839 -                                       
47840 +
47841                                                         if (con->request.uri->ptr[j] > 32 &&
47842 -                                                           con->request.uri->ptr[j] != 127) {  
47843 +                                                           con->request.uri->ptr[j] != 127) {
47844                                                                 /* the character is printable -> print it */
47845                                                                 log_error_write(srv, __FILE__, __LINE__, "ss",
47846                                                                                 "invalid character in URI -> 400",
47847 @@ -473,20 +475,20 @@
47848                                                                                 "invalid character in URI -> 400",
47849                                                                                 con->request.uri->ptr[j]);
47850                                                         }
47851 -                                               
47852 +
47853                                                         log_error_write(srv, __FILE__, __LINE__, "Sb",
47854                                                                         "request-header:\n",
47855                                                                         con->request.request);
47856                                                 }
47857 -                                               
47858 +
47859                                                 return 0;
47860                                         }
47861                                 }
47862 -                               
47863 +
47864                                 buffer_copy_string_buffer(con->request.orig_uri, con->request.uri);
47865 -                               
47866 +
47867                                 con->http_status = 0;
47868 -                               
47869 +
47870                                 i++;
47871                                 line++;
47872                                 first = i+1;
47873 @@ -494,14 +496,14 @@
47874                         break;
47875                 case ' ':
47876                         switch(request_line_stage) {
47877 -                       case 0: 
47878 +                       case 0:
47879                                 /* GET|POST|... */
47880 -                               method = con->parse_request->ptr + first; 
47881 +                               method = con->parse_request->ptr + first;
47882                                 first = i + 1;
47883                                 break;
47884                         case 1:
47885                                 /* /foobar/... */
47886 -                               uri = con->parse_request->ptr + first; 
47887 +                               uri = con->parse_request->ptr + first;
47888                                 first = i + 1;
47889                                 break;
47890                         default:
47891 @@ -509,7 +511,7 @@
47892                                 con->http_status = 400;
47893                                 con->response.keep_alive = 0;
47894                                 con->keep_alive = 0;
47895 -                               
47896 +
47897                                 if (srv->srvconf.log_request_header_on_error) {
47898                                         log_error_write(srv, __FILE__, __LINE__, "s", "overlong request line -> 400");
47899                                         log_error_write(srv, __FILE__, __LINE__, "Sb",
47900 @@ -518,12 +520,12 @@
47901                                 }
47902                                 return 0;
47903                         }
47904 -                       
47905 +
47906                         request_line_stage++;
47907                         break;
47908                 }
47909         }
47910 -       
47911 +
47912         in_folding = 0;
47913  
47914         if (con->request.uri->used == 1) {
47915 @@ -540,30 +542,30 @@
47916                 return 0;
47917         }
47918  
47919 -       
47920 +
47921         for (; i < con->parse_request->used && !done; i++) {
47922                 char *cur = con->parse_request->ptr + i;
47923 -               
47924 +
47925                 if (is_key) {
47926                         size_t j;
47927                         int got_colon = 0;
47928 -                       
47929 +
47930                         /**
47931                          * 1*<any CHAR except CTLs or separators>
47932                          * CTLs == 0-31 + 127
47933 -                        * 
47934 +                        *
47935                          */
47936                         switch(*cur) {
47937                         case ':':
47938                                 is_key = 0;
47939 -                               
47940 +
47941                                 value = cur + 1;
47942 -                               
47943 +
47944                                 if (is_ws_after_key == 0) {
47945                                         key_len = i - first;
47946                                 }
47947                                 is_ws_after_key = 0;
47948 -                                       
47949 +
47950                                 break;
47951                         case '(':
47952                         case ')':
47953 @@ -584,8 +586,8 @@
47954                                 con->http_status = 400;
47955                                 con->keep_alive = 0;
47956                                 con->response.keep_alive = 0;
47957 -                               
47958 -                               log_error_write(srv, __FILE__, __LINE__, "sbsds", 
47959 +
47960 +                               log_error_write(srv, __FILE__, __LINE__, "sbsds",
47961                                                 "invalid character in key", con->request.request, cur, *cur, "-> 400");
47962                                 return 0;
47963                         case ' ':
47964 @@ -594,13 +596,13 @@
47965                                         is_key = 0;
47966                                         in_folding = 1;
47967                                         value = cur;
47968 -                                       
47969 +
47970                                         break;
47971                                 }
47972 -                               
47973 -                               
47974 +
47975 +
47976                                 key_len = i - first;
47977 -                               
47978 +
47979                                 /* skip every thing up to the : */
47980                                 for (j = 1; !got_colon; j++) {
47981                                         switch(con->parse_request->ptr[j + i]) {
47982 @@ -610,40 +612,40 @@
47983                                                 continue;
47984                                         case ':':
47985                                                 /* ok, done */
47986 -                                               
47987 +
47988                                                 i += j - 1;
47989                                                 got_colon = 1;
47990 -                                               
47991 +
47992                                                 break;
47993                                         default:
47994                                                 /* error */
47995 -                                               
47996 +
47997                                                 if (srv->srvconf.log_request_header_on_error) {
47998                                                         log_error_write(srv, __FILE__, __LINE__, "s", "WS character in key -> 400");
47999                                                         log_error_write(srv, __FILE__, __LINE__, "Sb",
48000                                                                 "request-header:\n",
48001                                                                 con->request.request);
48002                                                 }
48003 -                                       
48004 +
48005                                                 con->http_status = 400;
48006                                                 con->response.keep_alive = 0;
48007                                                 con->keep_alive = 0;
48008 -                                               
48009 +
48010                                                 return 0;
48011                                         }
48012                                 }
48013 -                               
48014 +
48015                                 break;
48016                         case '\r':
48017                                 if (con->parse_request->ptr[i+1] == '\n' && i == first) {
48018                                         /* End of Header */
48019                                         con->parse_request->ptr[i] = '\0';
48020                                         con->parse_request->ptr[i+1] = '\0';
48021 -                                       
48022 +
48023                                         i++;
48024 -                                       
48025 +
48026                                         done = 1;
48027 -                                       
48028 +
48029                                         break;
48030                                 } else {
48031                                         if (srv->srvconf.log_request_header_on_error) {
48032 @@ -652,7 +654,7 @@
48033                                                         "request-header:\n",
48034                                                         con->request.request);
48035                                         }
48036 -                                       
48037 +
48038                                         con->http_status = 400;
48039                                         con->keep_alive = 0;
48040                                         con->response.keep_alive = 0;
48041 @@ -693,16 +695,16 @@
48042                                 con->http_status = 400;
48043                                 con->keep_alive = 0;
48044                                 con->response.keep_alive = 0;
48045 -                               
48046 +
48047                                 if (srv->srvconf.log_request_header_on_error) {
48048 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsds", 
48049 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsds",
48050                                                 "CTL character in key", con->request.request, cur, *cur, "-> 400");
48051  
48052                                         log_error_write(srv, __FILE__, __LINE__, "Sb",
48053                                                 "request-header:\n",
48054                                                 con->request.request);
48055                                 }
48056 -                               
48057 +
48058                                 return 0;
48059                         default:
48060                                 /* ok */
48061 @@ -710,25 +712,25 @@
48062                         }
48063                 } else {
48064                         switch(*cur) {
48065 -                       case '\r': 
48066 +                       case '\r':
48067                                 if (con->parse_request->ptr[i+1] == '\n') {
48068                                         /* End of Headerline */
48069                                         con->parse_request->ptr[i] = '\0';
48070                                         con->parse_request->ptr[i+1] = '\0';
48071 -                                       
48072 +
48073                                         if (in_folding) {
48074                                                 if (!ds) {
48075                                                         /* 400 */
48076 -                                       
48077 +
48078                                                         if (srv->srvconf.log_request_header_on_error) {
48079                                                                 log_error_write(srv, __FILE__, __LINE__, "s", "WS at the start of first line -> 400");
48080 -                                                       
48081 +
48082                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48083                                                                         "request-header:\n",
48084                                                                         con->request.request);
48085                                                         }
48086  
48087 -                                       
48088 +
48089                                                         con->http_status = 400;
48090                                                         con->keep_alive = 0;
48091                                                         con->response.keep_alive = 0;
48092 @@ -738,9 +740,9 @@
48093                                         } else {
48094                                                 int s_len;
48095                                                 key = con->parse_request->ptr + first;
48096 -                                       
48097 +
48098                                                 s_len = cur - value;
48099 -                                               
48100 +
48101                                                 if (s_len > 0) {
48102                                                         int cmp = 0;
48103                                                         if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
48104 @@ -748,86 +750,87 @@
48105                                                         }
48106                                                         buffer_copy_string_len(ds->key, key, key_len);
48107                                                         buffer_copy_string_len(ds->value, value, s_len);
48108 -                                                       
48109 -                                                       /* retreive values 
48110 -                                                        * 
48111 -                                                        * 
48112 +
48113 +                                                       /* retreive values
48114 +                                                        *
48115 +                                                        *
48116                                                          * the list of options is sorted to simplify the search
48117                                                          */
48118 -                                                       
48119 +
48120                                                         if (0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Connection")))) {
48121                                                                 array *vals;
48122                                                                 size_t vi;
48123 -                                                               
48124 +
48125                                                                 /* split on , */
48126 -                                                               
48127 +
48128                                                                 vals = srv->split_vals;
48129  
48130                                                                 array_reset(vals);
48131 -                                                               
48132 +
48133                                                                 http_request_split_value(vals, ds->value);
48134 -                                                               
48135 +
48136                                                                 for (vi = 0; vi < vals->used; vi++) {
48137                                                                         data_string *dsv = (data_string *)vals->data[vi];
48138 -                                                                       
48139 +
48140                                                                         if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("keep-alive"))) {
48141                                                                                 keep_alive_set = HTTP_CONNECTION_KEEPALIVE;
48142 -                                                                               
48143 +
48144                                                                                 break;
48145                                                                         } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("close"))) {
48146                                                                                 keep_alive_set = HTTP_CONNECTION_CLOSE;
48147 -                                                                               
48148 +
48149                                                                                 break;
48150                                                                         }
48151                                                                 }
48152 -                                                               
48153 +
48154                                                         } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) {
48155                                                                 char *err;
48156                                                                 unsigned long int r;
48157                                                                 size_t j;
48158 -                                                               
48159 +
48160                                                                 if (con_length_set) {
48161                                                                         con->http_status = 400;
48162                                                                         con->keep_alive = 0;
48163 -                                                                       
48164 +
48165                                                                         if (srv->srvconf.log_request_header_on_error) {
48166 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
48167 +                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
48168                                                                                                 "duplicate Content-Length-header -> 400");
48169                                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48170                                                                                                 "request-header:\n",
48171                                                                                                 con->request.request);
48172                                                                         }
48173 +                                                                       ds->free((data_unset *) ds);
48174                                                                         return 0;
48175                                                                 }
48176 -                                                               
48177 +
48178                                                                 if (ds->value->used == 0) SEGFAULT();
48179 -                                                               
48180 +
48181                                                                 for (j = 0; j < ds->value->used - 1; j++) {
48182                                                                         char c = ds->value->ptr[j];
48183                                                                         if (!isdigit((unsigned char)c)) {
48184 -                                                                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
48185 +                                                                               log_error_write(srv, __FILE__, __LINE__, "sbs",
48186                                                                                                 "content-length broken:", ds->value, "-> 400");
48187 -                                                                               
48188 +
48189                                                                                 con->http_status = 400;
48190                                                                                 con->keep_alive = 0;
48191 -                                                                               
48192 +
48193                                                                                 array_insert_unique(con->request.headers, (data_unset *)ds);
48194                                                                                 return 0;
48195                                                                         }
48196                                                                 }
48197 -                                                               
48198 +
48199                                                                 r = strtoul(ds->value->ptr, &err, 10);
48200 -                                                               
48201 +
48202                                                                 if (*err == '\0') {
48203                                                                         con_length_set = 1;
48204                                                                         con->request.content_length = r;
48205                                                                 } else {
48206 -                                                                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
48207 +                                                                       log_error_write(srv, __FILE__, __LINE__, "sbs",
48208                                                                                         "content-length broken:", ds->value, "-> 400");
48209 -                                                                       
48210 +
48211                                                                         con->http_status = 400;
48212                                                                         con->keep_alive = 0;
48213 -                                                                       
48214 +
48215                                                                         array_insert_unique(con->request.headers, (data_unset *)ds);
48216                                                                         return 0;
48217                                                                 }
48218 @@ -838,23 +841,24 @@
48219                                                                 } else {
48220                                                                         con->http_status = 400;
48221                                                                         con->keep_alive = 0;
48222 -                                                                       
48223 +
48224                                                                         if (srv->srvconf.log_request_header_on_error) {
48225 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
48226 +                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
48227                                                                                                 "duplicate Content-Type-header -> 400");
48228                                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48229                                                                                                 "request-header:\n",
48230                                                                                                 con->request.request);
48231                                                                         }
48232 +                                                                       ds->free((data_unset *) ds);
48233                                                                         return 0;
48234                                                                 }
48235                                                         } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Expect")))) {
48236 -                                                               /* HTTP 2616 8.2.3 
48237 +                                                               /* HTTP 2616 8.2.3
48238                                                                  * Expect: 100-continue
48239 -                                                                * 
48240 +                                                                *
48241                                                                  *   -> (10.1.1)  100 (read content, process request, send final status-code)
48242                                                                  *   -> (10.4.18) 417 (close)
48243 -                                                                * 
48244 +                                                                *
48245                                                                  * (not handled at all yet, we always send 417 here)
48246                                                                  *
48247                                                                  * What has to be added ?
48248 @@ -863,10 +867,10 @@
48249                                                                  *    header
48250                                                                  *
48251                                                                  */
48252 -                                                               
48253 +
48254                                                                 con->http_status = 417;
48255                                                                 con->keep_alive = 0;
48256 -                                                               
48257 +
48258                                                                 array_insert_unique(con->request.headers, (data_unset *)ds);
48259                                                                 return 0;
48260                                                         } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Host")))) {
48261 @@ -875,14 +879,15 @@
48262                                                                 } else {
48263                                                                         con->http_status = 400;
48264                                                                         con->keep_alive = 0;
48265 -                                                                       
48266 +
48267                                                                         if (srv->srvconf.log_request_header_on_error) {
48268 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
48269 +                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
48270                                                                                                 "duplicate Host-header -> 400");
48271                                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48272                                                                                                 "request-header:\n",
48273                                                                                                 con->request.request);
48274                                                                         }
48275 +                                                                       ds->free((data_unset *) ds);
48276                                                                         return 0;
48277                                                                 }
48278                                                         } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) {
48279 @@ -897,14 +902,15 @@
48280                                                                 } else {
48281                                                                         con->http_status = 400;
48282                                                                         con->keep_alive = 0;
48283 -                                                                       
48284 +
48285                                                                         if (srv->srvconf.log_request_header_on_error) {
48286 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
48287 +                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
48288                                                                                                 "duplicate If-Modified-Since header -> 400");
48289                                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48290                                                                                                 "request-header:\n",
48291                                                                                                 con->request.request);
48292                                                                         }
48293 +                                                                       ds->free((data_unset *) ds);
48294                                                                         return 0;
48295                                                                 }
48296                                                         } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-None-Match")))) {
48297 @@ -914,47 +920,49 @@
48298                                                                 } else {
48299                                                                         con->http_status = 400;
48300                                                                         con->keep_alive = 0;
48301 -                                                                       
48302 +
48303                                                                         if (srv->srvconf.log_request_header_on_error) {
48304 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
48305 +                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
48306                                                                                                 "duplicate If-None-Match-header -> 400");
48307                                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48308                                                                                                 "request-header:\n",
48309                                                                                                 con->request.request);
48310                                                                         }
48311 +                                                                       ds->free((data_unset *) ds);
48312                                                                         return 0;
48313                                                                 }
48314                                                         } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Range")))) {
48315                                                                 if (!con->request.http_range) {
48316                                                                         /* bytes=.*-.* */
48317 -                                                               
48318 +
48319                                                                         if (0 == strncasecmp(ds->value->ptr, "bytes=", 6) &&
48320                                                                             NULL != strchr(ds->value->ptr+6, '-')) {
48321 -                                                                               
48322 +
48323                                                                                 /* if dup, only the first one will survive */
48324                                                                                 con->request.http_range = ds->value->ptr + 6;
48325                                                                         }
48326                                                                 } else {
48327                                                                         con->http_status = 400;
48328                                                                         con->keep_alive = 0;
48329 -                                                                       
48330 +
48331                                                                         if (srv->srvconf.log_request_header_on_error) {
48332 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
48333 +                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
48334                                                                                                 "duplicate Range-header -> 400");
48335                                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48336                                                                                                 "request-header:\n",
48337                                                                                                 con->request.request);
48338                                                                         }
48339 +                                                                       ds->free((data_unset *) ds);
48340                                                                         return 0;
48341                                                                 }
48342                                                         }
48343 -                                                       
48344 +
48345                                                         array_insert_unique(con->request.headers, (data_unset *)ds);
48346                                                 } else {
48347                                                         /* empty header-fields are not allowed by HTTP-RFC, we just ignore them */
48348                                                 }
48349                                         }
48350 -                                       
48351 +
48352                                         i++;
48353                                         first = i+1;
48354                                         is_key = 1;
48355 @@ -963,10 +971,10 @@
48356                                         in_folding = 0;
48357                                 } else {
48358                                         if (srv->srvconf.log_request_header_on_error) {
48359 -                                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
48360 +                                               log_error_write(srv, __FILE__, __LINE__, "sbs",
48361                                                                 "CR without LF", con->request.request, "-> 400");
48362                                         }
48363 -                                       
48364 +
48365                                         con->http_status = 400;
48366                                         con->keep_alive = 0;
48367                                         con->response.keep_alive = 0;
48368 @@ -982,28 +990,28 @@
48369                         }
48370                 }
48371         }
48372 -       
48373 +
48374         con->header_len = i;
48375 -       
48376 +
48377         /* do some post-processing */
48378  
48379         if (con->request.http_version == HTTP_VERSION_1_1) {
48380                 if (keep_alive_set != HTTP_CONNECTION_CLOSE) {
48381                         /* no Connection-Header sent */
48382 -                       
48383 +
48384                         /* HTTP/1.1 -> keep-alive default TRUE */
48385                         con->keep_alive = 1;
48386                 } else {
48387                         con->keep_alive = 0;
48388                 }
48389 -               
48390 +
48391                 /* RFC 2616, 14.23 */
48392                 if (con->request.http_host == NULL ||
48393                     buffer_is_empty(con->request.http_host)) {
48394                         con->http_status = 400;
48395                         con->response.keep_alive = 0;
48396                         con->keep_alive = 0;
48397 -                       
48398 +
48399                         if (srv->srvconf.log_request_header_on_error) {
48400                                 log_error_write(srv, __FILE__, __LINE__, "s", "HTTP/1.1 but Host missing -> 400");
48401                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48402 @@ -1015,18 +1023,18 @@
48403         } else {
48404                 if (keep_alive_set == HTTP_CONNECTION_KEEPALIVE) {
48405                         /* no Connection-Header sent */
48406 -                       
48407 +
48408                         /* HTTP/1.0 -> keep-alive default FALSE  */
48409                         con->keep_alive = 1;
48410                 } else {
48411                         con->keep_alive = 0;
48412                 }
48413         }
48414 -       
48415 +
48416         /* check hostname field if it is set */
48417         if (NULL != con->request.http_host &&
48418             0 != request_check_hostname(srv, con, con->request.http_host)) {
48419 -               
48420 +
48421                 if (srv->srvconf.log_request_header_on_error) {
48422                         log_error_write(srv, __FILE__, __LINE__, "s",
48423                                         "Invalid Hostname -> 400");
48424 @@ -1038,7 +1046,7 @@
48425                 con->http_status = 400;
48426                 con->response.keep_alive = 0;
48427                 con->keep_alive = 0;
48428 -               
48429 +
48430                 return 0;
48431         }
48432  
48433 @@ -1048,7 +1056,7 @@
48434                 /* content-length is forbidden for those */
48435                 if (con_length_set && con->request.content_length != 0) {
48436                         /* content-length is missing */
48437 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
48438 +                       log_error_write(srv, __FILE__, __LINE__, "s",
48439                                         "GET/HEAD with content-length -> 400");
48440  
48441                         con->keep_alive = 0;
48442 @@ -1060,7 +1068,7 @@
48443                 /* content-length is required for them */
48444                 if (!con_length_set) {
48445                         /* content-length is missing */
48446 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
48447 +                       log_error_write(srv, __FILE__, __LINE__, "s",
48448                                         "POST-request, but content-length missing -> 411");
48449  
48450                         con->keep_alive = 0;
48451 @@ -1073,16 +1081,16 @@
48452                 /* the may have a content-length */
48453                 break;
48454         }
48455 -                       
48456 -       
48457 +
48458 +
48459         /* check if we have read post data */
48460         if (con_length_set) {
48461                 /* don't handle more the SSIZE_MAX bytes in content-length */
48462                 if (con->request.content_length > SSIZE_MAX) {
48463 -                       con->http_status = 413; 
48464 +                       con->http_status = 413;
48465                         con->keep_alive = 0;
48466  
48467 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
48468 +                       log_error_write(srv, __FILE__, __LINE__, "sds",
48469                                         "request-size too long:", con->request.content_length, "-> 413");
48470                         return 0;
48471                 }
48472 @@ -1090,25 +1098,25 @@
48473                 /* divide by 1024 as srvconf.max_request_size is in kBytes */
48474                 if (srv->srvconf.max_request_size != 0 &&
48475                     (con->request.content_length >> 10) > srv->srvconf.max_request_size) {
48476 -                       /* the request body itself is larger then 
48477 +                       /* the request body itself is larger then
48478                          * our our max_request_size
48479                          */
48480 -               
48481 +
48482                         con->http_status = 413;
48483                         con->keep_alive = 0;
48484 -               
48485 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
48486 +
48487 +                       log_error_write(srv, __FILE__, __LINE__, "sds",
48488                                         "request-size too long:", con->request.content_length, "-> 413");
48489                         return 0;
48490                 }
48491 -               
48492 -               
48493 +
48494 +
48495                 /* we have content */
48496                 if (con->request.content_length != 0) {
48497                         return 1;
48498                 }
48499         }
48500 -       
48501 +
48502         return 0;
48503  }
48504  
48505 @@ -1116,9 +1124,9 @@
48506         UNUSED(srv);
48507  
48508         if (con->request.request->used < 5) return 0;
48509 -       
48510 +
48511         if (0 == memcmp(con->request.request->ptr + con->request.request->used - 5, "\r\n\r\n", 4)) return 1;
48512         if (NULL != strstr(con->request.request->ptr, "\r\n\r\n")) return 1;
48513 -       
48514 +
48515         return 0;
48516  }
48517 --- ../lighttpd-1.4.11/src/response.c   2006-03-04 16:41:39.000000000 +0200
48518 +++ lighttpd-1.4.12/src/response.c      2006-07-16 00:26:04.000000000 +0300
48519 @@ -7,7 +7,6 @@
48520  #include <stdlib.h>
48521  #include <string.h>
48522  #include <time.h>
48523 -#include <unistd.h>
48524  #include <ctype.h>
48525  #include <assert.h>
48526  
48527 @@ -24,15 +23,17 @@
48528  #include "plugin.h"
48529  
48530  #include "sys-socket.h"
48531 +#include "sys-files.h"
48532 +#include "sys-strings.h"
48533  
48534  int http_response_write_header(server *srv, connection *con) {
48535         buffer *b;
48536         size_t i;
48537         int have_date = 0;
48538         int have_server = 0;
48539 -       
48540 +
48541         b = chunkqueue_get_prepend_buffer(con->write_queue);
48542 -       
48543 +
48544         if (con->request.http_version == HTTP_VERSION_1_1) {
48545                 BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 ");
48546         } else {
48547 @@ -41,25 +42,26 @@
48548         buffer_append_long(b, con->http_status);
48549         BUFFER_APPEND_STRING_CONST(b, " ");
48550         buffer_append_string(b, get_http_status_name(con->http_status));
48551 -       
48552 +
48553         if (con->request.http_version != HTTP_VERSION_1_1 || con->keep_alive == 0) {
48554                 BUFFER_APPEND_STRING_CONST(b, "\r\nConnection: ");
48555                 buffer_append_string(b, con->keep_alive ? "keep-alive" : "close");
48556         }
48557 -       
48558 +
48559         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
48560                 BUFFER_APPEND_STRING_CONST(b, "\r\nTransfer-Encoding: chunked");
48561         }
48562 -       
48563 -       
48564 +
48565 +
48566         /* add all headers */
48567         for (i = 0; i < con->response.headers->used; i++) {
48568                 data_string *ds;
48569 -               
48570 +
48571                 ds = (data_string *)con->response.headers->data[i];
48572 -               
48573 +
48574                 if (ds->value->used && ds->key->used &&
48575 -                   0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1)) {
48576 +                   0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1) &&
48577 +                   0 != strcasecmp(ds->key->ptr, "X-Sendfile")) {
48578                         if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Date"))) have_date = 1;
48579                         if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Server"))) have_server = 1;
48580  
48581 @@ -68,28 +70,28 @@
48582                         BUFFER_APPEND_STRING_CONST(b, ": ");
48583                         buffer_append_string_buffer(b, ds->value);
48584  #if 0
48585 -                       log_error_write(srv, __FILE__, __LINE__, "bb", 
48586 +                       log_error_write(srv, __FILE__, __LINE__, "bb",
48587                                         ds->key, ds->value);
48588  #endif
48589                 }
48590         }
48591 -       
48592 +
48593         if (!have_date) {
48594                 /* HTTP/1.1 requires a Date: header */
48595                 BUFFER_APPEND_STRING_CONST(b, "\r\nDate: ");
48596 -       
48597 +
48598                 /* cache the generated timestamp */
48599                 if (srv->cur_ts != srv->last_generated_date_ts) {
48600                         buffer_prepare_copy(srv->ts_date_str, 255);
48601 -               
48602 -                       strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1, 
48603 +
48604 +                       strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1,
48605                                  "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(srv->cur_ts)));
48606 -                        
48607 +
48608                         srv->ts_date_str->used = strlen(srv->ts_date_str->ptr) + 1;
48609 -               
48610 +
48611                         srv->last_generated_date_ts = srv->cur_ts;
48612                 }
48613 -       
48614 +
48615                 buffer_append_string_buffer(b, srv->ts_date_str);
48616         }
48617  
48618 @@ -101,16 +103,16 @@
48619                         buffer_append_string_buffer(b, con->conf.server_tag);
48620                 }
48621         }
48622 -       
48623 +
48624         BUFFER_APPEND_STRING_CONST(b, "\r\n\r\n");
48625 -       
48626 -       
48627 +
48628 +
48629         con->bytes_header = b->used - 1;
48630 -       
48631 +
48632         if (con->conf.log_response_header) {
48633                 log_error_write(srv, __FILE__, __LINE__, "sSb", "Response-Header:", "\n", b);
48634         }
48635 -       
48636 +
48637         return 0;
48638  }
48639  
48640 @@ -118,71 +120,71 @@
48641  
48642  handler_t http_response_prepare(server *srv, connection *con) {
48643         handler_t r;
48644 -       
48645 -       /* looks like someone has already done a decision */
48646 -       if (con->mode == DIRECT && 
48647 +
48648 +       /* looks like someone has already made a decision */
48649 +       if (con->mode == DIRECT &&
48650             (con->http_status != 0 && con->http_status != 200)) {
48651                 /* remove a packets in the queue */
48652                 if (con->file_finished == 0) {
48653                         chunkqueue_reset(con->write_queue);
48654                 }
48655 -               
48656 +
48657                 return HANDLER_FINISHED;
48658         }
48659 -       
48660 +
48661         /* no decision yet, build conf->filename */
48662         if (con->mode == DIRECT && con->physical.path->used == 0) {
48663                 char *qstr;
48664  
48665 -               /* we only come here when we have the parse the full request again
48666 -                * 
48667 -                * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a 
48668 +               /* we only come here when we have to parse the full request again
48669 +                *
48670 +                * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a
48671                  * problem here as mod_setenv might get called multiple times
48672                  *
48673                  * fastcgi-auth might lead to a COMEBACK too
48674                  * fastcgi again dead server too
48675                  *
48676                  * mod_compress might add headers twice too
48677 -                * 
48678 +                *
48679                  *  */
48680 -               
48681 +
48682                 if (con->conf.log_condition_handling) {
48683                         log_error_write(srv, __FILE__, __LINE__,  "s",  "run condition");
48684                 }
48685                 config_patch_connection(srv, con, COMP_SERVER_SOCKET); /* SERVERsocket */
48686 -               
48687 +
48688                 /**
48689                  * prepare strings
48690 -                * 
48691 -                * - uri.path_raw 
48692 +                *
48693 +                * - uri.path_raw
48694                  * - uri.path (secure)
48695                  * - uri.query
48696 -                * 
48697 +                *
48698                  */
48699 -               
48700 -               /** 
48701 +
48702 +               /**
48703                  * Name according to RFC 2396
48704 -                * 
48705 +                *
48706                  * - scheme
48707                  * - authority
48708                  * - path
48709                  * - query
48710 -                * 
48711 +                *
48712                  * (scheme)://(authority)(path)?(query)
48713 -                * 
48714 -                * 
48715 +                *
48716 +                *
48717                  */
48718 -       
48719 +
48720                 buffer_copy_string(con->uri.scheme, con->conf.is_ssl ? "https" : "http");
48721                 buffer_copy_string_buffer(con->uri.authority, con->request.http_host);
48722                 buffer_to_lower(con->uri.authority);
48723 -               
48724 +
48725                 config_patch_connection(srv, con, COMP_HTTP_HOST);      /* Host:        */
48726                 config_patch_connection(srv, con, COMP_HTTP_REMOTEIP);  /* Client-IP */
48727                 config_patch_connection(srv, con, COMP_HTTP_REFERER);   /* Referer:     */
48728                 config_patch_connection(srv, con, COMP_HTTP_USERAGENT); /* User-Agent:  */
48729                 config_patch_connection(srv, con, COMP_HTTP_COOKIE);    /* Cookie:  */
48730 -               
48731 +
48732                 /** extract query string from request.uri */
48733                 if (NULL != (qstr = strchr(con->request.uri->ptr, '?'))) {
48734                         buffer_copy_string    (con->uri.query, qstr + 1);
48735 @@ -200,22 +202,22 @@
48736                         log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-path     : ", con->uri.path_raw);
48737                         log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-query    : ", con->uri.query);
48738                 }
48739 -               
48740 +
48741                 /* disable keep-alive if requested */
48742 -               
48743 +
48744                 if (con->request_count > con->conf.max_keep_alive_requests) {
48745                         con->keep_alive = 0;
48746                 }
48747 -               
48748 -               
48749 +
48750 +
48751                 /**
48752 -                *  
48753 -                * call plugins 
48754 -                * 
48755 +                *
48756 +                * call plugins
48757 +                *
48758                  * - based on the raw URL
48759 -                * 
48760 +                *
48761                  */
48762 -               
48763 +
48764                 switch(r = plugins_call_handle_uri_raw(srv, con)) {
48765                 case HANDLER_GO_ON:
48766                         break;
48767 @@ -229,14 +231,14 @@
48768                         break;
48769                 }
48770  
48771 -               /* build filename 
48772 +               /* build filename
48773                  *
48774                  * - decode url-encodings  (e.g. %20 -> ' ')
48775                  * - remove path-modifiers (e.g. /../)
48776                  */
48777 -               
48778 -               
48779 -               
48780 +
48781 +
48782 +
48783                 if (con->request.http_method == HTTP_METHOD_OPTIONS &&
48784                     con->uri.path_raw->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
48785                         /* OPTIONS * ... */
48786 @@ -253,15 +255,20 @@
48787                 }
48788  
48789                 /**
48790 -                *  
48791 -                * call plugins 
48792 -                * 
48793 +                *
48794 +                * call plugins
48795 +                *
48796                  * - based on the clean URL
48797 -                * 
48798 +                *
48799                  */
48800 -               
48801 +
48802                 config_patch_connection(srv, con, COMP_HTTP_URL); /* HTTPurl */
48803 -               
48804 +
48805 +               /* do we have to downgrade to 1.0 ? */
48806 +               if (!con->conf.allow_http11) {
48807 +                       con->request.http_version = HTTP_VERSION_1_0;
48808 +               }
48809 +
48810                 switch(r = plugins_call_handle_uri_clean(srv, con)) {
48811                 case HANDLER_GO_ON:
48812                         break;
48813 @@ -274,11 +281,11 @@
48814                         log_error_write(srv, __FILE__, __LINE__, "");
48815                         break;
48816                 }
48817 -               
48818 +
48819                 if (con->request.http_method == HTTP_METHOD_OPTIONS &&
48820                     con->uri.path->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
48821 -                       /* option requests are handled directly without checking of the path */
48822 -               
48823 +                       /* option requests are handled directly without checking the path */
48824 +
48825                         response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
48826  
48827                         con->http_status = 200;
48828 @@ -288,46 +295,47 @@
48829                 }
48830  
48831                 /***
48832 -                * 
48833 -                * border 
48834 -                * 
48835 +                *
48836 +                * border
48837 +                *
48838                  * logical filename (URI) becomes a physical filename here
48839 -                * 
48840 -                * 
48841 -                * 
48842 +                *
48843 +                *
48844 +                *
48845                  */
48846 -               
48847 -               
48848 -               
48849 -               
48850 +
48851 +
48852 +
48853 +
48854                 /* 1. stat()
48855                  * ... ISREG() -> ok, go on
48856                  * ... ISDIR() -> index-file -> redirect
48857 -                * 
48858 -                * 2. pathinfo() 
48859 +                *
48860 +                * 2. pathinfo()
48861                  * ... ISREG()
48862 -                * 
48863 +                *
48864                  * 3. -> 404
48865 -                * 
48866 +                *
48867                  */
48868 -               
48869 +
48870                 /*
48871                  * SEARCH DOCUMENT ROOT
48872                  */
48873 -               
48874 +
48875                 /* set a default */
48876 -               
48877 +
48878                 buffer_copy_string_buffer(con->physical.doc_root, con->conf.document_root);
48879                 buffer_copy_string_buffer(con->physical.rel_path, con->uri.path);
48880 -               
48881 -#if defined(__WIN32) || defined(__CYGWIN__)
48882 -               /* strip dots from the end and spaces
48883 +
48884 +               filename_unix2local(con->physical.rel_path);
48885 +#if defined(_WIN32) || defined(__CYGWIN__)
48886 +               /* strip dots and spaces from the end
48887                  *
48888                  * windows/dos handle those filenames as the same file
48889                  *
48890                  * foo == foo. == foo..... == "foo...   " == "foo..  ./"
48891                  *
48892 -                * This will affect in some cases PATHINFO
48893 +                * This will affect PATHINFO in some cases
48894                  *
48895                  * on native windows we could prepend the filename with \\?\ to circumvent
48896                  * this behaviour. I have no idea how to push this through cygwin
48897 @@ -377,36 +385,41 @@
48898                         log_error_write(srv, __FILE__, __LINE__, "");
48899                         break;
48900                 }
48901 -               
48902 -               /* MacOS X and Windows can't distiguish between upper and lower-case 
48903 -                * 
48904 -                * convert to lower-case
48905 +
48906 +               /* The default Mac OS X and Windows filesystems can't distiguish between
48907 +                * upper- and lowercase, so convert to lowercase
48908                  */
48909                 if (con->conf.force_lowercase_filenames) {
48910                         buffer_to_lower(con->physical.rel_path);
48911                 }
48912  
48913 -               /* the docroot plugins might set the servername, if they don't we take http-host */
48914 +               /* the docroot plugins might set the servername; if they don't we take http-host */
48915                 if (buffer_is_empty(con->server_name)) {
48916                         buffer_copy_string_buffer(con->server_name, con->uri.authority);
48917                 }
48918 -               
48919 -               /** 
48920 -                * create physical filename 
48921 +
48922 +               /**
48923 +                * create physical filename
48924                  * -> physical.path = docroot + rel_path
48925 -                * 
48926 +                *
48927                  */
48928 -               
48929 +
48930                 buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
48931 -               BUFFER_APPEND_SLASH(con->physical.path);
48932 +               PATHNAME_APPEND_SLASH(con->physical.path);
48933                 buffer_copy_string_buffer(con->physical.basedir, con->physical.path);
48934                 if (con->physical.rel_path->used &&
48935 -                   con->physical.rel_path->ptr[0] == '/') {
48936 +                   con->physical.rel_path->ptr[0] == DIR_SEPERATOR) {
48937                         buffer_append_string_len(con->physical.path, con->physical.rel_path->ptr + 1, con->physical.rel_path->used - 2);
48938                 } else {
48939                         buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
48940                 }
48941  
48942 +        /* win32: directories can't have a trailing slash */
48943 +        if (con->physical.path->ptr[con->physical.path->used - 2] == DIR_SEPERATOR) {
48944 +            con->physical.path->ptr[con->physical.path->used - 2] = '\0';
48945 +            con->physical.path->used--;
48946 +        }
48947 +
48948                 if (con->conf.log_request_handling) {
48949                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- after doc_root");
48950                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
48951 @@ -426,7 +439,7 @@
48952                         log_error_write(srv, __FILE__, __LINE__, "");
48953                         break;
48954                 }
48955 -               
48956 +
48957                 if (con->conf.log_request_handling) {
48958                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- logical -> physical");
48959                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
48960 @@ -434,38 +447,38 @@
48961                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
48962                 }
48963         }
48964 -       
48965 -       /* 
48966 -        * Noone catched away the file from normal path of execution yet (like mod_access)
48967 -        * 
48968 +
48969 +       /*
48970 +        * No one took the file away from the normal path of execution yet (like mod_access)
48971 +        *
48972          * Go on and check of the file exists at all
48973          */
48974 -       
48975 +
48976         if (con->mode == DIRECT) {
48977                 char *slash = NULL;
48978                 char *pathinfo = NULL;
48979                 int found = 0;
48980                 stat_cache_entry *sce = NULL;
48981 -               
48982 +
48983                 if (con->conf.log_request_handling) {
48984                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling physical path");
48985                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
48986                 }
48987 -               
48988 +
48989                 if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
48990                         /* file exists */
48991 -                       
48992 +
48993                         if (con->conf.log_request_handling) {
48994                                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- file found");
48995                                 log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
48996                         }
48997 -                       
48998 +
48999                         if (S_ISDIR(sce->st.st_mode)) {
49000 -                               if (con->physical.path->ptr[con->physical.path->used - 2] != '/') {
49001 +                               if (con->uri.path->ptr[con->uri.path->used - 2] != '/') {
49002                                         /* redirect to .../ */
49003 -                                       
49004 +
49005                                         http_response_redirect_to_directory(srv, con);
49006 -                                       
49007 +
49008                                         return HANDLER_FINISHED;
49009                                 }
49010                         } else if (!S_ISREG(sce->st.st_mode)) {
49011 @@ -477,12 +490,12 @@
49012                         switch (errno) {
49013                         case EACCES:
49014                                 con->http_status = 403;
49015 -       
49016 +
49017                                 if (con->conf.log_request_handling) {
49018                                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- access denied");
49019                                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
49020                                 }
49021 -                       
49022 +
49023                                 buffer_reset(con->physical.path);
49024                                 return HANDLER_FINISHED;
49025                         case ENOENT:
49026 @@ -499,77 +512,77 @@
49027                                 /* PATH_INFO ! :) */
49028                                 break;
49029                         default:
49030 -                               /* we have no idea what happend. let's tell the user so. */
49031 +                               /* we have no idea what happened, so tell the user. */
49032                                 con->http_status = 500;
49033                                 buffer_reset(con->physical.path);
49034 -                               
49035 +
49036                                 log_error_write(srv, __FILE__, __LINE__, "ssbsb",
49037                                                 "file not found ... or so: ", strerror(errno),
49038                                                 con->uri.path,
49039                                                 "->", con->physical.path);
49040 -                               
49041 +
49042                                 return HANDLER_FINISHED;
49043                         }
49044 -                       
49045 +
49046                         /* not found, perhaps PATHINFO */
49047 -                       
49048 +
49049                         buffer_copy_string_buffer(srv->tmp_buf, con->physical.path);
49050 -                       
49051 +
49052                         do {
49053                                 struct stat st;
49054 -                               
49055 +
49056                                 if (slash) {
49057                                         buffer_copy_string_len(con->physical.path, srv->tmp_buf->ptr, slash - srv->tmp_buf->ptr);
49058                                 } else {
49059                                         buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
49060                                 }
49061 -                               
49062 +
49063                                 if (0 == stat(con->physical.path->ptr, &(st)) &&
49064                                     S_ISREG(st.st_mode)) {
49065                                         found = 1;
49066                                         break;
49067                                 }
49068 -                               
49069 +
49070                                 if (pathinfo != NULL) {
49071                                         *pathinfo = '\0';
49072                                 }
49073                                 slash = strrchr(srv->tmp_buf->ptr, '/');
49074 -                               
49075 +
49076                                 if (pathinfo != NULL) {
49077                                         /* restore '/' */
49078                                         *pathinfo = '/';
49079                                 }
49080 -                               
49081 +
49082                                 if (slash) pathinfo = slash;
49083                         } while ((found == 0) && (slash != NULL) && (slash - srv->tmp_buf->ptr > con->physical.basedir->used - 2));
49084 -                       
49085 +
49086                         if (found == 0) {
49087 -                               /* no it really doesn't exists */
49088 +                               /* no, it really doesn't exists */
49089                                 con->http_status = 404;
49090 -                               
49091 +
49092                                 if (con->conf.log_file_not_found) {
49093                                         log_error_write(srv, __FILE__, __LINE__, "sbsb",
49094                                                         "file not found:", con->uri.path,
49095                                                         "->", con->physical.path);
49096                                 }
49097 -                               
49098 +
49099                                 buffer_reset(con->physical.path);
49100 -                               
49101 +
49102                                 return HANDLER_FINISHED;
49103                         }
49104 -                       
49105 +
49106                         /* we have a PATHINFO */
49107                         if (pathinfo) {
49108                                 buffer_copy_string(con->request.pathinfo, pathinfo);
49109 -                               
49110 +
49111                                 /*
49112                                  * shorten uri.path
49113                                  */
49114 -                               
49115 +
49116                                 con->uri.path->used -= strlen(pathinfo);
49117                                 con->uri.path->ptr[con->uri.path->used - 1] = '\0';
49118                         }
49119 -                       
49120 +
49121                         if (con->conf.log_request_handling) {
49122                                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- after pathinfo check");
49123                                 log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
49124 @@ -577,12 +590,12 @@
49125                                 log_error_write(srv, __FILE__, __LINE__,  "sb", "Pathinfo     :", con->request.pathinfo);
49126                         }
49127                 }
49128 -               
49129 +
49130                 if (con->conf.log_request_handling) {
49131                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling subrequest");
49132                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
49133                 }
49134 -               
49135 +
49136                 /* call the handlers */
49137                 switch(r = plugins_call_handle_subrequest_start(srv, con)) {
49138                 case HANDLER_GO_ON:
49139 @@ -593,32 +606,32 @@
49140                         if (con->conf.log_request_handling) {
49141                                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- subrequest finished");
49142                         }
49143 -                       
49144 -                       /* something strange happend */
49145 +
49146 +                       /* something strange happened */
49147                         return r;
49148                 }
49149 -               
49150 -               /* if we are still here, no one wanted the file, status 403 is ok I think */
49151 -               
49152 +
49153 +               /* if we are still here, no one wanted the file; status 403 is ok I think */
49154 +
49155                 if (con->mode == DIRECT) {
49156                         con->http_status = 403;
49157 -                       
49158 +
49159                         return HANDLER_FINISHED;
49160                 }
49161 -               
49162 +
49163         }
49164 -       
49165 +
49166         switch(r = plugins_call_handle_subrequest(srv, con)) {
49167         case HANDLER_GO_ON:
49168 -               /* request was not handled, looks like we are done */
49169 +               /* request was not handled; looks like we are done */
49170                 return HANDLER_FINISHED;
49171         case HANDLER_FINISHED:
49172                 /* request is finished */
49173         default:
49174 -               /* something strange happend */
49175 +               /* something strange happened */
49176                 return r;
49177         }
49178 -       
49179 +
49180         /* can't happen */
49181         return HANDLER_COMEBACK;
49182  }
49183 --- ../lighttpd-1.4.11/src/server.c     2006-03-04 19:12:17.000000000 +0200
49184 +++ lighttpd-1.4.12/src/server.c        2006-07-18 13:03:40.000000000 +0300
49185 @@ -1,11 +1,9 @@
49186  #include <sys/types.h>
49187 -#include <sys/time.h>
49188  #include <sys/stat.h>
49189  
49190  #include <string.h>
49191  #include <errno.h>
49192  #include <fcntl.h>
49193 -#include <unistd.h>
49194  #include <stdlib.h>
49195  #include <time.h>
49196  #include <signal.h>
49197 @@ -29,9 +27,14 @@
49198  #include "plugin.h"
49199  #include "joblist.h"
49200  #include "network_backends.h"
49201 -
49202 +#ifdef _WIN32
49203 +/* use local getopt implementation */
49204 +# undef HAVE_GETOPT_H
49205 +#endif
49206  #ifdef HAVE_GETOPT_H
49207  #include <getopt.h>
49208 +#else
49209 +#include "getopt.h"
49210  #endif
49211  
49212  #ifdef HAVE_VALGRIND_VALGRIND_H
49213 @@ -60,8 +63,17 @@
49214  /* #define USE_ALARM */
49215  #endif
49216  
49217 +#ifdef _WIN32
49218 +#undef HAVE_SIGNAL
49219 +#endif
49220 +
49221 +#include "sys-files.h"
49222 +#include "sys-process.h"
49223 +#include "sys-socket.h"
49224 +
49225  static volatile sig_atomic_t srv_shutdown = 0;
49226  static volatile sig_atomic_t graceful_shutdown = 0;
49227 +static volatile sig_atomic_t graceful_restart = 0;
49228  static volatile sig_atomic_t handle_sig_alarm = 1;
49229  static volatile sig_atomic_t handle_sig_hup = 0;
49230  
49231 @@ -72,9 +84,9 @@
49232  
49233         switch (sig) {
49234         case SIGTERM: srv_shutdown = 1; break;
49235 -       case SIGINT: 
49236 +       case SIGINT:
49237              if (graceful_shutdown) srv_shutdown = 1;
49238 -            else graceful_shutdown = 1; 
49239 +            else graceful_shutdown = 1;
49240  
49241              break;
49242         case SIGALRM: handle_sig_alarm = 1; break;
49243 @@ -86,9 +98,9 @@
49244  static void signal_handler(int sig) {
49245         switch (sig) {
49246         case SIGTERM: srv_shutdown = 1; break;
49247 -       case SIGINT: 
49248 +       case SIGINT:
49249              if (graceful_shutdown) srv_shutdown = 1;
49250 -            else graceful_shutdown = 1; 
49251 +            else graceful_shutdown = 1;
49252  
49253              break;
49254         case SIGALRM: handle_sig_alarm = 1; break;
49255 @@ -110,35 +122,35 @@
49256         signal(SIGTSTP, SIG_IGN);
49257  #endif
49258         if (0 != fork()) exit(0);
49259 -       
49260 +
49261         if (-1 == setsid()) exit(0);
49262  
49263         signal(SIGHUP, SIG_IGN);
49264  
49265         if (0 != fork()) exit(0);
49266 -       
49267 +
49268         if (0 != chdir("/")) exit(0);
49269  }
49270  #endif
49271  
49272  static server *server_init(void) {
49273         int i;
49274 -       
49275 +
49276         server *srv = calloc(1, sizeof(*srv));
49277         assert(srv);
49278 +    srv->max_fds = 1024;
49279  #define CLEAN(x) \
49280         srv->x = buffer_init();
49281 -       
49282 +
49283         CLEAN(response_header);
49284         CLEAN(parse_full_path);
49285         CLEAN(ts_debug_str);
49286         CLEAN(ts_date_str);
49287 -       CLEAN(errorlog_buf);
49288         CLEAN(response_range);
49289         CLEAN(tmp_buf);
49290         srv->empty_string = buffer_init_string("");
49291         CLEAN(cond_check_buf);
49292 -       
49293 +
49294         CLEAN(srvconf.errorlog_file);
49295         CLEAN(srvconf.groupname);
49296         CLEAN(srvconf.username);
49297 @@ -146,68 +158,63 @@
49298         CLEAN(srvconf.bindhost);
49299         CLEAN(srvconf.event_handler);
49300         CLEAN(srvconf.pid_file);
49301 -       
49302 +
49303         CLEAN(tmp_chunk_len);
49304  #undef CLEAN
49305 -       
49306 +
49307  #define CLEAN(x) \
49308         srv->x = array_init();
49309 -       
49310 +
49311         CLEAN(config_context);
49312         CLEAN(config_touched);
49313         CLEAN(status);
49314  #undef CLEAN
49315 -       
49316 +
49317         for (i = 0; i < FILE_CACHE_MAX; i++) {
49318                 srv->mtime_cache[i].str = buffer_init();
49319         }
49320 -       
49321 +
49322         srv->cur_ts = time(NULL);
49323         srv->startup_ts = srv->cur_ts;
49324 -       
49325 +
49326         srv->conns = calloc(1, sizeof(*srv->conns));
49327         assert(srv->conns);
49328 -       
49329 +
49330         srv->joblist = calloc(1, sizeof(*srv->joblist));
49331         assert(srv->joblist);
49332 -       
49333 +
49334         srv->fdwaitqueue = calloc(1, sizeof(*srv->fdwaitqueue));
49335         assert(srv->fdwaitqueue);
49336 -       
49337 +
49338         srv->srvconf.modules = array_init();
49339         srv->srvconf.modules_dir = buffer_init_string(LIBRARY_DIR);
49340         srv->srvconf.network_backend = buffer_init();
49341         srv->srvconf.upload_tempdirs = array_init();
49342 -       
49343 -       /* use syslog */
49344 -       srv->errorlog_fd = -1;
49345 -       srv->errorlog_mode = ERRORLOG_STDERR;
49346  
49347         srv->split_vals = array_init();
49348 -       
49349 +
49350         return srv;
49351  }
49352  
49353  static void server_free(server *srv) {
49354         size_t i;
49355 -       
49356 +
49357         for (i = 0; i < FILE_CACHE_MAX; i++) {
49358                 buffer_free(srv->mtime_cache[i].str);
49359         }
49360 -       
49361 +
49362  #define CLEAN(x) \
49363         buffer_free(srv->x);
49364 -       
49365 +
49366         CLEAN(response_header);
49367         CLEAN(parse_full_path);
49368         CLEAN(ts_debug_str);
49369         CLEAN(ts_date_str);
49370 -       CLEAN(errorlog_buf);
49371         CLEAN(response_range);
49372         CLEAN(tmp_buf);
49373         CLEAN(empty_string);
49374         CLEAN(cond_check_buf);
49375 -       
49376 +
49377         CLEAN(srvconf.errorlog_file);
49378         CLEAN(srvconf.groupname);
49379         CLEAN(srvconf.username);
49380 @@ -217,7 +224,7 @@
49381         CLEAN(srvconf.pid_file);
49382         CLEAN(srvconf.modules_dir);
49383         CLEAN(srvconf.network_backend);
49384 -       
49385 +
49386         CLEAN(tmp_chunk_len);
49387  #undef CLEAN
49388  
49389 @@ -225,15 +232,15 @@
49390         fdevent_unregister(srv->ev, srv->fd);
49391  #endif
49392         fdevent_free(srv->ev);
49393 -       
49394 +
49395         free(srv->conns);
49396 -       
49397 +
49398         if (srv->config_storage) {
49399                 for (i = 0; i < srv->config_context->used; i++) {
49400                         specific_config *s = srv->config_storage[i];
49401  
49402                         if (!s) continue;
49403 -                       
49404 +
49405                         buffer_free(s->document_root);
49406                         buffer_free(s->server_name);
49407                         buffer_free(s->server_tag);
49408 @@ -242,32 +249,32 @@
49409                         buffer_free(s->error_handler);
49410                         buffer_free(s->errorfile_prefix);
49411                         array_free(s->mimetypes);
49412 -                       
49413 +
49414                         free(s);
49415                 }
49416                 free(srv->config_storage);
49417                 srv->config_storage = NULL;
49418         }
49419 -       
49420 +
49421  #define CLEAN(x) \
49422         array_free(srv->x);
49423 -       
49424 +
49425         CLEAN(config_context);
49426         CLEAN(config_touched);
49427         CLEAN(status);
49428         CLEAN(srvconf.upload_tempdirs);
49429  #undef CLEAN
49430 -       
49431 +
49432         joblist_free(srv, srv->joblist);
49433         fdwaitqueue_free(srv, srv->fdwaitqueue);
49434 -       
49435 +
49436         if (srv->stat_cache) {
49437                 stat_cache_free(srv->stat_cache);
49438         }
49439  
49440         array_free(srv->srvconf.modules);
49441         array_free(srv->split_vals);
49442 -       
49443 +
49444         free(srv);
49445  }
49446  
49447 @@ -281,14 +288,12 @@
49448  " - a light and fast webserver\n" \
49449  "Build-Date: " __DATE__ " " __TIME__ "\n";
49450  ;
49451 -#undef TEXT_SSL        
49452 +#undef TEXT_SSL
49453         write(STDOUT_FILENO, b, strlen(b));
49454  }
49455  
49456  static void show_features (void) {
49457 -  show_version();
49458 -  printf("\nEvent Handlers:\n\n%s",
49459 -
49460 +  const char *s = ""
49461  #ifdef USE_SELECT
49462        "\t+ select (generic)\n"
49463  #else
49464 @@ -355,11 +360,6 @@
49465  #else
49466        "\t- crypt support\n"
49467  #endif
49468 -#ifdef USE_PAM
49469 -      "\t+ PAM support\n"
49470 -#else
49471 -      "\t- PAM support\n"
49472 -#endif
49473  #ifdef USE_OPENSSL
49474        "\t+ SSL Support\n"
49475  #else
49476 @@ -371,9 +371,9 @@
49477        "\t- PCRE support\n"
49478  #endif
49479  #ifdef HAVE_MYSQL
49480 -      "\t+ mySQL support\n"
49481 +      "\t+ MySQL support\n"
49482  #else
49483 -      "\t- mySQL support\n"
49484 +      "\t- MySQL support\n"
49485  #endif
49486  #if defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER)
49487        "\t+ LDAP support\n"
49488 @@ -410,8 +410,11 @@
49489  #else
49490        "\t- GDBM support\n"
49491  #endif
49492 -      "\n"
49493 -      );
49494 +      "\n";
49495 +
49496 +  show_version();
49497 +
49498 +  printf("\nEvent Handlers:\n\n%s", s);
49499  }
49500  
49501  static void show_help (void) {
49502 @@ -433,277 +436,644 @@
49503  " -h         show this help\n" \
49504  "\n"
49505  ;
49506 -#undef TEXT_SSL        
49507 +#undef TEXT_SSL
49508  #undef TEXT_IPV6
49509         write(STDOUT_FILENO, b, strlen(b));
49510  }
49511  
49512 -int main (int argc, char **argv) {
49513 -       server *srv = NULL;
49514 -       int print_config = 0;
49515 -       int test_config = 0;
49516 -       int i_am_root;
49517 -       int o;
49518 -       int num_childs = 0;
49519 -       int pid_fd = -1, fd;
49520 -       size_t i;
49521 -#ifdef HAVE_SIGACTION
49522 -       struct sigaction act;
49523 -#endif
49524 -#ifdef HAVE_GETRLIMIT
49525 -       struct rlimit rlim;
49526 -#endif
49527 -       
49528 -#ifdef USE_ALARM
49529 -       struct itimerval interval;
49530 -       
49531 -       interval.it_interval.tv_sec = 1;
49532 -       interval.it_interval.tv_usec = 0;
49533 -       interval.it_value.tv_sec = 1;
49534 -       interval.it_value.tv_usec = 0;
49535 -#endif
49536 -       
49537 -       
49538 -       /* for nice %b handling in strfime() */
49539 -       setlocale(LC_TIME, "C");
49540 -       
49541 -       if (NULL == (srv = server_init())) {
49542 -               fprintf(stderr, "did this really happen?\n");
49543 -               return -1;
49544 -       }
49545 -       
49546 -       /* init structs done */
49547 -       
49548 -       srv->srvconf.port = 0;
49549 -#ifdef HAVE_GETUID
49550 -       i_am_root = (getuid() == 0);
49551 -#else
49552 -       i_am_root = 0;
49553 -#endif
49554 -       srv->srvconf.dont_daemonize = 0;
49555 -       
49556 -       while(-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) {
49557 -               switch(o) {
49558 -               case 'f': 
49559 -                       if (config_read(srv, optarg)) { 
49560 -                               server_free(srv);
49561 -                               return -1;
49562 -                       }
49563 -                       break;
49564 -               case 'm':
49565 -                       buffer_copy_string(srv->srvconf.modules_dir, optarg);
49566 -                       break;
49567 -               case 'p': print_config = 1; break;
49568 -               case 't': test_config = 1; break;
49569 -               case 'D': srv->srvconf.dont_daemonize = 1; break;
49570 -               case 'v': show_version(); return 0;
49571 -               case 'V': show_features(); return 0;          
49572 -               case 'h': show_help(); return 0;
49573 -               default: 
49574 -                       show_help();
49575 -                       server_free(srv);
49576 -                       return -1;
49577 -               }
49578 -       }
49579 -       
49580 -       if (!srv->config_storage) {
49581 -               log_error_write(srv, __FILE__, __LINE__, "s",
49582 -                               "No configuration available. Try using -f option.");
49583 -               
49584 -               server_free(srv);
49585 -               return -1;
49586 -       }
49587 -       
49588 -       if (print_config) {
49589 -               data_unset *dc = srv->config_context->data[0];
49590 -               if (dc) {
49591 -                       dc->print(dc, 0);
49592 -                       fprintf(stderr, "\n");
49593 -               } else {
49594 -                       /* shouldn't happend */
49595 -                       fprintf(stderr, "global config not found\n");
49596 -               }
49597 -       }
49598 +int lighty_mainloop(server *srv) {
49599 +       fdevent_revents *revents = fdevent_revents_init();
49600  
49601 -       if (test_config) {
49602 -               printf("Syntax OK\n");
49603 -       }
49604 +       /* main-loop */
49605 +       while (!srv_shutdown) {
49606 +               int n;
49607 +               size_t ndx;
49608 +               time_t min_ts;
49609  
49610 -       if (test_config || print_config) {
49611 -               server_free(srv);
49612 -               return 0;
49613 -       }
49614 -       
49615 -       /* close stdin and stdout, as they are not needed */
49616 -       /* move stdin to /dev/null */
49617 -       if (-1 != (fd = open("/dev/null", O_RDONLY))) {
49618 -               close(STDIN_FILENO);
49619 -               dup2(fd, STDIN_FILENO);
49620 -               close(fd);
49621 -       }
49622 -       
49623 -       /* move stdout to /dev/null */
49624 -       if (-1 != (fd = open("/dev/null", O_WRONLY))) {
49625 -               close(STDOUT_FILENO);
49626 -               dup2(fd, STDOUT_FILENO);
49627 -               close(fd);
49628 -       }
49629 -       
49630 -       if (0 != config_set_defaults(srv)) {
49631 -               log_error_write(srv, __FILE__, __LINE__, "s", 
49632 -                               "setting default values failed");
49633 -               server_free(srv);
49634 -               return -1;
49635 -       }
49636 -       
49637 -       /* UID handling */
49638 -#ifdef HAVE_GETUID
49639 -       if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
49640 -               /* we are setuid-root */
49641 -               
49642 -               log_error_write(srv, __FILE__, __LINE__, "s", 
49643 -                               "Are you nuts ? Don't apply a SUID bit to this binary");
49644 -               
49645 -               server_free(srv);
49646 -               return -1;
49647 -       }
49648 -#endif
49649 -       
49650 -       /* check document-root */
49651 -       if (srv->config_storage[0]->document_root->used <= 1) {
49652 -               log_error_write(srv, __FILE__, __LINE__, "s", 
49653 -                               "document-root is not set\n");
49654 -               
49655 -               server_free(srv);
49656 -               
49657 -               return -1;
49658 -       }
49659 -       
49660 -       if (plugins_load(srv)) {
49661 -               log_error_write(srv, __FILE__, __LINE__, "s",
49662 -                               "loading plugins finally failed");
49663 -               
49664 -               plugins_free(srv);
49665 -               server_free(srv);
49666 -               
49667 -               return -1;
49668 -       }
49669 -       
49670 -       /* open pid file BEFORE chroot */
49671 -       if (srv->srvconf.pid_file->used) {
49672 -               if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
49673 -                       struct stat st;
49674 -                       if (errno != EEXIST) {
49675 -                               log_error_write(srv, __FILE__, __LINE__, "sbs",
49676 -                                       "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49677 -                               return -1;
49678 -                       }
49679 -                       
49680 -                       if (0 != stat(srv->srvconf.pid_file->ptr, &st)) {
49681 -                               log_error_write(srv, __FILE__, __LINE__, "sbs",
49682 -                                               "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49683 -                       }
49684 -                       
49685 -                       if (!S_ISREG(st.st_mode)) {
49686 -                               log_error_write(srv, __FILE__, __LINE__, "sb",
49687 -                                               "pid-file exists and isn't regular file:", srv->srvconf.pid_file);
49688 -                               return -1;
49689 -                       }
49690 -                       
49691 -                       if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
49692 -                               log_error_write(srv, __FILE__, __LINE__, "sbs",
49693 -                                               "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49694 -                               return -1;
49695 +               if (handle_sig_hup) {
49696 +                       handler_t r;
49697 +
49698 +                       /* reset notification */
49699 +                       handle_sig_hup = 0;
49700 +
49701 +#if 0
49702 +                               pid_t pid;
49703 +
49704 +                       /* send the old process into a graceful-shutdown and start a
49705 +                        * new process right away
49706 +                        *
49707 +                        * BUGS:
49708 +                        * - if webserver is running on port < 1024 (e.g. 80, 433)
49709 +                        *   we don't have the permissions to bind to that port anymore
49710 +                        *
49711 +                        *
49712 +                        *  */
49713 +                       if (0 == (pid = fork())) {
49714 +                               execve(argv[0], argv, envp);
49715 +
49716 +                               exit(-1);
49717 +                       } else if (pid == -1) {
49718 +
49719 +                       } else {
49720 +                               /* parent */
49721 +
49722 +                               graceful_shutdown = 1; /* shutdown without killing running connections */
49723 +                               graceful_restart = 1;  /* don't delete pid file */
49724                         }
49725 -               }
49726 -       }
49727 +#else
49728 +                       /* cycle logfiles */
49729  
49730 -       if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
49731 -               /* select limits itself
49732 -                *
49733 -                * as it is a hard limit and will lead to a segfault we add some safety
49734 -                * */
49735 -               srv->max_fds = FD_SETSIZE - 200;
49736 -       } else {
49737 -               srv->max_fds = 4096;
49738 -       }
49739 +                       switch(r = plugins_call_handle_sighup(srv)) {
49740 +                       case HANDLER_GO_ON:
49741 +                               break;
49742 +                       default:
49743 +                               log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r);
49744 +                               break;
49745 +                       }
49746  
49747 -       if (i_am_root) {
49748 -               struct group *grp = NULL;
49749 -               struct passwd *pwd = NULL;
49750 -               int use_rlimit = 1;
49751 +                       if (-1 == log_error_cycle()) {
49752 +                               log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying");
49753  
49754 -#ifdef HAVE_VALGRIND_VALGRIND_H
49755 -               if (RUNNING_ON_VALGRIND) use_rlimit = 0;
49756 -#endif
49757 -               
49758 -#ifdef HAVE_GETRLIMIT
49759 -               if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) {
49760 -                       log_error_write(srv, __FILE__, __LINE__,
49761 -                                       "ss", "couldn't get 'max filedescriptors'",
49762 -                                       strerror(errno));
49763 -                       return -1;
49764 -               }
49765 -               
49766 -               if (use_rlimit && srv->srvconf.max_fds) {
49767 -                       /* set rlimits */
49768 -                       
49769 -                       rlim.rlim_cur = srv->srvconf.max_fds;
49770 -                       rlim.rlim_max = srv->srvconf.max_fds;
49771 -                       
49772 -                       if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) {
49773 -                               log_error_write(srv, __FILE__, __LINE__,
49774 -                                               "ss", "couldn't set 'max filedescriptors'",
49775 -                                               strerror(errno));
49776                                 return -1;
49777                         }
49778 +#endif
49779                 }
49780  
49781 -               /* #372: solaris need some fds extra for devpoll */     
49782 -               if (rlim.rlim_cur > 10) rlim.rlim_cur -= 10;
49783 +               if (handle_sig_alarm) {
49784 +                       /* a new second */
49785  
49786 -               if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
49787 -                       srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200;
49788 -               } else {
49789 -                       srv->max_fds = rlim.rlim_cur;
49790 -               }
49791 +#ifdef USE_ALARM
49792 +                       /* reset notification */
49793 +                       handle_sig_alarm = 0;
49794 +#endif
49795  
49796 -               /* set core file rlimit, if enable_cores is set */
49797 -               if (use_rlimit && srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) {
49798 -                       rlim.rlim_cur = rlim.rlim_max;
49799 +                       /* get current time */
49800 +                       min_ts = time(NULL);
49801 +
49802 +                       if (min_ts != srv->cur_ts) {
49803 +                               int cs = 0;
49804 +                               connections *conns = srv->conns;
49805 +                               handler_t r;
49806 +
49807 +                               switch(r = plugins_call_handle_trigger(srv)) {
49808 +                               case HANDLER_GO_ON:
49809 +                                       break;
49810 +                               case HANDLER_ERROR:
49811 +                                       log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed");
49812 +                                       break;
49813 +                               default:
49814 +                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
49815 +                                       break;
49816 +                               }
49817 +
49818 +                               /* trigger waitpid */
49819 +                               srv->cur_ts = min_ts;
49820 +
49821 +                               /* cleanup stat-cache */
49822 +                               stat_cache_trigger_cleanup(srv);
49823 +                               /**
49824 +                                * check all connections for timeouts
49825 +                                *
49826 +                                */
49827 +                               for (ndx = 0; ndx < conns->used; ndx++) {
49828 +                                       int changed = 0;
49829 +                                       connection *con;
49830 +                                       int t_diff;
49831 +
49832 +                                       con = conns->ptr[ndx];
49833 +
49834 +                                       if (con->state == CON_STATE_READ ||
49835 +                                           con->state == CON_STATE_READ_POST) {
49836 +                                               if (con->request_count == 1) {
49837 +                                                       if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
49838 +                                                               /* time - out */
49839 +#if 0
49840 +                                                               log_error_write(srv, __FILE__, __LINE__, "sd",
49841 +                                                                               "connection closed - read-timeout:", con->fd);
49842 +#endif
49843 +                                                               connection_set_state(srv, con, CON_STATE_ERROR);
49844 +                                                               changed = 1;
49845 +                                                       }
49846 +                                               } else {
49847 +                                                       if (srv->cur_ts - con->read_idle_ts > con->conf.max_keep_alive_idle) {
49848 +                                                               /* time - out */
49849 +#if 0
49850 +                                                               log_error_write(srv, __FILE__, __LINE__, "sd",
49851 +                                                                               "connection closed - read-timeout:", con->fd);
49852 +#endif
49853 +                                                               connection_set_state(srv, con, CON_STATE_ERROR);
49854 +                                                               changed = 1;
49855 +                                                       }
49856 +                                               }
49857 +                                       }
49858 +
49859 +                                       if ((con->state == CON_STATE_WRITE) &&
49860 +                                           (con->write_request_ts != 0)) {
49861 +#if 0
49862 +                                               if (srv->cur_ts - con->write_request_ts > 60) {
49863 +                                                       log_error_write(srv, __FILE__, __LINE__, "sdd",
49864 +                                                                       "connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts);
49865 +                                               }
49866 +#endif
49867 +
49868 +                                               if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) {
49869 +                                                       /* time - out */
49870 +#if 1
49871 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbsosds",
49872 +                                                                       "NOTE: a request for",
49873 +                                                                       con->request.uri,
49874 +                                                                       "timed out after writing",
49875 +                                                                       con->bytes_written,
49876 +                                                                       "bytes. We waited",
49877 +                                                                       (int)con->conf.max_write_idle,
49878 +                                                                       "seconds. If this a problem increase server.max-write-idle");
49879 +#endif
49880 +                                                       connection_set_state(srv, con, CON_STATE_ERROR);
49881 +                                                       changed = 1;
49882 +                                               }
49883 +                                       }
49884 +                                       /* we don't like div by zero */
49885 +                                       if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1;
49886 +
49887 +                                       if (con->traffic_limit_reached &&
49888 +                                           (con->conf.kbytes_per_second == 0 ||
49889 +                                            ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) {
49890 +                                               /* enable connection again */
49891 +                                               con->traffic_limit_reached = 0;
49892 +
49893 +                                               changed = 1;
49894 +                                       }
49895 +
49896 +                                       if (changed) {
49897 +                                               connection_state_machine(srv, con);
49898 +                                       }
49899 +                                       con->bytes_written_cur_second = 0;
49900 +                                       *(con->conf.global_bytes_per_second_cnt_ptr) = 0;
49901 +
49902 +#if 0
49903 +                                       if (cs == 0) {
49904 +                                               fprintf(stderr, "connection-state: ");
49905 +                                               cs = 1;
49906 +                                       }
49907 +
49908 +                                       fprintf(stderr, "c[%d,%d]: %s ",
49909 +                                               con->fd,
49910 +                                               con->fcgi.fd,
49911 +                                               connection_get_state(con->state));
49912 +#endif
49913 +                               }
49914 +
49915 +                               if (cs == 1) fprintf(stderr, "\n");
49916 +                       }
49917 +               }
49918 +
49919 +               if (srv->sockets_disabled) {
49920 +                       /* our server sockets are disabled, why ? */
49921 +
49922 +                       if ((srv->cur_fds + srv->want_fds < srv->max_fds * 0.8) && /* we have enough unused fds */
49923 +                           (srv->conns->used < srv->max_conns * 0.9) &&
49924 +                           (0 == graceful_shutdown)) {
49925 +                               size_t i;
49926 +
49927 +                               for (i = 0; i < srv->srv_sockets.used; i++) {
49928 +                                       server_socket *srv_socket = srv->srv_sockets.ptr[i];
49929 +                                       fdevent_event_add(srv->ev, srv_socket->sock, FDEVENT_IN);
49930 +                               }
49931 +
49932 +                               log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again");
49933 +
49934 +                               srv->sockets_disabled = 0;
49935 +                       }
49936 +               } else {
49937 +                       if ((srv->cur_fds + srv->want_fds > srv->max_fds * 0.9) || /* out of fds */
49938 +                           (srv->conns->used > srv->max_conns) || /* out of connections */
49939 +                           (graceful_shutdown)) { /* graceful_shutdown */
49940 +                               size_t i;
49941 +
49942 +                               /* disable server-fds */
49943 +
49944 +                               for (i = 0; i < srv->srv_sockets.used; i++) {
49945 +                                       server_socket *srv_socket = srv->srv_sockets.ptr[i];
49946 +                                       fdevent_event_del(srv->ev, srv_socket->sock);
49947 +
49948 +                                       if (graceful_shutdown) {
49949 +                                               /* we don't want this socket anymore,
49950 +                                                *
49951 +                                                * closing it right away will make it possible for
49952 +                                                * the next lighttpd to take over (graceful restart)
49953 +                                                *  */
49954 +
49955 +                                               fdevent_unregister(srv->ev, srv_socket->sock);
49956 +                                               closesocket(srv_socket->sock->fd);
49957 +                                               srv_socket->sock->fd = -1;
49958 +
49959 +                                               /* network_close() will cleanup after us */
49960 +                                       }
49961 +                               }
49962 +
49963 +                               if (graceful_shutdown) {
49964 +                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started");
49965 +                               } else if (srv->conns->used > srv->max_conns) {
49966 +                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached");
49967 +                               } else {
49968 +                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds");
49969 +                               }
49970 +
49971 +                               srv->sockets_disabled = 1;
49972 +                       }
49973 +               }
49974 +
49975 +               if (graceful_shutdown && srv->conns->used == 0) {
49976 +                       /* we are in graceful shutdown phase and all connections are closed
49977 +                        * we are ready to terminate without harming anyone */
49978 +                       srv_shutdown = 1;
49979 +               }
49980 +
49981 +               /* we still have some fds to share */
49982 +               if (srv->want_fds) {
49983 +                       /* check the fdwaitqueue for waiting fds */
49984 +                       int free_fds = srv->max_fds - srv->cur_fds - 16;
49985 +                       connection *con;
49986 +
49987 +                       for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) {
49988 +                               connection_state_machine(srv, con);
49989 +
49990 +                               srv->want_fds--;
49991 +                       }
49992 +               }
49993 +
49994 +               if ((n = fdevent_poll(srv->ev, 1000)) > 0) {
49995 +                       /* n is the number of events */
49996 +                       size_t i;
49997 +                       fdevent_get_revents(srv->ev, n, revents);
49998 +
49999 +                       /* handle client connections first
50000 +                        * 
50001 +                        * this is a bit of a hack, but we have to make sure than we handle 
50002 +                        * close-events before the connection is reused for a keep-alive 
50003 +                        * request
50004 +                        *
50005 +                        * this is mostly an issue for mod_proxy_core, but you never know
50006 +                        *
50007 +                        */
50008 +
50009 +                       for (i = 0; i < revents->used; i++) {
50010 +                               fdevent_revent *revent = revents->ptr[i];
50011 +                               handler_t r;
50012 +
50013 +                               /* skip server-fds */
50014 +                               if (revent->handler == network_server_handle_fdevent) continue;
50015 +
50016 +                               switch (r = (*(revent->handler))(srv, revent->context, revent->revents)) {
50017 +                               case HANDLER_FINISHED:
50018 +                               case HANDLER_GO_ON:
50019 +                               case HANDLER_WAIT_FOR_EVENT:
50020 +                               case HANDLER_WAIT_FOR_FD:
50021 +                                       break;
50022 +                               case HANDLER_ERROR:
50023 +                                       /* should never happen */
50024 +                                       SEGFAULT();
50025 +                                       break;
50026 +                               default:
50027 +                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
50028 +                                       break;
50029 +                               }
50030 +                       } 
50031 +
50032 +                       for (i = 0; i < revents->used; i++) {
50033 +                               fdevent_revent *revent = revents->ptr[i];
50034 +                               handler_t r;
50035 +
50036 +                               /* server fds only */
50037 +                               if (revent->handler != network_server_handle_fdevent) continue;
50038 +
50039 +                               switch (r = (*(revent->handler))(srv, revent->context, revent->revents)) {
50040 +                               case HANDLER_FINISHED:
50041 +                               case HANDLER_GO_ON:
50042 +                               case HANDLER_WAIT_FOR_EVENT:
50043 +                               case HANDLER_WAIT_FOR_FD:
50044 +                                       break;
50045 +                               case HANDLER_ERROR:
50046 +                                       /* should never happen */
50047 +                                       SEGFAULT();
50048 +                                       break;
50049 +                               default:
50050 +                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
50051 +                                       break;
50052 +                               }
50053 +                       } 
50054 +
50055 +               } else if (n < 0 && errno != EINTR) {
50056 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
50057 +                                       "fdevent_poll failed:",
50058 +                                       strerror(errno));
50059 +               }
50060 +
50061 +               for (ndx = 0; ndx < srv->joblist->used; ndx++) {
50062 +                       connection *con = srv->joblist->ptr[ndx];
50063 +                       handler_t r;
50064 +
50065 +                       connection_state_machine(srv, con);
50066 +
50067 +                       switch(r = plugins_call_handle_joblist(srv, con)) {
50068 +                       case HANDLER_FINISHED:
50069 +                       case HANDLER_GO_ON:
50070 +                               break;
50071 +                       default:
50072 +                               log_error_write(srv, __FILE__, __LINE__, "d", r);
50073 +                               break;
50074 +                       }
50075 +
50076 +                       con->in_joblist = 0;
50077 +               }
50078 +
50079 +               srv->joblist->used = 0;
50080 +       }
50081 +
50082 +       fdevent_revents_free(revents);
50083 +
50084 +       return 0;
50085 +}
50086 +
50087 +
50088 +int main (int argc, char **argv, char **envp) {
50089 +       server *srv = NULL;
50090 +       int print_config = 0;
50091 +       int test_config = 0;
50092 +       int i_am_root;
50093 +       int o;
50094 +       int num_childs = 0;
50095 +       int pid_fd = -1, fd;
50096 +       size_t i;
50097 +#ifdef _WIN32
50098 +       char *optarg = NULL;
50099 +#endif
50100 +
50101 +#ifdef HAVE_SIGACTION
50102 +       struct sigaction act;
50103 +#endif
50104 +#ifdef HAVE_GETRLIMIT
50105 +       struct rlimit rlim;
50106 +#endif
50107 +
50108 +#ifdef USE_ALARM
50109 +       struct itimerval interval;
50110 +
50111 +       interval.it_interval.tv_sec = 1;
50112 +       interval.it_interval.tv_usec = 0;
50113 +       interval.it_value.tv_sec = 1;
50114 +       interval.it_value.tv_usec = 0;
50115 +#endif
50116 +
50117 +       log_init();
50118 +
50119 +       /* for nice %b handling in strfime() */
50120 +       setlocale(LC_TIME, "C");
50121 +
50122 +       if (NULL == (srv = server_init())) {
50123 +               fprintf(stderr, "did this really happen?\n");
50124 +               return -1;
50125 +       }
50126 +
50127 +       /* init structs done */
50128 +
50129 +       srv->srvconf.port = 0;
50130 +#ifdef HAVE_GETUID
50131 +       i_am_root = (getuid() == 0);
50132 +#else
50133 +       i_am_root = 0;
50134 +#endif
50135 +       srv->srvconf.dont_daemonize = 0;
50136 +
50137 +       while(-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) {
50138 +               switch(o) {
50139 +               case 'f':
50140 +#ifdef _WIN32
50141 +                       /* evil HACK for windows, optarg is not set */
50142 +                       optarg = argv[optind-1];
50143 +#endif
50144 +                       if (config_read(srv, optarg)) {
50145 +                               server_free(srv);
50146 +                               return -1;
50147 +                       }
50148 +
50149 +                       break;
50150 +               case 'm':
50151 +                       buffer_copy_string(srv->srvconf.modules_dir, optarg);
50152 +                       break;
50153 +               case 'p': print_config = 1; break;
50154 +               case 't': test_config = 1; break;
50155 +               case 'D': srv->srvconf.dont_daemonize = 1; break;
50156 +               case 'v': show_version(); return 0;
50157 +               case 'V': show_features(); return 0;
50158 +               case 'h': show_help(); return 0;
50159 +               default:
50160 +                       show_help();
50161 +                       server_free(srv);
50162 +                       return -1;
50163 +               }
50164 +       }
50165 +
50166 +       if (!srv->config_storage) {
50167 +               log_error_write(srv, __FILE__, __LINE__, "s",
50168 +                               "No configuration available. Try using -f option.");
50169 +
50170 +               server_free(srv);
50171 +               return -1;
50172 +       }
50173 +
50174 +       if (print_config) {
50175 +               data_unset *dc = srv->config_context->data[0];
50176 +               if (dc) {
50177 +                       dc->print(dc, 0);
50178 +                       fprintf(stderr, "\n");
50179 +               } else {
50180 +                       /* shouldn't happend */
50181 +                       fprintf(stderr, "global config not found\n");
50182 +               }
50183 +       }
50184 +
50185 +       if (test_config) {
50186 +               printf("Syntax OK\n");
50187 +       }
50188 +
50189 +       if (test_config || print_config) {
50190 +               server_free(srv);
50191 +               return 0;
50192 +       }
50193 +
50194 +       /* close stdin and stdout, as they are not needed */
50195 +       /* move stdin to /dev/null */
50196 +       if (-1 != (fd = open("/dev/null", O_RDONLY))) {
50197 +               close(STDIN_FILENO);
50198 +               dup2(fd, STDIN_FILENO);
50199 +               close(fd);
50200 +       }
50201 +
50202 +       /* move stdout to /dev/null */
50203 +       if (-1 != (fd = open("/dev/null", O_WRONLY))) {
50204 +               close(STDOUT_FILENO);
50205 +               dup2(fd, STDOUT_FILENO);
50206 +               close(fd);
50207 +       }
50208 +
50209 +       if (0 != config_set_defaults(srv)) {
50210 +               log_error_write(srv, __FILE__, __LINE__, "s",
50211 +                               "setting default values failed");
50212 +               server_free(srv);
50213 +               return -1;
50214 +       }
50215 +
50216 +       /* UID handling */
50217 +#ifdef HAVE_GETUID
50218 +       if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
50219 +               /* we are setuid-root */
50220 +
50221 +               log_error_write(srv, __FILE__, __LINE__, "s",
50222 +                               "Are you nuts ? Don't apply a SUID bit to this binary");
50223 +
50224 +               server_free(srv);
50225 +               return -1;
50226 +       }
50227 +#endif
50228 +
50229 +       /* check document-root */
50230 +       if (srv->config_storage[0]->document_root->used <= 1) {
50231 +               log_error_write(srv, __FILE__, __LINE__, "s",
50232 +                               "document-root is not set\n");
50233 +
50234 +               server_free(srv);
50235 +
50236 +               return -1;
50237 +       }
50238 +
50239 +       if (plugins_load(srv)) {
50240 +               log_error_write(srv, __FILE__, __LINE__, "s",
50241 +                               "loading plugins finally failed");
50242 +
50243 +               plugins_free(srv);
50244 +               server_free(srv);
50245 +
50246 +               return -1;
50247 +       }
50248 +
50249 +#ifndef _WIN32
50250 +       /* open pid file BEFORE chroot */
50251 +       if (srv->srvconf.pid_file->used) {
50252 +               if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
50253 +                       struct stat st;
50254 +                       if (errno != EEXIST) {
50255 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
50256 +                                       "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
50257 +                               return -1;
50258 +                       }
50259 +
50260 +                       if (0 != stat(srv->srvconf.pid_file->ptr, &st)) {
50261 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
50262 +                                               "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno));
50263 +                       }
50264 +
50265 +                       if (!S_ISREG(st.st_mode)) {
50266 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
50267 +                                               "pid-file exists and isn't regular file:", srv->srvconf.pid_file);
50268 +                               return -1;
50269 +                       }
50270 +
50271 +                       if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
50272 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
50273 +                                               "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
50274 +                               return -1;
50275 +                       }
50276 +               }
50277 +       }
50278 +#endif
50279 +       if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50280 +               /* select limits itself
50281 +                *
50282 +                * as it is a hard limit and will lead to a segfault we add some safety
50283 +                * */
50284 +        fprintf(stderr, "%s.%d: max parallel connections: %d\r\n", __FILE__, __LINE__, FD_SETSIZE);
50285 +               srv->max_fds = FD_SETSIZE - 4;
50286 +       } else {
50287 +               srv->max_fds = 4096;
50288 +       }
50289 +
50290 +       if (i_am_root) {
50291 +               struct group *grp = NULL;
50292 +               struct passwd *pwd = NULL;
50293 +               int use_rlimit = 1;
50294 +
50295 +#ifdef HAVE_VALGRIND_VALGRIND_H
50296 +               if (RUNNING_ON_VALGRIND) use_rlimit = 0;
50297 +#endif
50298 +
50299 +#ifdef HAVE_GETRLIMIT
50300 +               if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) {
50301 +                       log_error_write(srv, __FILE__, __LINE__,
50302 +                                       "ss", "couldn't get 'max filedescriptors'",
50303 +                                       strerror(errno));
50304 +                       return -1;
50305 +               }
50306 +
50307 +               if (use_rlimit && srv->srvconf.max_fds) {
50308 +                       /* set rlimits */
50309 +
50310 +                       rlim.rlim_cur = srv->srvconf.max_fds;
50311 +                       rlim.rlim_max = srv->srvconf.max_fds;
50312 +
50313 +                       if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) {
50314 +                               log_error_write(srv, __FILE__, __LINE__,
50315 +                                               "ss", "couldn't set 'max filedescriptors'",
50316 +                                               strerror(errno));
50317 +                               return -1;
50318 +                       }
50319 +               }
50320 +
50321 +               /* #372: solaris need some fds extra for devpoll */
50322 +               if (rlim.rlim_cur > 10) rlim.rlim_cur -= 10;
50323 +
50324 +               if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50325 +                       srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200;
50326 +               } else {
50327 +                       srv->max_fds = rlim.rlim_cur;
50328 +               }
50329 +
50330 +               /* set core file rlimit, if enable_cores is set */
50331 +               if (use_rlimit && srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) {
50332 +                       rlim.rlim_cur = rlim.rlim_max;
50333                         setrlimit(RLIMIT_CORE, &rlim);
50334                 }
50335  #endif
50336                 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50337                         /* don't raise the limit above FD_SET_SIZE */
50338                         if (srv->max_fds > FD_SETSIZE - 200) {
50339 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
50340 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
50341                                                 "can't raise max filedescriptors above",  FD_SETSIZE - 200,
50342                                                 "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds.");
50343                                 return -1;
50344                         }
50345                 }
50346  
50347 -               
50348 +
50349  #ifdef HAVE_PWD_H
50350                 /* set user and group */
50351                 if (srv->srvconf.username->used) {
50352                         if (NULL == (pwd = getpwnam(srv->srvconf.username->ptr))) {
50353 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
50354 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
50355                                                 "can't find username", srv->srvconf.username);
50356                                 return -1;
50357                         }
50358 -                       
50359 +
50360                         if (pwd->pw_uid == 0) {
50361                                 log_error_write(srv, __FILE__, __LINE__, "s",
50362                                                 "I will not set uid to 0\n");
50363                                 return -1;
50364                         }
50365                 }
50366 -               
50367 +
50368                 if (srv->srvconf.groupname->used) {
50369                         if (NULL == (grp = getgrnam(srv->srvconf.groupname->ptr))) {
50370 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
50371 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
50372                                         "can't find groupname", srv->srvconf.groupname);
50373                                 return -1;
50374                         }
50375 @@ -713,15 +1083,15 @@
50376                                 return -1;
50377                         }
50378                 }
50379 -#endif         
50380 +#endif
50381                 /* we need root-perms for port < 1024 */
50382                 if (0 != network_init(srv)) {
50383                         plugins_free(srv);
50384                         server_free(srv);
50385 -                       
50386 +
50387                         return -1;
50388                 }
50389 -#ifdef HAVE_CHROOT     
50390 +#ifdef HAVE_CHROOT
50391                 if (srv->srvconf.changeroot->used) {
50392                         tzset();
50393  
50394 @@ -761,7 +1131,7 @@
50395                 }
50396  
50397                 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50398 -                       srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200;
50399 +                       srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 4 ? rlim.rlim_cur : FD_SETSIZE - 4;
50400                 } else {
50401                         srv->max_fds = rlim.rlim_cur;
50402                 }
50403 @@ -775,18 +1145,18 @@
50404  #endif
50405                 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50406                         /* don't raise the limit above FD_SET_SIZE */
50407 -                       if (srv->max_fds > FD_SETSIZE - 200) {
50408 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
50409 -                                               "can't raise max filedescriptors above",  FD_SETSIZE - 200,
50410 +                       if (srv->max_fds > FD_SETSIZE - 4) {
50411 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
50412 +                                               "can't raise max filedescriptors above",  FD_SETSIZE - 4,
50413                                                 "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds.");
50414                                 return -1;
50415                         }
50416                 }
50417 -               
50418 +
50419                 if (0 != network_init(srv)) {
50420                         plugins_free(srv);
50421                         server_free(srv);
50422 -                       
50423 +
50424                         return -1;
50425                 }
50426         }
50427 @@ -802,25 +1172,27 @@
50428                 /* or use the default */
50429                 srv->max_conns = srv->max_fds;
50430         }
50431 -       
50432 +
50433         if (HANDLER_GO_ON != plugins_call_init(srv)) {
50434                 log_error_write(srv, __FILE__, __LINE__, "s", "Initialization of plugins failed. Going down.");
50435 -               
50436 +
50437                 plugins_free(srv);
50438                 network_close(srv);
50439                 server_free(srv);
50440 -               
50441 +
50442                 return -1;
50443         }
50444  
50445 -#ifdef HAVE_FORK       
50446 +#ifdef HAVE_FORK
50447         /* network is up, let's deamonize ourself */
50448         if (srv->srvconf.dont_daemonize == 0) daemonize();
50449  #endif
50450  
50451 +#ifdef HAVE_PWD_H
50452         srv->gid = getgid();
50453         srv->uid = getuid();
50454 -       
50455 +#endif
50456 +
50457         /* write pid file */
50458         if (pid_fd != -1) {
50459                 buffer_copy_long(srv->tmp_buf, getpid());
50460 @@ -829,17 +1201,17 @@
50461                 close(pid_fd);
50462                 pid_fd = -1;
50463         }
50464 -       
50465 +
50466         if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) {
50467                 log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down.");
50468 -               
50469 +
50470                 plugins_free(srv);
50471                 network_close(srv);
50472                 server_free(srv);
50473 -               
50474 +
50475                 return -1;
50476         }
50477 -       
50478 +
50479         /* dump unused config-keys */
50480         for (i = 0; i < srv->config_context->used; i++) {
50481                 array *config = ((data_config *)srv->config_context->data[i])->value;
50482 @@ -847,43 +1219,42 @@
50483  
50484                 for (j = 0; config && j < config->used; j++) {
50485                         data_unset *du = config->data[j];
50486 -                       
50487 +
50488                         /* all var.* is known as user defined variable */
50489                         if (strncmp(du->key->ptr, "var.", sizeof("var.") - 1) == 0) {
50490                                 continue;
50491                         }
50492  
50493                         if (NULL == array_get_element(srv->config_touched, du->key->ptr)) {
50494 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
50495 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
50496                                                 "WARNING: unknown config-key:",
50497                                                 du->key,
50498                                                 "(ignored)");
50499                         }
50500                 }
50501         }
50502 -       
50503 +
50504         if (srv->config_deprecated) {
50505 -               log_error_write(srv, __FILE__, __LINE__, "s", 
50506 +               log_error_write(srv, __FILE__, __LINE__, "s",
50507                                 "Configuration contains deprecated keys. Going down.");
50508 -               
50509 +
50510                 plugins_free(srv);
50511                 network_close(srv);
50512                 server_free(srv);
50513 -               
50514 +
50515                 return -1;
50516         }
50517 -       
50518 -       if (-1 == log_error_open(srv)) {
50519 -               log_error_write(srv, __FILE__, __LINE__, "s", 
50520 +
50521 +       if (-1 == log_error_open(srv->srvconf.errorlog_file, srv->srvconf.errorlog_use_syslog)) {
50522 +               log_error_write(srv, __FILE__, __LINE__, "s",
50523                                 "opening errorlog failed, dying");
50524 -               
50525 +
50526                 plugins_free(srv);
50527                 network_close(srv);
50528                 server_free(srv);
50529                 return -1;
50530         }
50531 -       
50532 -       
50533 +
50534  #ifdef HAVE_SIGACTION
50535         memset(&act, 0, sizeof(act));
50536         act.sa_handler = SIG_IGN;
50537 @@ -903,7 +1274,7 @@
50538         sigaction(SIGHUP,  &act, NULL);
50539         sigaction(SIGALRM, &act, NULL);
50540         sigaction(SIGCHLD, &act, NULL);
50541 -       
50542 +
50543  #elif defined(HAVE_SIGNAL)
50544         /* ignore the SIGPIPE from sendfile() */
50545         signal(SIGPIPE, SIG_IGN);
50546 @@ -914,20 +1285,20 @@
50547         signal(SIGCHLD,  signal_handler);
50548         signal(SIGINT,  signal_handler);
50549  #endif
50550 -       
50551 +
50552  #ifdef USE_ALARM
50553         signal(SIGALRM, signal_handler);
50554 -       
50555 +
50556         /* setup periodic timer (1 second) */
50557         if (setitimer(ITIMER_REAL, &interval, NULL)) {
50558                 log_error_write(srv, __FILE__, __LINE__, "s", "setting timer failed");
50559                 return -1;
50560         }
50561 -       
50562 +
50563         getitimer(ITIMER_REAL, &interval);
50564  #endif
50565  
50566 -#ifdef HAVE_FORK       
50567 +#ifdef HAVE_FORK
50568         /* start watcher and workers */
50569         num_childs = srv->srvconf.max_worker;
50570         if (num_childs > 0) {
50571 @@ -957,13 +1328,13 @@
50572         }
50573  #endif
50574  
50575 -       if (NULL == (srv->ev = fdevent_init(srv->max_fds + 1, srv->event_handler))) {
50576 +       if (NULL == (srv->ev = fdevent_init(/*srv->max_fds + 1*/ 4096, srv->event_handler))) {
50577                 log_error_write(srv, __FILE__, __LINE__,
50578                                 "s", "fdevent_init failed");
50579                 return -1;
50580         }
50581 -       /* 
50582 -        * kqueue() is called here, select resets its internals, 
50583 +       /*
50584 +        * kqueue() is called here, select resets its internals,
50585          * all server sockets get their handlers
50586          *
50587          * */
50588 @@ -971,7 +1342,7 @@
50589                 plugins_free(srv);
50590                 network_close(srv);
50591                 server_free(srv);
50592 -               
50593 +
50594                 return -1;
50595         }
50596  
50597 @@ -986,17 +1357,17 @@
50598         /* setup FAM */
50599         if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) {
50600                 if (0 != FAMOpen2(srv->stat_cache->fam, "lighttpd")) {
50601 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
50602 +                       log_error_write(srv, __FILE__, __LINE__, "s",
50603                                          "could not open a fam connection, dieing.");
50604                         return -1;
50605                 }
50606  #ifdef HAVE_FAMNOEXISTS
50607                 FAMNoExists(srv->stat_cache->fam);
50608  #endif
50609 +               srv->stat_cache->sock->fd = FAMCONNECTION_GETFD(srv->stat_cache->fam);
50610  
50611 -               srv->stat_cache->fam_fcce_ndx = -1;
50612 -               fdevent_register(srv->ev, FAMCONNECTION_GETFD(srv->stat_cache->fam), stat_cache_handle_fdevent, NULL);
50613 -               fdevent_event_add(srv->ev, &(srv->stat_cache->fam_fcce_ndx), FAMCONNECTION_GETFD(srv->stat_cache->fam), FDEVENT_IN);
50614 +               fdevent_register(srv->ev, srv->stat_cache->sock, stat_cache_handle_fdevent, NULL);
50615 +               fdevent_event_add(srv->ev, srv->stat_cache->sock, FDEVENT_IN);
50616         }
50617  #endif
50618  
50619 @@ -1007,330 +1378,34 @@
50620  
50621         for (i = 0; i < srv->srv_sockets.used; i++) {
50622                 server_socket *srv_socket = srv->srv_sockets.ptr[i];
50623 -               if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->fd)) {
50624 +               if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->sock)) {
50625                         log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno));
50626                         return -1;
50627                 }
50628         }
50629  
50630 -       /* main-loop */
50631 -       while (!srv_shutdown) {
50632 -               int n;
50633 -               size_t ndx;
50634 -               time_t min_ts;
50635 -               
50636 -               if (handle_sig_hup) {
50637 -                       handler_t r;
50638 -                       
50639 -                       /* reset notification */
50640 -                       handle_sig_hup = 0;
50641 -                       
50642 -                       
50643 -                       /* cycle logfiles */
50644 -                       
50645 -                       switch(r = plugins_call_handle_sighup(srv)) {
50646 -                       case HANDLER_GO_ON:
50647 -                               break;
50648 -                       default:
50649 -                               log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r);
50650 -                               break;
50651 -                       }
50652 -                       
50653 -                       if (-1 == log_error_cycle(srv)) {
50654 -                               log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying");
50655 -                               
50656 -                               return -1;
50657 -                       }
50658 -               }
50659 -               
50660 -               if (handle_sig_alarm) {
50661 -                       /* a new second */
50662 -                       
50663 -#ifdef USE_ALARM
50664 -                       /* reset notification */
50665 -                       handle_sig_alarm = 0;
50666 -#endif
50667 -                       
50668 -                       /* get current time */
50669 -                       min_ts = time(NULL);
50670 -                       
50671 -                       if (min_ts != srv->cur_ts) {
50672 -                               int cs = 0;
50673 -                               connections *conns = srv->conns;
50674 -                               handler_t r;
50675 -                               
50676 -                               switch(r = plugins_call_handle_trigger(srv)) {
50677 -                               case HANDLER_GO_ON:
50678 -                                       break;
50679 -                               case HANDLER_ERROR:
50680 -                                       log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed");
50681 -                                       break;
50682 -                               default:
50683 -                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
50684 -                                       break;
50685 -                               }
50686 -                               
50687 -                               /* trigger waitpid */
50688 -                               srv->cur_ts = min_ts;
50689 -                       
50690 -                               /* cleanup stat-cache */        
50691 -                               stat_cache_trigger_cleanup(srv);
50692 -                               /**
50693 -                                * check all connections for timeouts 
50694 -                                * 
50695 -                                */
50696 -                               for (ndx = 0; ndx < conns->used; ndx++) {
50697 -                                       int changed = 0;
50698 -                                       connection *con;
50699 -                                       int t_diff;
50700 -                                       
50701 -                                       con = conns->ptr[ndx];
50702 -
50703 -                                       if (con->state == CON_STATE_READ ||
50704 -                                           con->state == CON_STATE_READ_POST) {
50705 -                                               if (con->request_count == 1) {
50706 -                                                       if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
50707 -                                                               /* time - out */
50708 -#if 0
50709 -                                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
50710 -                                                                               "connection closed - read-timeout:", con->fd);
50711 -#endif
50712 -                                                               connection_set_state(srv, con, CON_STATE_ERROR);
50713 -                                                               changed = 1;
50714 -                                                       }
50715 -                                               } else {
50716 -                                                       if (srv->cur_ts - con->read_idle_ts > con->conf.max_keep_alive_idle) {
50717 -                                                               /* time - out */
50718 -#if 0
50719 -                                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
50720 -                                                                               "connection closed - read-timeout:", con->fd);
50721 -#endif
50722 -                                                               connection_set_state(srv, con, CON_STATE_ERROR);
50723 -                                                               changed = 1;
50724 -                                                       }
50725 -                                               }
50726 -                                       }
50727 -                                       
50728 -                                       if ((con->state == CON_STATE_WRITE) &&
50729 -                                           (con->write_request_ts != 0)) { 
50730 -#if 0
50731 -                                               if (srv->cur_ts - con->write_request_ts > 60) {
50732 -                                                       log_error_write(srv, __FILE__, __LINE__, "sdd", 
50733 -                                                                       "connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts);
50734 -                                               }
50735 -#endif
50736 -                                               
50737 -                                               if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) {
50738 -                                                       /* time - out */
50739 -#if 1
50740 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbsosds", 
50741 -                                                                       "NOTE: a request for",
50742 -                                                                       con->request.uri,
50743 -                                                                       "timed out after writing",
50744 -                                                                       con->bytes_written,
50745 -                                                                       "bytes. We waited",
50746 -                                                                       (int)con->conf.max_write_idle,
50747 -                                                                       "seconds. If this a problem increase server.max-write-idle");
50748 -#endif
50749 -                                                       connection_set_state(srv, con, CON_STATE_ERROR);
50750 -                                                       changed = 1;
50751 -                                               }
50752 -                                       }
50753 -                                       /* we don't like div by zero */
50754 -                                       if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1;
50755 -       
50756 -                                       if (con->traffic_limit_reached && 
50757 -                                           (con->conf.kbytes_per_second == 0 || 
50758 -                                            ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) {
50759 -                                               /* enable connection again */
50760 -                                               con->traffic_limit_reached = 0;
50761 -                                               
50762 -                                               changed = 1;
50763 -                                       }
50764 -                                       
50765 -                                       if (changed) {
50766 -                                               connection_state_machine(srv, con);
50767 -                                       }
50768 -                                       con->bytes_written_cur_second = 0;
50769 -                                       *(con->conf.global_bytes_per_second_cnt_ptr) = 0;
50770 -                                       
50771 -#if 0
50772 -                                       if (cs == 0) {
50773 -                                               fprintf(stderr, "connection-state: ");
50774 -                                               cs = 1;
50775 -                                       }
50776 -                                       
50777 -                                       fprintf(stderr, "c[%d,%d]: %s ",
50778 -                                               con->fd,
50779 -                                               con->fcgi.fd,
50780 -                                               connection_get_state(con->state));
50781 -#endif
50782 -                               }
50783 -                               
50784 -                               if (cs == 1) fprintf(stderr, "\n");
50785 -                       }
50786 -               }
50787 -
50788 -               if (srv->sockets_disabled) {
50789 -                       /* our server sockets are disabled, why ? */
50790 -
50791 -                       if ((srv->cur_fds + srv->want_fds < srv->max_fds * 0.8) && /* we have enough unused fds */
50792 -                           (srv->conns->used < srv->max_conns * 0.9) &&
50793 -                           (0 == graceful_shutdown)) {
50794 -                               for (i = 0; i < srv->srv_sockets.used; i++) {
50795 -                                       server_socket *srv_socket = srv->srv_sockets.ptr[i];
50796 -                                       fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
50797 -                               }
50798 -                       
50799 -                               log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again");
50800 -                       
50801 -                               srv->sockets_disabled = 0;
50802 -                       }
50803 -               } else {
50804 -                       if ((srv->cur_fds + srv->want_fds > srv->max_fds * 0.9) || /* out of fds */
50805 -                           (srv->conns->used > srv->max_conns) || /* out of connections */
50806 -                           (graceful_shutdown)) { /* graceful_shutdown */ 
50807 -
50808 -                               /* disable server-fds */
50809 -                       
50810 -                               for (i = 0; i < srv->srv_sockets.used; i++) {
50811 -                                       server_socket *srv_socket = srv->srv_sockets.ptr[i];
50812 -                                       fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
50813 -
50814 -                                       if (graceful_shutdown) {
50815 -                                               /* we don't want this socket anymore,
50816 -                                                *
50817 -                                                * closing it right away will make it possible for
50818 -                                                * the next lighttpd to take over (graceful restart)
50819 -                                                *  */
50820 -
50821 -                                               fdevent_unregister(srv->ev, srv_socket->fd);
50822 -                                               close(srv_socket->fd);
50823 -                                               srv_socket->fd = -1;
50824 -
50825 -                                               /* network_close() will cleanup after us */
50826 -                                       }
50827 -                               }
50828 -               
50829 -                               if (graceful_shutdown) {
50830 -                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started");
50831 -                               } else if (srv->conns->used > srv->max_conns) {
50832 -                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached");
50833 -                               } else {
50834 -                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds");
50835 -                               }
50836 -                       
50837 -                               srv->sockets_disabled = 1;
50838 -                       }
50839 -               }
50840 -
50841 -               if (graceful_shutdown && srv->conns->used == 0) {
50842 -                       /* we are in graceful shutdown phase and all connections are closed
50843 -                        * we are ready to terminate without harming anyone */
50844 -                       srv_shutdown = 1;
50845 -               }
50846 -               
50847 -               /* we still have some fds to share */
50848 -               if (srv->want_fds) { 
50849 -                       /* check the fdwaitqueue for waiting fds */
50850 -                       int free_fds = srv->max_fds - srv->cur_fds - 16;
50851 -                       connection *con;
50852 -                       
50853 -                       for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) {
50854 -                               connection_state_machine(srv, con);
50855 -                               
50856 -                               srv->want_fds--;
50857 -                       }
50858 -               }
50859 +       lighty_mainloop(srv);
50860  
50861 -               if ((n = fdevent_poll(srv->ev, 1000)) > 0) {
50862 -                       /* n is the number of events */
50863 -                       int revents;
50864 -                       int fd_ndx;
50865 -#if 0
50866 -                       if (n > 0) {
50867 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
50868 -                                               "polls:", n);
50869 -                       }
50870 -#endif                 
50871 -                       fd_ndx = -1;
50872 -                       do {
50873 -                               fdevent_handler handler;
50874 -                               void *context;
50875 -                               handler_t r;
50876 -                               
50877 -                               fd_ndx  = fdevent_event_next_fdndx (srv->ev, fd_ndx);
50878 -                               revents = fdevent_event_get_revent (srv->ev, fd_ndx);
50879 -                               fd      = fdevent_event_get_fd     (srv->ev, fd_ndx);
50880 -                               handler = fdevent_get_handler(srv->ev, fd);
50881 -                               context = fdevent_get_context(srv->ev, fd);
50882 -                               
50883 -                               /* connection_handle_fdevent needs a joblist_append */
50884 -#if 0
50885 -                               log_error_write(srv, __FILE__, __LINE__, "sdd", 
50886 -                                               "event for", fd, revents);
50887 -#endif                         
50888 -                               switch (r = (*handler)(srv, context, revents)) {
50889 -                               case HANDLER_FINISHED:
50890 -                               case HANDLER_GO_ON:
50891 -                               case HANDLER_WAIT_FOR_EVENT:
50892 -                               case HANDLER_WAIT_FOR_FD:
50893 -                                       break;
50894 -                               case HANDLER_ERROR:
50895 -                                       /* should never happen */
50896 -                                       SEGFAULT();
50897 -                                       break;
50898 -                               default:
50899 -                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
50900 -                                       break;
50901 -                               }
50902 -                       } while (--n > 0);
50903 -               } else if (n < 0 && errno != EINTR) {
50904 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
50905 -                                       "fdevent_poll failed:", 
50906 -                                       strerror(errno));
50907 -               }
50908 -               
50909 -               for (ndx = 0; ndx < srv->joblist->used; ndx++) {
50910 -                       connection *con = srv->joblist->ptr[ndx];
50911 -                       handler_t r;
50912 -                       
50913 -                       connection_state_machine(srv, con);
50914 -                       
50915 -                       switch(r = plugins_call_handle_joblist(srv, con)) {
50916 -                       case HANDLER_FINISHED:
50917 -                       case HANDLER_GO_ON:
50918 -                               break;
50919 -                       default:
50920 -                               log_error_write(srv, __FILE__, __LINE__, "d", r);
50921 -                               break;
50922 -                       }
50923 -                       
50924 -                       con->in_joblist = 0;
50925 -               }
50926 -               
50927 -               srv->joblist->used = 0;
50928 -       }
50929 -       
50930 -       if (srv->srvconf.pid_file->used &&
50931 +       if (0 == graceful_restart &&
50932 +           srv->srvconf.pid_file->used &&
50933             srv->srvconf.changeroot->used == 0) {
50934                 if (0 != unlink(srv->srvconf.pid_file->ptr)) {
50935                         if (errno != EACCES && errno != EPERM) {
50936 -                               log_error_write(srv, __FILE__, __LINE__, "sbds", 
50937 -                                               "unlink failed for:", 
50938 +                               log_error_write(srv, __FILE__, __LINE__, "sbds",
50939 +                                               "unlink failed for:",
50940                                                 srv->srvconf.pid_file,
50941                                                 errno,
50942                                                 strerror(errno));
50943                         }
50944                 }
50945         }
50946 -       
50947 +
50948         /* clean-up */
50949 -       log_error_close(srv);
50950         network_close(srv);
50951         connections_free(srv);
50952         plugins_free(srv);
50953         server_free(srv);
50954 -       
50955 +       log_free();
50956 +
50957         return 0;
50958  }
50959 --- ../lighttpd-1.4.11/src/settings.h   2005-08-11 01:26:41.000000000 +0300
50960 +++ lighttpd-1.4.12/src/settings.h      2006-07-16 00:26:04.000000000 +0300
50961 @@ -9,24 +9,24 @@
50962  /**
50963   * max size of a buffer which will just be reset
50964   * to ->used = 0 instead of really freeing the buffer
50965 - * 
50966 + *
50967   * 64kB (no real reason, just a guess)
50968   */
50969  #define BUFFER_MAX_REUSE_SIZE  (4 * 1024)
50970  
50971  /**
50972   * max size of the HTTP request header
50973 - * 
50974 + *
50975   * 32k should be enough for everything (just a guess)
50976 - * 
50977 + *
50978   */
50979  #define MAX_HTTP_REQUEST_HEADER  (32 * 1024)
50980  
50981 -typedef enum { HANDLER_UNSET, 
50982 -               HANDLER_GO_ON, 
50983 +typedef enum { HANDLER_UNSET,
50984 +               HANDLER_GO_ON,
50985                 HANDLER_FINISHED,
50986 -               HANDLER_COMEBACK, 
50987 -               HANDLER_WAIT_FOR_EVENT, 
50988 +               HANDLER_COMEBACK,
50989 +               HANDLER_WAIT_FOR_EVENT,
50990                 HANDLER_ERROR,
50991                 HANDLER_WAIT_FOR_FD
50992  } handler_t;
50993 --- ../lighttpd-1.4.11/src/spawn-fcgi.c 2006-03-07 14:18:10.000000000 +0200
50994 +++ lighttpd-1.4.12/src/spawn-fcgi.c    2006-07-16 00:26:04.000000000 +0300
50995 @@ -1,19 +1,16 @@
50996  #include <sys/types.h>
50997 -#include <sys/time.h>
50998  #include <sys/stat.h>
50999  
51000  #include <stdlib.h>
51001  #include <string.h>
51002  #include <errno.h>
51003  #include <stdio.h>
51004 -#include <unistd.h>
51005  #include <fcntl.h>
51006 -
51007 +#include <time.h>
51008  #ifdef HAVE_CONFIG_H
51009  #include "config.h"
51010  #endif
51011  
51012 -
51013  #ifdef HAVE_PWD_H
51014  #include <grp.h>
51015  #include <pwd.h>
51016 @@ -30,6 +27,7 @@
51017  #endif
51018  
51019  #include "sys-socket.h"
51020 +#include "sys-files.h"
51021  
51022  #ifdef HAVE_SYS_WAIT_H
51023  #include <sys/wait.h>
51024 @@ -45,28 +43,28 @@
51025         int fcgi_fd;
51026         int socket_type, status;
51027         struct timeval tv = { 0, 100 * 1000 };
51028 -       
51029 +
51030         struct sockaddr_un fcgi_addr_un;
51031         struct sockaddr_in fcgi_addr_in;
51032         struct sockaddr *fcgi_addr;
51033 -       
51034 +
51035         socklen_t servlen;
51036 -       
51037 +
51038         if (child_count < 2) {
51039                 child_count = 5;
51040         }
51041 -       
51042 +
51043         if (child_count > 256) {
51044                 child_count = 256;
51045         }
51046 -       
51047 -       
51048 +
51049 +
51050         if (unixsocket) {
51051                 memset(&fcgi_addr, 0, sizeof(fcgi_addr));
51052 -               
51053 +
51054                 fcgi_addr_un.sun_family = AF_UNIX;
51055                 strcpy(fcgi_addr_un.sun_path, unixsocket);
51056 -               
51057 +
51058  #ifdef SUN_LEN
51059                 servlen = SUN_LEN(&fcgi_addr_un);
51060  #else
51061 @@ -84,50 +82,50 @@
51062                  }
51063                 fcgi_addr_in.sin_port = htons(port);
51064                 servlen = sizeof(fcgi_addr_in);
51065 -               
51066 +
51067                 socket_type = AF_INET;
51068                 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
51069         }
51070 -       
51071 +
51072         if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
51073 -               fprintf(stderr, "%s.%d\n", 
51074 +               fprintf(stderr, "%s.%d\n",
51075                         __FILE__, __LINE__);
51076                 return -1;
51077         }
51078 -       
51079 +
51080         if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
51081                 /* server is not up, spawn in  */
51082                 pid_t child;
51083                 int val;
51084 -               
51085 +
51086                 if (unixsocket) unlink(unixsocket);
51087 -               
51088 +
51089                 close(fcgi_fd);
51090 -               
51091 +
51092                 /* reopen socket */
51093                 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
51094 -                       fprintf(stderr, "%s.%d\n", 
51095 +                       fprintf(stderr, "%s.%d\n",
51096                                 __FILE__, __LINE__);
51097                         return -1;
51098                 }
51099  
51100                 val = 1;
51101                 if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
51102 -                       fprintf(stderr, "%s.%d\n", 
51103 +                       fprintf(stderr, "%s.%d\n",
51104                                 __FILE__, __LINE__);
51105                         return -1;
51106                 }
51107  
51108                 /* create socket */
51109                 if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
51110 -                       fprintf(stderr, "%s.%d: bind failed: %s\n", 
51111 +                       fprintf(stderr, "%s.%d: bind failed: %s\n",
51112                                 __FILE__, __LINE__,
51113                                 strerror(errno));
51114                         return -1;
51115                 }
51116 -               
51117 +
51118                 if (-1 == listen(fcgi_fd, 1024)) {
51119 -                       fprintf(stderr, "%s.%d: fd = -1\n", 
51120 +                       fprintf(stderr, "%s.%d: fd = -1\n",
51121                                 __FILE__, __LINE__);
51122                         return -1;
51123                 }
51124 @@ -137,42 +135,45 @@
51125                 } else {
51126                         child = 0;
51127                 }
51128 -               
51129 +
51130                 switch (child) {
51131                 case 0: {
51132                         char cgi_childs[64];
51133                         char *b;
51134 -                       
51135 +
51136                         int i = 0;
51137 -                       
51138 +
51139 +                       /* loose control terminal */
51140 +                       setsid();
51141 +
51142                         /* is save as we limit to 256 childs */
51143                         sprintf(cgi_childs, "PHP_FCGI_CHILDREN=%d", child_count);
51144 -                       
51145 +
51146                         if(fcgi_fd != FCGI_LISTENSOCK_FILENO) {
51147                                 close(FCGI_LISTENSOCK_FILENO);
51148                                 dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
51149                                 close(fcgi_fd);
51150                         }
51151 -                       
51152 +
51153                         /* we don't need the client socket */
51154                         for (i = 3; i < 256; i++) {
51155                                 close(i);
51156                         }
51157 -                       
51158 +
51159                         /* create environment */
51160 -                       
51161 +
51162                         putenv(cgi_childs);
51163 -                       
51164 +
51165                         /* fork and replace shell */
51166                         b = malloc(strlen("exec ") + strlen(appPath) + 1);
51167                         strcpy(b, "exec ");
51168                         strcat(b, appPath);
51169 -                       
51170 +
51171                         /* exec the cgi */
51172                         execl("/bin/sh", "sh", "-c", b, NULL);
51173 -                       
51174 +
51175                         exit(errno);
51176 -                       
51177 +
51178                         break;
51179                 }
51180                 case -1:
51181 @@ -180,47 +181,47 @@
51182                         break;
51183                 default:
51184                         /* father */
51185 -                       
51186 +
51187                         /* wait */
51188                         select(0, NULL, NULL, NULL, &tv);
51189 -                       
51190 +
51191                         switch (waitpid(child, &status, WNOHANG)) {
51192                         case 0:
51193 -                               fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n", 
51194 +                               fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n",
51195                                         __FILE__, __LINE__,
51196                                         child);
51197 -                               
51198 +
51199                                 /* write pid file */
51200                                 if (pid_fd != -1) {
51201                                         /* assume a 32bit pid_t */
51202                                         char pidbuf[12];
51203 -                                       
51204 +
51205                                         snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child);
51206 -                                       
51207 +
51208                                         write(pid_fd, pidbuf, strlen(pidbuf));
51209                                         close(pid_fd);
51210                                         pid_fd = -1;
51211                                 }
51212 -                               
51213 +
51214                                 break;
51215                         case -1:
51216                                 break;
51217                         default:
51218                                 if (WIFEXITED(status)) {
51219 -                                       fprintf(stderr, "%s.%d: child exited with: %d, %s\n", 
51220 +                                       fprintf(stderr, "%s.%d: child exited with: %d, %s\n",
51221                                                 __FILE__, __LINE__,
51222                                                 WEXITSTATUS(status), strerror(WEXITSTATUS(status)));
51223                                 } else if (WIFSIGNALED(status)) {
51224 -                                       fprintf(stderr, "%s.%d: child signaled: %d\n", 
51225 +                                       fprintf(stderr, "%s.%d: child signaled: %d\n",
51226                                                 __FILE__, __LINE__,
51227                                                 WTERMSIG(status));
51228                                 } else {
51229 -                                       fprintf(stderr, "%s.%d: child died somehow: %d\n", 
51230 +                                       fprintf(stderr, "%s.%d: child died somehow: %d\n",
51231                                                 __FILE__, __LINE__,
51232                                                 status);
51233                                 }
51234                         }
51235 -                               
51236 +
51237                         break;
51238                 }
51239         } else {
51240 @@ -228,16 +229,16 @@
51241                         __FILE__, __LINE__);
51242                 return -1;
51243         }
51244 -       
51245 +
51246         close(fcgi_fd);
51247 -       
51248 +
51249         return 0;
51250  }
51251  
51252  
51253  void show_version () {
51254         char *b = "spawn-fcgi" "-" PACKAGE_VERSION \
51255 -" - spawns fastcgi processes\n" 
51256 +" - spawns fastcgi processes\n"
51257  ;
51258         write(1, b, strlen(b));
51259  }
51260 @@ -265,7 +266,7 @@
51261  
51262  
51263  int main(int argc, char **argv) {
51264 -       char *fcgi_app = NULL, *changeroot = NULL, *username = NULL, 
51265 +       char *fcgi_app = NULL, *changeroot = NULL, *username = NULL,
51266                 *groupname = NULL, *unixsocket = NULL, *pid_file = NULL,
51267                  *addr = NULL;
51268         unsigned short port = 0;
51269 @@ -273,9 +274,9 @@
51270         int i_am_root, o;
51271         int pid_fd = -1;
51272         int nofork = 0;
51273 -       
51274 +
51275         i_am_root = (getuid() == 0);
51276 -       
51277 +
51278         while(-1 != (o = getopt(argc, argv, "c:f:g:hna:p:u:vC:s:P:"))) {
51279                 switch(o) {
51280                 case 'f': fcgi_app = optarg; break;
51281 @@ -290,137 +291,137 @@
51282                 case 'P': pid_file = optarg; /* PID file */ break;
51283                 case 'v': show_version(); return 0;
51284                 case 'h': show_help(); return 0;
51285 -               default: 
51286 +               default:
51287                         show_help();
51288                         return -1;
51289                 }
51290         }
51291 -       
51292 +
51293         if (fcgi_app == NULL || (port == 0 && unixsocket == NULL)) {
51294                 show_help();
51295                 return -1;
51296         }
51297 -           
51298 +
51299         if (unixsocket && port) {
51300 -               fprintf(stderr, "%s.%d: %s\n", 
51301 +               fprintf(stderr, "%s.%d: %s\n",
51302                         __FILE__, __LINE__,
51303                         "either a unix domain socket or a tcp-port, but not both\n");
51304 -               
51305 +
51306                 return -1;
51307         }
51308 -       
51309 +
51310         if (unixsocket && strlen(unixsocket) > UNIX_PATH_MAX - 1) {
51311 -               fprintf(stderr, "%s.%d: %s\n", 
51312 +               fprintf(stderr, "%s.%d: %s\n",
51313                         __FILE__, __LINE__,
51314                         "path of the unix socket is too long\n");
51315 -               
51316 +
51317                 return -1;
51318         }
51319  
51320         /* UID handling */
51321         if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
51322                 /* we are setuid-root */
51323 -               
51324 -               fprintf(stderr, "%s.%d: %s\n", 
51325 +
51326 +               fprintf(stderr, "%s.%d: %s\n",
51327                         __FILE__, __LINE__,
51328                         "Are you nuts ? Don't apply a SUID bit to this binary\n");
51329 -               
51330 +
51331                 return -1;
51332         }
51333 -       
51334 -       if (pid_file && 
51335 +
51336 +       if (pid_file &&
51337             (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)))) {
51338                 struct stat st;
51339                 if (errno != EEXIST) {
51340 -                       fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n", 
51341 +                       fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
51342                                 __FILE__, __LINE__,
51343                                 pid_file, strerror(errno));
51344 -                       
51345 +
51346                         return -1;
51347                 }
51348 -               
51349 +
51350                 /* ok, file exists */
51351 -               
51352 +
51353                 if (0 != stat(pid_file, &st)) {
51354 -                       fprintf(stderr, "%s.%d: stating pid-file '%s' failed: %s\n", 
51355 +                       fprintf(stderr, "%s.%d: stating pid-file '%s' failed: %s\n",
51356                                 __FILE__, __LINE__,
51357                                 pid_file, strerror(errno));
51358 -                       
51359 +
51360                         return -1;
51361                 }
51362 -               
51363 +
51364                 /* is it a regular file ? */
51365 -               
51366 +
51367                 if (!S_ISREG(st.st_mode)) {
51368 -                       fprintf(stderr, "%s.%d: pid-file exists and isn't regular file: '%s'\n", 
51369 +                       fprintf(stderr, "%s.%d: pid-file exists and isn't regular file: '%s'\n",
51370                                 __FILE__, __LINE__,
51371                                 pid_file);
51372 -                       
51373 +
51374                         return -1;
51375                 }
51376 -               
51377 +
51378                 if (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
51379 -                       fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n", 
51380 +                       fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
51381                                 __FILE__, __LINE__,
51382                                 pid_file, strerror(errno));
51383 -                       
51384 +
51385                         return -1;
51386                 }
51387         }
51388 -       
51389 +
51390         if (i_am_root) {
51391                 struct group *grp = NULL;
51392                 struct passwd *pwd = NULL;
51393 -               
51394 +
51395                 /* set user and group */
51396 -               
51397 +
51398                 if (username) {
51399                         if (NULL == (pwd = getpwnam(username))) {
51400 -                               fprintf(stderr, "%s.%d: %s, %s\n", 
51401 +                               fprintf(stderr, "%s.%d: %s, %s\n",
51402                                         __FILE__, __LINE__,
51403                                         "can't find username", username);
51404                                 return -1;
51405                         }
51406 -                       
51407 +
51408                         if (pwd->pw_uid == 0) {
51409 -                               fprintf(stderr, "%s.%d: %s\n", 
51410 +                               fprintf(stderr, "%s.%d: %s\n",
51411                                         __FILE__, __LINE__,
51412                                         "I will not set uid to 0\n");
51413                                 return -1;
51414                         }
51415                 }
51416 -               
51417 +
51418                 if (groupname) {
51419                         if (NULL == (grp = getgrnam(groupname))) {
51420 -                               fprintf(stderr, "%s.%d: %s %s\n", 
51421 +                               fprintf(stderr, "%s.%d: %s %s\n",
51422                                         __FILE__, __LINE__,
51423 -                                       "can't find groupname", 
51424 +                                       "can't find groupname",
51425                                         groupname);
51426                                 return -1;
51427                         }
51428                         if (grp->gr_gid == 0) {
51429 -                               fprintf(stderr, "%s.%d: %s\n", 
51430 +                               fprintf(stderr, "%s.%d: %s\n",
51431                                         __FILE__, __LINE__,
51432                                         "I will not set gid to 0\n");
51433                                 return -1;
51434                         }
51435                 }
51436 -               
51437 +
51438                 if (changeroot) {
51439                         if (-1 == chroot(changeroot)) {
51440 -                               fprintf(stderr, "%s.%d: %s %s\n", 
51441 +                               fprintf(stderr, "%s.%d: %s %s\n",
51442                                         __FILE__, __LINE__,
51443                                         "chroot failed: ", strerror(errno));
51444                                 return -1;
51445                         }
51446                         if (-1 == chdir("/")) {
51447 -                               fprintf(stderr, "%s.%d: %s %s\n", 
51448 +                               fprintf(stderr, "%s.%d: %s %s\n",
51449                                         __FILE__, __LINE__,
51450                                         "chdir failed: ", strerror(errno));
51451                                 return -1;
51452                         }
51453                 }
51454 -               
51455 +
51456                 /* drop root privs */
51457                 if (groupname) {
51458                         setgid(grp->gr_gid);
51459 @@ -428,7 +429,7 @@
51460                 }
51461                 if (username) setuid(pwd->pw_uid);
51462         }
51463 -       
51464 +
51465         return fcgi_spawn_connection(fcgi_app, addr, port, unixsocket, child_count, pid_fd, nofork);
51466  }
51467  #else
51468 --- ../lighttpd-1.4.11/src/splaytree.c  2005-09-12 21:51:28.000000000 +0300
51469 +++ lighttpd-1.4.12/src/splaytree.c     2006-07-16 00:26:03.000000000 +0300
51470 @@ -56,19 +56,19 @@
51471  
51472  #define node_size splaytree_size
51473  
51474 -/* Splay using the key i (which may or may not be in the tree.) 
51475 - * The starting root is t, and the tree used is defined by rat 
51476 +/* Splay using the key i (which may or may not be in the tree.)
51477 + * The starting root is t, and the tree used is defined by rat
51478   * size fields are maintained */
51479  splay_tree * splaytree_splay (splay_tree *t, int i) {
51480      splay_tree N, *l, *r, *y;
51481      int comp, root_size, l_size, r_size;
51482 -    
51483 +
51484      if (t == NULL) return t;
51485      N.left = N.right = NULL;
51486      l = r = &N;
51487      root_size = node_size(t);
51488      l_size = r_size = 0;
51489
51490 +
51491      for (;;) {
51492          comp = compare(i, t->key);
51493          if (comp < 0) {
51494 @@ -120,7 +120,7 @@
51495          y->size = r_size;
51496          r_size -= 1+node_size(y->right);
51497      }
51498
51499 +
51500      l->right = t->left;                                /* assemble */
51501      r->left = t->right;
51502      t->left = N.right;
51503 --- ../lighttpd-1.4.11/src/splaytree.h  2005-09-12 21:51:13.000000000 +0300
51504 +++ lighttpd-1.4.12/src/splaytree.h     2006-07-16 00:26:03.000000000 +0300
51505 @@ -19,6 +19,6 @@
51506  /* This macro returns the size of a node.  Unlike "x->size",     */
51507  /* it works even if x=NULL.  The test could be avoided by using  */
51508  /* a special version of NULL which was a real node with size 0.  */
51509
51510 +
51511  
51512  #endif
51513 --- ../lighttpd-1.4.11/src/stat_cache.c 2005-11-22 15:23:51.000000000 +0200
51514 +++ lighttpd-1.4.12/src/stat_cache.c    2006-07-18 13:03:40.000000000 +0300
51515 @@ -6,7 +6,6 @@
51516  #include <stdlib.h>
51517  #include <string.h>
51518  #include <errno.h>
51519 -#include <unistd.h>
51520  #include <stdio.h>
51521  #include <fcntl.h>
51522  #include <assert.h>
51523 @@ -25,19 +24,8 @@
51524  #endif
51525  
51526  #include "sys-mmap.h"
51527 -
51528 -/* NetBSD 1.3.x needs it */
51529 -#ifndef MAP_FAILED
51530 -# define MAP_FAILED -1
51531 -#endif
51532 -
51533 -#ifndef O_LARGEFILE
51534 -# define O_LARGEFILE 0
51535 -#endif
51536 -
51537 -#ifndef HAVE_LSTAT
51538 -#define lstat stat
51539 -#endif
51540 +#include "sys-files.h"
51541 +#include "sys-strings.h"
51542  
51543  #if 0
51544  /* enables debug code for testing if all nodes in the stat-cache as accessable */
51545 @@ -52,8 +40,8 @@
51546   *
51547   * if we get a change-event from FAM, we increment the version in the FAM->dir mapping
51548   *
51549 - * if the stat()-cache is queried we check if the version id for the directory is the 
51550 - * same and return immediatly. 
51551 + * if the stat()-cache is queried we check if the version id for the directory is the
51552 + * same and return immediatly.
51553   *
51554   *
51555   * What we need:
51556 @@ -62,17 +50,17 @@
51557   * - for each FAMRequest we have to find the version in the directory cache (index as userdata)
51558   *
51559   * stat <<-> directory <-> FAMRequest
51560 - * 
51561 - * if file is deleted, directory is dirty, file is rechecked ... 
51562 + *
51563 + * if file is deleted, directory is dirty, file is rechecked ...
51564   * if directory is deleted, directory mapping is removed
51565 - *  
51566 + *
51567   * */
51568  
51569  #ifdef HAVE_FAM_H
51570  typedef struct {
51571         FAMRequest *req;
51572         FAMConnection *fc;
51573 -       
51574 +
51575         buffer *name;
51576  
51577         int version;
51578 @@ -83,16 +71,16 @@
51579   * - we need a hash
51580   * - the hash-key is used as sorting criteria for a tree
51581   * - a splay-tree is used as we can use the caching effect of it
51582 - */ 
51583 + */
51584  
51585  /* we want to cleanup the stat-cache every few seconds, let's say 10
51586   *
51587   * - remove entries which are outdated since 30s
51588   * - remove entries which are fresh but havn't been used since 60s
51589   * - if we don't have a stat-cache entry for a directory, release it from the monitor
51590 - */ 
51591 + */
51592  
51593 -#ifdef DEBUG_STAT_CACHE        
51594 +#ifdef DEBUG_STAT_CACHE
51595  typedef struct {
51596         int *ptr;
51597  
51598 @@ -105,15 +93,16 @@
51599  
51600  stat_cache *stat_cache_init(void) {
51601         stat_cache *fc = NULL;
51602 -       
51603 +
51604         fc = calloc(1, sizeof(*fc));
51605 -       
51606 +
51607         fc->dir_name = buffer_init();
51608  #ifdef HAVE_FAM_H
51609         fc->fam = calloc(1, sizeof(*fc->fam));
51610 +       fc->sock = iosocket_init();
51611  #endif
51612  
51613 -#ifdef DEBUG_STAT_CACHE        
51614 +#ifdef DEBUG_STAT_CACHE
51615         ctrl.size = 0;
51616  #endif
51617  
51618 @@ -122,24 +111,24 @@
51619  
51620  static stat_cache_entry * stat_cache_entry_init(void) {
51621         stat_cache_entry *sce = NULL;
51622 -       
51623 +
51624         sce = calloc(1, sizeof(*sce));
51625 -       
51626 +
51627         sce->name = buffer_init();
51628         sce->etag = buffer_init();
51629         sce->content_type = buffer_init();
51630 -       
51631 +
51632         return sce;
51633  }
51634  
51635  static void stat_cache_entry_free(void *data) {
51636         stat_cache_entry *sce = data;
51637         if (!sce) return;
51638 -       
51639 +
51640         buffer_free(sce->etag);
51641         buffer_free(sce->name);
51642         buffer_free(sce->content_type);
51643 -       
51644 +
51645         free(sce);
51646  }
51647  
51648 @@ -148,22 +137,22 @@
51649         fam_dir_entry *fam_dir = NULL;
51650  
51651         fam_dir = calloc(1, sizeof(*fam_dir));
51652 -       
51653 +
51654         fam_dir->name = buffer_init();
51655 -       
51656 +
51657         return fam_dir;
51658  }
51659  
51660  static void fam_dir_entry_free(void *data) {
51661         fam_dir_entry *fam_dir = data;
51662 -       
51663 +
51664         if (!fam_dir) return;
51665 -       
51666 +
51667         FAMCancelMonitor(fam_dir->fc, fam_dir->req);
51668 -       
51669 +
51670         buffer_free(fam_dir->name);
51671         free(fam_dir->req);
51672 -       
51673 +
51674         free(fam_dir);
51675  }
51676  #endif
51677 @@ -174,7 +163,7 @@
51678                 splay_tree *node = sc->files;
51679  
51680                 osize = sc->files->size;
51681 -                       
51682 +
51683                 stat_cache_entry_free(node->data);
51684                 sc->files = splaytree_delete(sc->files, node->key);
51685  
51686 @@ -187,12 +176,12 @@
51687         while (sc->dirs) {
51688                 int osize;
51689                 splay_tree *node = sc->dirs;
51690 -               
51691 +
51692                 osize = sc->dirs->size;
51693  
51694                 fam_dir_entry_free(node->data);
51695                 sc->dirs = splaytree_delete(sc->dirs, node->key);
51696 -               
51697 +
51698                 if (osize == 1) {
51699                         assert(NULL == sc->dirs);
51700                 } else {
51701 @@ -202,6 +191,7 @@
51702  
51703         if (sc->fam) {
51704                 FAMClose(sc->fam);
51705 +               iosocket_free(sc->sock);
51706                 free(sc->fam);
51707         }
51708  #endif
51709 @@ -212,7 +202,7 @@
51710  static int stat_cache_attr_get(buffer *buf, char *name) {
51711         int attrlen;
51712         int ret;
51713 -       
51714 +
51715         attrlen = 1024;
51716         buffer_prepare_copy(buf, attrlen);
51717         attrlen--;
51718 @@ -251,15 +241,15 @@
51719             sc->fam) {
51720  
51721                 events = FAMPending(sc->fam);
51722 -       
51723 +
51724                 for (i = 0; i < events; i++) {
51725                         FAMEvent fe;
51726                         fam_dir_entry *fam_dir;
51727                         splay_tree *node;
51728                         int ndx;
51729 -               
51730 +
51731                         FAMNextEvent(sc->fam, &fe);
51732 -       
51733 +
51734                         /* handle event */
51735  
51736                         switch(fe.code) {
51737 @@ -280,7 +270,7 @@
51738  
51739                                 sc->dirs = splaytree_splay(sc->dirs, ndx);
51740                                 node = sc->dirs;
51741 -                       
51742 +
51743                                 if (node && (node->key == ndx)) {
51744                                         int osize = splaytree_size(sc->dirs);
51745  
51746 @@ -298,17 +288,15 @@
51747  
51748         if (revent & FDEVENT_HUP) {
51749                 /* fam closed the connection */
51750 -               srv->stat_cache->fam_fcce_ndx = -1;
51751 -
51752 -               fdevent_event_del(srv->ev, &(sc->fam_fcce_ndx), FAMCONNECTION_GETFD(sc->fam));
51753 -               fdevent_unregister(srv->ev, FAMCONNECTION_GETFD(sc->fam));
51754 +               fdevent_event_del(srv->ev, sc->sock);
51755 +               fdevent_unregister(srv->ev, sc->sock);
51756  
51757                 FAMClose(sc->fam);
51758                 free(sc->fam);
51759  
51760                 sc->fam = NULL;
51761         }
51762 -       
51763 +
51764         return HANDLER_GO_ON;
51765  }
51766  
51767 @@ -332,7 +320,7 @@
51768   *
51769   *
51770   *
51771 - * returns: 
51772 + * returns:
51773   *  - HANDLER_FINISHED on cache-miss (don't forget to reopen the file)
51774   *  - HANDLER_ERROR on stat() failed -> see errno for problem
51775   */
51776 @@ -348,16 +336,16 @@
51777         struct stat st;
51778         size_t k;
51779         int fd;
51780 -#ifdef DEBUG_STAT_CACHE        
51781 +#ifdef DEBUG_STAT_CACHE
51782         size_t i;
51783  #endif
51784  
51785         int file_ndx;
51786         splay_tree *file_node = NULL;
51787  
51788 -       *ret_sce = NULL; 
51789 +       *ret_sce = NULL;
51790  
51791 -       /* 
51792 +       /*
51793          * check if the directory for this file has changed
51794          */
51795  
51796 @@ -366,23 +354,23 @@
51797         file_ndx = hashme(name);
51798         sc->files = splaytree_splay(sc->files, file_ndx);
51799  
51800 -#ifdef DEBUG_STAT_CACHE        
51801 +#ifdef DEBUG_STAT_CACHE
51802         for (i = 0; i < ctrl.used; i++) {
51803                 if (ctrl.ptr[i] == file_ndx) break;
51804         }
51805  #endif
51806  
51807         if (sc->files && (sc->files->key == file_ndx)) {
51808 -#ifdef DEBUG_STAT_CACHE        
51809 +#ifdef DEBUG_STAT_CACHE
51810                 /* it was in the cache */
51811                 assert(i < ctrl.used);
51812  #endif
51813 -               
51814 -               /* we have seen this file already and 
51815 +
51816 +               /* we have seen this file already and
51817                  * don't stat() it again in the same second */
51818  
51819                 file_node = sc->files;
51820 -               
51821 +
51822                 sce = file_node->data;
51823  
51824                 /* check if the name is the same, we might have a collision */
51825 @@ -390,7 +378,7 @@
51826                 if (buffer_is_equal(name, sce->name)) {
51827                         if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_SIMPLE) {
51828                                 if (sce->stat_ts == srv->cur_ts) {
51829 -                                       *ret_sce = sce; 
51830 +                                       *ret_sce = sce;
51831                                         return HANDLER_GO_ON;
51832                                 }
51833                         }
51834 @@ -400,15 +388,15 @@
51835                          * file_node is used by the FAM check below to see if we know this file
51836                          * and if we can save a stat().
51837                          *
51838 -                        * BUT, the sce is not reset here as the entry into the cache is ok, we 
51839 +                        * BUT, the sce is not reset here as the entry into the cache is ok, we
51840                          * it is just not pointing to our requested file.
51841 -                        * 
51842 +                        *
51843                          *  */
51844  
51845                         file_node = NULL;
51846                 }
51847         } else {
51848 -#ifdef DEBUG_STAT_CACHE        
51849 +#ifdef DEBUG_STAT_CACHE
51850                 if (i != ctrl.used) {
51851                         fprintf(stderr, "%s.%d: %08x was already inserted but not found in cache, %s\n", __FILE__, __LINE__, file_ndx, name->ptr);
51852                 }
51853 @@ -424,23 +412,23 @@
51854                 }
51855  
51856                 dir_ndx = hashme(sc->dir_name);
51857 -               
51858 +
51859                 sc->dirs = splaytree_splay(sc->dirs, dir_ndx);
51860 -               
51861 +
51862                 if (sc->dirs && (sc->dirs->key == dir_ndx)) {
51863                         dir_node = sc->dirs;
51864                 }
51865 -               
51866 +
51867                 if (dir_node && file_node) {
51868                         /* we found a file */
51869 -                       
51870 +
51871                         sce = file_node->data;
51872                         fam_dir = dir_node->data;
51873 -                       
51874 +
51875                         if (fam_dir->version == sce->dir_version) {
51876                                 /* the stat()-cache entry is still ok */
51877 -                               
51878 -                               *ret_sce = sce; 
51879 +
51880 +                               *ret_sce = sce;
51881                                 return HANDLER_GO_ON;
51882                         }
51883                 }
51884 @@ -448,7 +436,7 @@
51885  #endif
51886  
51887         /*
51888 -        * *lol* 
51889 +        * *lol*
51890          * - open() + fstat() on a named-pipe results in a (intended) hang.
51891          * - stat() if regualar file + open() to see if we can read from it is better
51892          *
51893 @@ -469,16 +457,16 @@
51894  
51895         if (NULL == sce) {
51896                 int osize = 0;
51897 -                      
51898 +
51899                 if (sc->files) {
51900                         osize = sc->files->size;
51901                 }
51902  
51903                 sce = stat_cache_entry_init();
51904                 buffer_copy_string_buffer(sce->name, name);
51905 -               
51906 -               sc->files = splaytree_insert(sc->files, file_ndx, sce); 
51907 -#ifdef DEBUG_STAT_CACHE        
51908 +
51909 +               sc->files = splaytree_insert(sc->files, file_ndx, sce);
51910 +#ifdef DEBUG_STAT_CACHE
51911                 if (ctrl.size == 0) {
51912                         ctrl.size = 16;
51913                         ctrl.used = 0;
51914 @@ -499,29 +487,29 @@
51915         sce->st = st;
51916         sce->stat_ts = srv->cur_ts;
51917  
51918 -       /* catch the obvious symlinks 
51919 +       /* catch the obvious symlinks
51920          *
51921          * this is not a secure check as we still have a race-condition between
51922 -        * the stat() and the open. We can only solve this by 
51923 +        * the stat() and the open. We can only solve this by
51924          * 1. open() the file
51925          * 2. fstat() the fd
51926          *
51927          * and keeping the file open for the rest of the time. But this can
51928          * only be done at network level.
51929 -        * 
51930 +        *
51931          * */
51932         if (S_ISLNK(st.st_mode) && !con->conf.follow_symlink) {
51933                 return HANDLER_ERROR;
51934         }
51935  
51936 -       if (S_ISREG(st.st_mode)) {      
51937 +       if (S_ISREG(st.st_mode)) {
51938                 /* determine mimetype */
51939                 buffer_reset(sce->content_type);
51940 -               
51941 +
51942                 for (k = 0; k < con->conf.mimetypes->used; k++) {
51943                         data_string *ds = (data_string *)con->conf.mimetypes->data[k];
51944                         buffer *type = ds->key;
51945 -               
51946 +
51947                         if (type->used == 0) continue;
51948  
51949                         /* check if the right side is the same */
51950 @@ -538,8 +526,10 @@
51951                         stat_cache_attr_get(sce->content_type, name->ptr);
51952                 }
51953  #endif
51954 +       } else if (S_ISDIR(st.st_mode)) {
51955 +               etag_create(sce->etag, &(sce->st));
51956         }
51957 -               
51958 +
51959  #ifdef HAVE_FAM_H
51960         if (sc->fam &&
51961             (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM)) {
51962 @@ -549,19 +539,19 @@
51963                         fam_dir->fc = sc->fam;
51964  
51965                         buffer_copy_string_buffer(fam_dir->name, sc->dir_name);
51966 -                       
51967 +
51968                         fam_dir->version = 1;
51969 -                       
51970 +
51971                         fam_dir->req = calloc(1, sizeof(FAMRequest));
51972 -                       
51973 -                       if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr, 
51974 +
51975 +                       if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr,
51976                                                      fam_dir->req, fam_dir)) {
51977 -                               
51978 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
51979 -                                               "monitoring dir failed:", 
51980 -                                               fam_dir->name, 
51981 +
51982 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
51983 +                                               "monitoring dir failed:",
51984 +                                               fam_dir->name,
51985                                                 FamErrlist[FAMErrno]);
51986 -                               
51987 +
51988                                 fam_dir_entry_free(fam_dir);
51989                         } else {
51990                                 int osize = 0;
51991 @@ -570,7 +560,7 @@
51992                                         osize = sc->dirs->size;
51993                                 }
51994  
51995 -                               sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir); 
51996 +                               sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir);
51997                                 assert(sc->dirs);
51998                                 assert(sc->dirs->data == fam_dir);
51999                                 assert(osize == (sc->dirs->size - 1));
52000 @@ -578,9 +568,9 @@
52001                 } else {
52002                         fam_dir = dir_node->data;
52003                 }
52004 -               
52005 +
52006                 /* bind the fam_fc to the stat() cache entry */
52007 -                       
52008 +
52009                 if (fam_dir) {
52010                         sce->dir_version = fam_dir->version;
52011                         sce->dir_ndx     = dir_ndx;
52012 @@ -594,11 +584,11 @@
52013  }
52014  
52015  /**
52016 - * remove stat() from cache which havn't been stat()ed for 
52017 + * remove stat() from cache which havn't been stat()ed for
52018   * more than 10 seconds
52019 - * 
52020   *
52021 - * walk though the stat-cache, collect the ids which are too old 
52022 + *
52023 + * walk though the stat-cache, collect the ids which are too old
52024   * and remove them in a second loop
52025   */
52026  
52027 @@ -639,9 +629,9 @@
52028                 sc->files = splaytree_splay(sc->files, ndx);
52029  
52030                 node = sc->files;
52031 -               
52032 +
52033                 if (node && (node->key == ndx)) {
52034 -#ifdef DEBUG_STAT_CACHE        
52035 +#ifdef DEBUG_STAT_CACHE
52036                         size_t j;
52037                         int osize = splaytree_size(sc->files);
52038                         stat_cache_entry *sce = node->data;
52039 @@ -649,7 +639,7 @@
52040                         stat_cache_entry_free(node->data);
52041                         sc->files = splaytree_delete(sc->files, ndx);
52042  
52043 -#ifdef DEBUG_STAT_CACHE        
52044 +#ifdef DEBUG_STAT_CACHE
52045                         for (j = 0; j < ctrl.used; j++) {
52046                                 if (ctrl.ptr[j] == ndx) {
52047                                         ctrl.ptr[j] = ctrl.ptr[--ctrl.used];
52048 --- ../lighttpd-1.4.11/src/stream.c     2005-09-23 21:50:15.000000000 +0300
52049 +++ lighttpd-1.4.12/src/stream.c        2006-07-16 00:26:04.000000000 +0300
52050 @@ -1,7 +1,6 @@
52051  #include <sys/types.h>
52052  #include <sys/stat.h>
52053  
52054 -#include <unistd.h> 
52055  #include <fcntl.h>
52056  
52057  #include "stream.h"
52058 @@ -10,6 +9,7 @@
52059  #endif
52060  
52061  #include "sys-mmap.h"
52062 +#include "sys-files.h"
52063  
52064  #ifndef O_BINARY
52065  # define O_BINARY 0
52066 @@ -19,39 +19,39 @@
52067         struct stat st;
52068  #ifdef HAVE_MMAP
52069         int fd;
52070 -#elif defined __WIN32
52071 +#elif defined _WIN32
52072         HANDLE *fh, *mh;
52073         void *p;
52074  #endif
52075  
52076         f->start = NULL;
52077 -       
52078 +
52079         if (-1 == stat(fn->ptr, &st)) {
52080                 return -1;
52081         }
52082 -       
52083 +
52084         f->size = st.st_size;
52085  
52086  #ifdef HAVE_MMAP
52087         if (-1 == (fd = open(fn->ptr, O_RDONLY | O_BINARY))) {
52088                 return -1;
52089         }
52090 -       
52091 +
52092         f->start = mmap(0, f->size, PROT_READ, MAP_SHARED, fd, 0);
52093 -       
52094 +
52095         close(fd);
52096 -       
52097 +
52098         if (MAP_FAILED == f->start) {
52099                 return -1;
52100         }
52101  
52102 -#elif defined __WIN32
52103 -       fh = CreateFile(fn->ptr, 
52104 -                       GENERIC_READ, 
52105 -                       FILE_SHARE_READ, 
52106 -                       NULL, 
52107 -                       OPEN_EXISTING, 
52108 -                       FILE_ATTRIBUTE_READONLY, 
52109 +#elif defined _WIN32
52110 +       fh = CreateFile(fn->ptr,
52111 +                       GENERIC_READ,
52112 +                       FILE_SHARE_READ,
52113 +                       NULL,
52114 +                       OPEN_EXISTING,
52115 +                       FILE_ATTRIBUTE_READONLY,
52116                         NULL);
52117  
52118         if (!fh) return -1;
52119 @@ -66,7 +66,7 @@
52120         if (!mh) {
52121                 LPVOID lpMsgBuf;
52122                 FormatMessage(
52123 -                       FORMAT_MESSAGE_ALLOCATE_BUFFER | 
52124 +                       FORMAT_MESSAGE_ALLOCATE_BUFFER |
52125                         FORMAT_MESSAGE_FROM_SYSTEM,
52126                         NULL,
52127                         GetLastError(),
52128 @@ -76,7 +76,7 @@
52129  
52130                 return -1;
52131         }
52132 -       
52133 +
52134         p = MapViewOfFile(mh,
52135                         FILE_MAP_READ,
52136                         0,
52137 @@ -87,9 +87,9 @@
52138  
52139         f->start = p;
52140  #else
52141 -# error no mmap found  
52142 +# error no mmap found
52143  #endif
52144 -       
52145 +
52146         return 0;
52147  }
52148  
52149 --- ../lighttpd-1.4.11/src/sys-files.h  1970-01-01 03:00:00.000000000 +0300
52150 +++ lighttpd-1.4.12/src/sys-files.h     2006-07-16 00:26:04.000000000 +0300
52151 @@ -0,0 +1,67 @@
52152 +#ifndef _SYS_FILES_H_
52153 +#define _SYS_FILES_H_
52154 +
52155 +#define DIR_SEPERATOR_UNIX '/'
52156 +#define DIR_SEPERATOR_WIN '\\'
52157 +
52158 +#ifdef _WIN32
52159 +#include <windows.h>
52160 +#include <io.h>     /* open */
52161 +#include <direct.h> /* chdir */
52162 +
52163 +#include "buffer.h"
52164 +
52165 +#define DIR_SEPERATOR DIR_SEPERATOR_WIN
52166 +
52167 +#define __S_ISTYPE(mode, mask)  (((mode) & _S_IFMT) == (mask))
52168 +
52169 +#define S_ISDIR(mode)    __S_ISTYPE((mode), _S_IFDIR)
52170 +#define S_ISCHR(mode)    __S_ISTYPE((mode), _S_IFCHR)
52171 +#define S_ISBLK(mode)    __S_ISTYPE((mode), _S_IFBLK)
52172 +#define S_ISREG(mode)    __S_ISTYPE((mode), _S_IFREG)
52173 +/* we don't support symlinks */
52174 +#define S_ISLNK(mode)    0
52175 +
52176 +#define lstat stat
52177 +#define mkstemp mktemp
52178 +#define mkdir(x, y) mkdir(x)
52179 +
52180 +struct dirent {
52181 +    const char *d_name;
52182 +};
52183 +
52184 +typedef struct {
52185 +    HANDLE h;
52186 +    WIN32_FIND_DATA finddata;
52187 +    struct dirent dent;
52188 +} DIR;
52189 +
52190 +DIR *opendir(const char *dn);
52191 +struct dirent *readdir(DIR *d);
52192 +void closedir(DIR *d);
52193 +
52194 +buffer *filename_unix2local(buffer *b);
52195 +buffer *pathname_unix2local(buffer *b);
52196 +
52197 +#else
52198 +#include <unistd.h>
52199 +#include <dirent.h>
52200 +
52201 +#define DIR_SEPERATOR DIR_SEPERATOR_UNIX
52202 +
52203 +#define filename_unix2local(x) (x)
52204 +#define pathname_unix2local(x) (x)
52205 +#endif
52206 +
52207 +#define PATHNAME_APPEND_SLASH(x) \
52208 +       if (x->used > 1 && x->ptr[x->used - 2] != DIR_SEPERATOR) { \
52209 +        char sl[2] = { DIR_SEPERATOR, 0 }; \
52210 +        BUFFER_APPEND_STRING_CONST(x, sl); \
52211 +    }
52212 +
52213 +#ifndef O_LARGEFILE
52214 +# define O_LARGEFILE 0
52215 +#endif
52216 +
52217 +#endif
52218 +
52219 --- ../lighttpd-1.4.11/src/sys-mmap.h   2005-08-11 01:26:34.000000000 +0300
52220 +++ lighttpd-1.4.12/src/sys-mmap.h      2006-07-16 00:26:04.000000000 +0300
52221 @@ -1,7 +1,7 @@
52222  #ifndef WIN32_MMAP_H
52223  #define WIN32_MMAP_H
52224  
52225 -#ifdef __WIN32
52226 +#ifdef _WIN32
52227  
52228  #define MAP_FAILED -1
52229  #define PROT_SHARED 0
52230 --- ../lighttpd-1.4.11/src/sys-process.h        1970-01-01 03:00:00.000000000 +0300
52231 +++ lighttpd-1.4.12/src/sys-process.h   2006-07-16 00:26:04.000000000 +0300
52232 @@ -0,0 +1,17 @@
52233 +#ifndef _SYS_PROCESS_H_
52234 +#define _SYS_PROCESS_H_
52235 +
52236 +#ifdef _WIN32
52237 +#include <process.h>
52238 +#define pid_t int
52239 +/* win32 has no fork() */
52240 +#define kill(x, y)
52241 +#define getpid() 0
52242 +
52243 +#else
52244 +#include <sys/wait.h>
52245 +#include <unistd.h>
52246 +#endif
52247 +
52248 +#endif
52249 +
52250 --- ../lighttpd-1.4.11/src/sys-socket.h 2005-08-11 01:26:39.000000000 +0300
52251 +++ lighttpd-1.4.12/src/sys-socket.h    2006-07-18 13:03:40.000000000 +0300
52252 @@ -1,15 +1,26 @@
52253  #ifndef WIN32_SOCKET_H
52254  #define WIN32_SOCKET_H
52255  
52256 -#ifdef __WIN32
52257 +#ifdef _WIN32
52258  
52259  #include <winsock2.h>
52260  
52261  #define ECONNRESET WSAECONNRESET
52262  #define EINPROGRESS WSAEINPROGRESS
52263  #define EALREADY WSAEALREADY
52264 +#define ENOTCONN WSAENOTCONN
52265 +#define EWOULDBLOCK WSAEWOULDBLOCK
52266  #define ioctl ioctlsocket
52267  #define hstrerror(x) ""
52268 +#define STDIN_FILENO 0
52269 +#define STDOUT_FILENO 1
52270 +#define STDERR_FILENO 2
52271 +#define ssize_t int
52272 +
52273 +int inet_aton(const char *cp, struct in_addr *inp);
52274 +#define HAVE_INET_ADDR
52275 +#undef HAVE_INET_ATON
52276 +
52277  #else
52278  #include <sys/socket.h>
52279  #include <sys/ioctl.h>
52280 @@ -18,7 +29,25 @@
52281  #include <sys/un.h>
52282  #include <arpa/inet.h>
52283  
52284 +#ifndef SUN_LEN
52285 +#define SUN_LEN(su) \
52286 +        (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
52287 +#endif
52288 +
52289 +#define closesocket(x) close(x)
52290 +
52291  #include <netdb.h>
52292 +#endif /* !_WIN32 */
52293 +
52294 +typedef union {
52295 +#ifdef HAVE_IPV6
52296 +       struct sockaddr_in6 ipv6;
52297 +#endif
52298 +       struct sockaddr_in ipv4;
52299 +#ifdef HAVE_SYS_UN_H
52300 +       struct sockaddr_un un;
52301  #endif
52302 +       struct sockaddr plain;
52303 +} sock_addr;
52304  
52305  #endif
52306 --- ../lighttpd-1.4.11/src/sys-strings.h        1970-01-01 03:00:00.000000000 +0300
52307 +++ lighttpd-1.4.12/src/sys-strings.h   2006-07-16 00:26:03.000000000 +0300
52308 @@ -0,0 +1,11 @@
52309 +#ifndef _SYS_STRINGS_H_
52310 +#define _SYS_STRINGS_H_
52311 +
52312 +#ifdef _WIN32
52313 +#define strcasecmp stricmp
52314 +#define strncasecmp strnicmp
52315 +#define strtoll(p, e, b) _strtoi64(p, e, b)
52316 +#endif
52317 +
52318 +#endif
52319 +
52320 --- ../lighttpd-1.4.11/tests/LightyTest.pm      2006-01-14 20:32:31.000000000 +0200
52321 +++ lighttpd-1.4.12/tests/LightyTest.pm 2006-07-18 13:03:40.000000000 +0300
52322 @@ -87,14 +87,16 @@
52323         # pre-process configfile if necessary
52324         #
52325  
52326 -       unlink($self->{TESTDIR}."/tmp/cfg.file");
52327 -       system("cat ".$self->{SRCDIR}."/".$self->{CONFIGFILE}.' | perl -pe "s#\@SRCDIR\@#'.$self->{BASEDIR}.'/tests/#" > '.$self->{TESTDIR}.'/tmp/cfg.file');
52328 +       $ENV{'SRCDIR'} = $self->{BASEDIR}.'/tests';
52329 +       $ENV{'PORT'} = $self->{PORT};
52330  
52331         unlink($self->{LIGHTTPD_PIDFILE});
52332 -       if (1) {
52333 -               system($self->{LIGHTTPD_PATH}." -f ".$self->{TESTDIR}."/tmp/cfg.file -m ".$self->{MODULES_PATH});
52334 +       if (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'strace') {
52335 +               system("strace -tt -s 512 -o strace ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH}." &");
52336 +       } elsif (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'valgrind') {
52337 +               system("valgrind --tool=memcheck --show-reachable=yes --leak-check=yes --logfile=valgrind ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH}." &");
52338         } else {
52339 -               system("valgrind --tool=memcheck --show-reachable=yes --leak-check=yes --logfile=foo ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{TESTDIR}."/tmp/cfg.file -m ".$self->{MODULES_PATH}." &");
52340 +               system($self->{LIGHTTPD_PATH}." -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH});
52341         }
52342  
52343         select(undef, undef, undef, 0.1);
52344 @@ -184,7 +186,7 @@
52345                                         (my $h = $1) =~ tr/[A-Z]/[a-z]/;
52346  
52347                                         if (defined $resp_hdr{$h}) {
52348 -                                               diag(sprintf("header %s is duplicated: %s and %s\n",
52349 +                                               diag(sprintf("header '%s' is duplicated: '%s' and '%s'\n",
52350                                                              $h, $resp_hdr{$h}, $2));
52351                                         } else {
52352                                                 $resp_hdr{$h} = $2;
52353 @@ -196,6 +198,9 @@
52354                         }
52355                 }
52356  
52357 +               $t->{etag} = $resp_hdr{'etag'};
52358 +               $t->{date} = $resp_hdr{'date'};
52359 +
52360                 # check length
52361                 if (defined $resp_hdr{"content-length"}) {
52362                         $resp_body = substr($lines, 0, $resp_hdr{"content-length"});
52363 --- ../lighttpd-1.4.11/tests/Makefile.am        2005-09-16 15:48:40.000000000 +0300
52364 +++ lighttpd-1.4.12/tests/Makefile.am   2006-07-16 00:26:05.000000000 +0300
52365 @@ -39,10 +39,18 @@
52366        mod-redirect.t \
52367        mod-userdir.t \
52368        mod-rewrite.t \
52369 +      mod-proxy.t \
52370        request.t \
52371        mod-ssi.t \
52372        LightyTest.pm \
52373 -      mod-setenv.t 
52374 +      mod-setenv.t \
52375 +      lowercase.t \
52376 +      lowercase.conf \
52377 +      proxy.conf \
52378 +      cachable.t \
52379 +      default.conf \
52380 +      proxy-backend-1.conf \
52381 +      proxy-backend-2.conf 
52382  
52383  
52384  TESTS_ENVIRONMENT=$(srcdir)/wrapper.sh $(srcdir) $(top_builddir) 
52385 --- ../lighttpd-1.4.11/tests/bug-06.conf        2005-08-27 17:44:19.000000000 +0300
52386 +++ lighttpd-1.4.12/tests/bug-06.conf   2006-07-16 00:26:04.000000000 +0300
52387 @@ -1,5 +1,5 @@
52388 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52389 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52390 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52391 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52392  
52393  ## bind to port (default: 80)
52394  server.port                 = 2048
52395 @@ -8,7 +8,7 @@
52396  
52397  ## bind to localhost (default: all interfaces)
52398  server.bind                = "localhost"
52399 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52400 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52401  server.name                = "www.example.org"
52402  server.tag                 = "Apache 1.3.29"
52403  
52404 @@ -59,7 +59,7 @@
52405  ######################## MODULE CONFIG ############################
52406  
52407  
52408 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52409 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52410  
52411  mimetype.assign             = ( ".png"  => "image/png", 
52412                                  ".jpg"  => "image/jpeg",
52413 @@ -77,7 +77,7 @@
52414                                 ".c"    => "text/plain",
52415                                 ".conf" => "text/plain" )
52416  
52417 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52418 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52419  compress.filetype           = ("text/plain", "text/html")
52420  
52421  setenv.add-environment      = ( "TRAC_ENV" => "foo")
52422 @@ -90,7 +90,7 @@
52423                                     "host" => "127.0.0.1",
52424                                     "port" => 1026,
52425  #                                  "mode" => "authorizer",
52426 -#                                  "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
52427 +#                                  "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
52428                                   )
52429                                 )
52430                               )
52431 @@ -106,7 +106,7 @@
52432  ssl.pemfile                 = "server.pem"
52433  
52434  auth.backend                = "plain"
52435 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52436 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52437  auth.backend.plain.groupfile = "lighttpd.group"
52438  
52439  auth.backend.ldap.hostname  = "localhost"
52440 @@ -149,15 +149,15 @@
52441  status.config-url           = "/server-config"
52442  
52443  simple-vhost.document-root  = "pages"
52444 -simple-vhost.server-root    = "@SRCDIR@/tmp/lighttpd/servers/"
52445 +simple-vhost.server-root    = env.SRCDIR + "/tmp/lighttpd/servers/"
52446  simple-vhost.default-host   = "www.example.org"
52447  
52448  $HTTP["host"] == "vvv.example.org" {
52449 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52450 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52451  }
52452  
52453  $HTTP["host"] == "zzz.example.org" {
52454 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52455 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52456    server.name = "zzz.example.org"
52457  }
52458  
52459 --- ../lighttpd-1.4.11/tests/bug-12.conf        2005-08-27 17:44:19.000000000 +0300
52460 +++ lighttpd-1.4.12/tests/bug-12.conf   2006-07-16 00:26:04.000000000 +0300
52461 @@ -1,5 +1,5 @@
52462 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52463 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52464 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52465 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52466  
52467  ## bind to port (default: 80)
52468  server.port                 = 2048
52469 @@ -8,7 +8,7 @@
52470  
52471  ## bind to localhost (default: all interfaces)
52472  server.bind                = "localhost"
52473 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52474 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52475  server.name                = "www.example.org"
52476  server.tag                 = "Apache 1.3.29"
52477  
52478 @@ -61,7 +61,7 @@
52479  ######################## MODULE CONFIG ############################
52480  
52481  
52482 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52483 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52484  
52485  mimetype.assign             = ( ".png"  => "image/png", 
52486                                  ".jpg"  => "image/jpeg",
52487 @@ -79,7 +79,7 @@
52488                                 ".c"    => "text/plain",
52489                                 ".conf" => "text/plain" )
52490  
52491 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52492 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52493  compress.filetype           = ("text/plain", "text/html")
52494  
52495  setenv.add-environment      = ( "TRAC_ENV" => "foo")
52496 @@ -92,7 +92,7 @@
52497                                     "host" => "127.0.0.1",
52498                                     "port" => 1026,
52499  #                                  "mode" => "authorizer",
52500 -#                                  "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
52501 +#                                  "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
52502                                   )
52503                                 )
52504                               )
52505 @@ -108,7 +108,7 @@
52506  ssl.pemfile                 = "server.pem"
52507  
52508  auth.backend                = "plain"
52509 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52510 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52511  auth.backend.plain.groupfile = "lighttpd.group"
52512  
52513  auth.backend.ldap.hostname  = "localhost"
52514 @@ -151,15 +151,15 @@
52515  status.config-url           = "/server-config"
52516  
52517  simple-vhost.document-root  = "pages"
52518 -simple-vhost.server-root    = "@SRCDIR@/tmp/lighttpd/servers/"
52519 +simple-vhost.server-root    = env.SRCDIR + "/tmp/lighttpd/servers/"
52520  simple-vhost.default-host   = "www.example.org"
52521  
52522  $HTTP["host"] == "vvv.example.org" {
52523 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52524 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52525  }
52526  
52527  $HTTP["host"] == "zzz.example.org" {
52528 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52529 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52530    server.name = "zzz.example.org"
52531  }
52532  
52533 --- ../lighttpd-1.4.11/tests/cachable.t 1970-01-01 03:00:00.000000000 +0300
52534 +++ lighttpd-1.4.12/tests/cachable.t    2006-07-18 13:03:40.000000000 +0300
52535 @@ -0,0 +1,112 @@
52536 +#!/usr/bin/env perl
52537 +BEGIN {
52538 +    # add current source dir to the include-path
52539 +    # we need this for make distcheck
52540 +   (my $srcdir = $0) =~ s#/[^/]+$#/#;
52541 +   unshift @INC, $srcdir;
52542 +}
52543 +
52544 +use strict;
52545 +use IO::Socket;
52546 +use Test::More tests => 12;
52547 +use LightyTest;
52548 +
52549 +my $tf = LightyTest->new();
52550 +my $t;
52551 +
52552 +$tf->{CONFIGFILE} = 'lighttpd.conf';
52553 +    
52554 +ok($tf->start_proc == 0, "Starting lighttpd") or die();
52555 +
52556 +## check if If-Modified-Since, If-None-Match works
52557 +
52558 +$t->{REQUEST}  = ( <<EOF
52559 +GET / HTTP/1.0
52560 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT
52561 +EOF
52562 + );
52563 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52564 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-Modified-Since');
52565 +
52566 +$t->{REQUEST}  = ( <<EOF
52567 +GET / HTTP/1.0
52568 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
52569 +EOF
52570 + );
52571 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+Last-Modified' => ''} ];
52572 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-Modified-Since, comment');
52573 +
52574 +my $now = $t->{date};
52575 +
52576 +$t->{REQUEST}  = ( <<EOF
52577 +GET / HTTP/1.0
52578 +If-Modified-Since: $now
52579 +EOF
52580 + );
52581 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52582 +ok($tf->handle_http($t) == 0, 'Conditional GET - new If-Modified-Since');
52583 +
52584 +$t->{REQUEST}  = ( <<EOF
52585 +GET / HTTP/1.0
52586 +If-Modified-Since: $now; foo
52587 +EOF
52588 + );
52589 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52590 +ok($tf->handle_http($t) == 0, 'Conditional GET - new If-Modified-Since, comment');
52591 +
52592 +$t->{REQUEST}  = ( <<EOF
52593 +GET / HTTP/1.0
52594 +If-None-Match: foo
52595 +EOF
52596 + );
52597 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+ETag' => ''} ];
52598 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-None-Match');
52599 +
52600 +my $etag = $t->{etag};
52601 +
52602 +$t->{REQUEST}  = ( <<EOF
52603 +GET / HTTP/1.0
52604 +If-None-Match: $etag
52605 +EOF
52606 + );
52607 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52608 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-None-Match');
52609 +
52610 +$t->{REQUEST}  = ( <<EOF
52611 +GET / HTTP/1.0
52612 +If-None-Match: $etag
52613 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
52614 +EOF
52615 + );
52616 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52617 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + old Last-Modified');
52618 +
52619 +$t->{REQUEST}  = ( <<EOF
52620 +GET / HTTP/1.0
52621 +If-None-Match: $etag
52622 +If-Modified-Since: $now; foo
52623 +EOF
52624 + );
52625 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52626 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag, Last-Modified + comment');
52627 +
52628 +$t->{REQUEST}  = ( <<EOF
52629 +GET / HTTP/1.0
52630 +If-None-Match: Foo
52631 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
52632 +EOF
52633 + );
52634 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52635 +ok($tf->handle_http($t) == 0, 'Conditional GET - old ETAG + old Last-Modified');
52636 +
52637 +$t->{REQUEST}  = ( <<EOF
52638 +GET / HTTP/1.0
52639 +If-None-Match: $etag
52640 +If-Modified-Since: $now foo
52641 +EOF
52642 + );
52643 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 412 } ];
52644 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + Last-Modified + overlong timestamp');
52645 +
52646 +ok($tf->stop_proc == 0, "Stopping lighttpd");
52647 +
52648 --- ../lighttpd-1.4.11/tests/condition.conf     2005-08-27 17:44:19.000000000 +0300
52649 +++ lighttpd-1.4.12/tests/condition.conf        2006-07-16 00:26:05.000000000 +0300
52650 @@ -2,15 +2,15 @@
52651  debug.log-request-handling = "enable"
52652  debug.log-condition-handling = "enable"
52653  
52654 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52655 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52656 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52657 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52658  
52659  ## bind to port (default: 80)
52660  server.port                 = 2048
52661  
52662  ## bind to localhost (default: all interfaces)
52663  server.bind                = "localhost"
52664 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52665 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52666  server.name                = "www.example.org"
52667  server.tag                 = "Apache 1.3.29"
52668  
52669 @@ -22,25 +22,25 @@
52670  ######################## MODULE CONFIG ############################
52671  
52672  
52673 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52674 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52675  
52676  mimetype.assign             = ( ".html" => "text/html" )
52677  
52678  url.redirect = ("^" => "/default")
52679  
52680  $HTTP["host"] == "www.example.org" {
52681 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52682 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52683    server.name = "www.example.org"
52684    url.redirect = ("^" => "/match_1")
52685  }
52686  else $HTTP["host"] == "test1.example.org" {
52687 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52688 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52689    server.name = "test1.example.org"
52690    url.redirect = ("^" => "/match_2")
52691  }
52692  # comments
52693  else $HTTP["host"] == "test2.example.org" {
52694 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52695 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52696    server.name = "test2.example.org"
52697    url.redirect = ("^" => "/match_3")
52698  }
52699 @@ -48,7 +48,7 @@
52700          # comments
52701  
52702  else $HTTP["host"] == "test3.example.org" {
52703 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52704 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52705    server.name = "test3.example.org"
52706    url.redirect = ("^" => "/match_4")
52707  
52708 --- ../lighttpd-1.4.11/tests/core-keepalive.t   2005-11-17 15:54:19.000000000 +0200
52709 +++ lighttpd-1.4.12/tests/core-keepalive.t      2006-07-16 00:26:05.000000000 +0300
52710 @@ -40,7 +40,7 @@
52711  
52712  GET /12345.txt HTTP/1.0
52713  Host: 123.example.org
52714 -Connection: keep-alive
52715 +Connection: close
52716  EOF
52717   );
52718  $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } , { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52719 --- ../lighttpd-1.4.11/tests/default.conf       1970-01-01 03:00:00.000000000 +0300
52720 +++ lighttpd-1.4.12/tests/default.conf  2006-07-16 00:26:05.000000000 +0300
52721 @@ -0,0 +1,111 @@
52722 +server.name                = "www.example.org"
52723 +
52724 +## bind to port (default: 80)
52725 +server.port                 = env.PORT
52726 +
52727 +
52728 +server.dir-listing          = "enable"
52729 +
52730 +#server.event-handler        = "linux-sysepoll"
52731 +#server.event-handler        = "linux-rtsig"
52732 +
52733 +server.modules              = ( 
52734 +                               "mod_rewrite",
52735 +                               "mod_setenv",
52736 +                               "mod_access", 
52737 +                               "mod_auth",
52738 +                               "mod_status", 
52739 +                               "mod_expire",
52740 +                               "mod_simple_vhost",
52741 +                               "mod_redirect", 
52742 +                               "mod_secdownload",
52743 +                               "mod_ssi",
52744 +                               "mod_fastcgi",
52745 +                               "mod_proxy",
52746 +                               "mod_cgi",
52747 +                               "mod_compress",
52748 +                               "mod_userdir",
52749 +                               "mod_accesslog" ) 
52750 +
52751 +server.indexfiles           = ( "index.php", "index.html", 
52752 +                                "index.htm", "default.htm" )
52753 +
52754 +ssi.extension = ( ".shtml" )
52755 +
52756 +######################## MODULE CONFIG ############################
52757 +
52758 +
52759 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52760 +server.errorlog             = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52761 +
52762 +mimetype.assign             = ( ".png"  => "image/png", 
52763 +                                ".jpg"  => "image/jpeg",
52764 +                                ".jpeg" => "image/jpeg",
52765 +                                ".gif"  => "image/gif",
52766 +                                ".html" => "text/html",
52767 +                                ".htm"  => "text/html",
52768 +                                ".pdf"  => "application/pdf",
52769 +                                ".swf"  => "application/x-shockwave-flash",
52770 +                                ".spl"  => "application/futuresplash",
52771 +                                ".txt"  => "text/plain",
52772 +                                ".tar.gz" =>   "application/x-tgz",
52773 +                                ".tgz"  => "application/x-tgz",
52774 +                                ".gz"   => "application/x-gzip",
52775 +                               ".c"    => "text/plain",
52776 +                               ".conf" => "text/plain" )
52777 +
52778 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52779 +compress.filetype           = ("text/plain", "text/html")
52780 +
52781 +setenv.add-environment      = ( "TRAC_ENV" => "tracenv", "SETENV" => "setenv")
52782 +
52783 +cgi.assign                  = ( ".pl"  => "/usr/bin/perl",
52784 +                                ".cgi" => "/usr/bin/perl",
52785 +                               ".py"  => "/usr/bin/python" )
52786 +                       
52787 +userdir.include-user = ( "jan" )
52788 +userdir.path = "/"
52789 +
52790 +ssl.engine                  = "disable"
52791 +ssl.pemfile                 = "server.pem"
52792 +
52793 +auth.backend                = "plain"
52794 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52795 +auth.backend.htpasswd.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.htpasswd"
52796 +auth.backend.plain.groupfile = "lighttpd.group"
52797 +
52798 +auth.backend.ldap.hostname  = "localhost"
52799 +auth.backend.ldap.base-dn   = "dc=my-domain,dc=com"
52800 +auth.backend.ldap.filter    = "(uid=$)"
52801 +
52802 +auth.require                = ( "/server-status" => 
52803 +                                ( 
52804 +                                 "method"  => "digest",
52805 +                                 "realm"   => "download archiv",
52806 +                                 "require" => "valid-user"
52807 +                               ),
52808 +                               "/auth.php" => 
52809 +                                ( 
52810 +                                 "method"  => "basic",
52811 +                                 "realm"   => "download archiv",
52812 +                                 "require" => "user=jan"
52813 +                               ),
52814 +                               "/server-config" => 
52815 +                                ( 
52816 +                                 "method"  => "basic",
52817 +                                 "realm"   => "download archiv",
52818 +                                 "require" => "valid-user"
52819 +                               )
52820 +                              )
52821 +
52822 +url.access-deny             = ( "~", ".inc")
52823 +
52824 +url.redirect                = ( "^/redirect/$" => "http://localhost:2048/" )
52825 +
52826 +url.rewrite                = ( "^/rewrite/foo($|\?.+)" => "/indexfile/rewrite.php$1",
52827 +                               "^/rewrite/bar(?:$|\?(.+))" => "/indexfile/rewrite.php?bar&$1" )
52828 +
52829 +#### status module
52830 +status.status-url           = "/server-status"
52831 +status.config-url           = "/server-config"
52832 +
52833 --- ../lighttpd-1.4.11/tests/docroot/www/dummydir/.svn/entries  2006-03-09 19:21:49.000000000 +0200
52834 +++ lighttpd-1.4.12/tests/docroot/www/dummydir/.svn/entries     2006-07-18 17:34:32.000000000 +0300
52835 @@ -9,5 +9,6 @@
52836     last-author="jan"
52837     kind="dir"
52838     uuid="152afb58-edef-0310-8abb-c4023f1b3aa9"
52839 -   revision="1040"/>
52840 +   repos="svn://svn.lighttpd.net/lighttpd"
52841 +   revision="1202"/>
52842  </wc-entries>
52843 --- ../lighttpd-1.4.11/tests/fastcgi-10.conf    2005-08-31 23:36:34.000000000 +0300
52844 +++ lighttpd-1.4.12/tests/fastcgi-10.conf       2006-07-16 00:26:04.000000000 +0300
52845 @@ -1,12 +1,12 @@
52846 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52847 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52848 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52849 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52850  
52851  ## bind to port (default: 80)
52852  server.port                 = 2048
52853  
52854  ## bind to localhost (default: all interfaces)
52855  server.bind                = "localhost"
52856 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52857 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52858  server.name                = "www.example.org"
52859  server.tag                 = "Apache 1.3.29"
52860  
52861 @@ -44,7 +44,7 @@
52862  ######################## MODULE CONFIG ############################
52863  
52864  
52865 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52866 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52867  
52868  mimetype.assign             = ( ".png"  => "image/png", 
52869                                  ".jpg"  => "image/jpeg",
52870 @@ -62,7 +62,7 @@
52871                                 ".c"    => "text/plain",
52872                                 ".conf" => "text/plain" )
52873  
52874 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52875 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52876  compress.filetype           = ("text/plain", "text/html")
52877  
52878  fastcgi.debug               = 0
52879 @@ -85,7 +85,7 @@
52880  ssl.pemfile                 = "server.pem"
52881  
52882  auth.backend                = "plain"
52883 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52884 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52885  auth.backend.plain.groupfile = "lighttpd.group"
52886  
52887  auth.backend.ldap.hostname  = "localhost"
52888 @@ -128,11 +128,11 @@
52889  status.config-url           = "/server-config"
52890  
52891  $HTTP["host"] == "vvv.example.org" {
52892 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52893 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52894  }
52895  
52896  $HTTP["host"] == "zzz.example.org" {
52897 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52898 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52899    server.name = "zzz.example.org"
52900  }
52901  
52902 --- ../lighttpd-1.4.11/tests/fastcgi-13.conf    2006-01-03 12:38:17.000000000 +0200
52903 +++ lighttpd-1.4.12/tests/fastcgi-13.conf       2006-07-18 13:03:40.000000000 +0300
52904 @@ -1,5 +1,5 @@
52905 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52906 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52907 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52908 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52909  
52910  debug.log-request-header   = "enable"
52911  debug.log-response-header  = "enable"
52912 @@ -10,7 +10,7 @@
52913  
52914  ## bind to localhost (default: all interfaces)
52915  server.bind                = "localhost"
52916 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52917 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52918  server.name                = "www.example.org"
52919  server.tag                 = "Apache 1.3.29"
52920  
52921 @@ -59,7 +59,7 @@
52922  ######################## MODULE CONFIG ############################
52923  
52924  
52925 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52926 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52927  
52928  mimetype.assign             = ( ".png"  => "image/png", 
52929                                  ".jpg"  => "image/jpeg",
52930 @@ -77,7 +77,7 @@
52931                                 ".c"    => "text/plain",
52932                                 ".conf" => "text/plain" )
52933  
52934 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52935 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52936  compress.filetype           = ("text/plain", "text/html")
52937  
52938  fastcgi.debug               = 0
52939 @@ -85,7 +85,7 @@
52940                                    "grisu" => ( 
52941                                     "host" => "127.0.0.1",
52942                                     "port" => 1048,
52943 -                                   "bin-path" => "/home/jan/Documents/php-5.1.0/sapi/cgi/php -c /usr/local/lib/php.ini",
52944 +                                   "bin-path" => "/home/jan/Documents/php-5.1.4/sapi/cgi/php -c /usr/local/lib/php.ini",
52945                                     "bin-copy-environment" => ( "PATH", "SHELL", "USER" ),
52946                                   )
52947                                 )
52948 @@ -102,7 +102,7 @@
52949  ssl.pemfile                 = "server.pem"
52950  
52951  auth.backend                = "plain"
52952 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52953 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52954  auth.backend.plain.groupfile = "lighttpd.group"
52955  
52956  auth.backend.ldap.hostname  = "localhost"
52957 @@ -145,11 +145,11 @@
52958  status.config-url           = "/server-config"
52959  
52960  $HTTP["host"] == "vvv.example.org" {
52961 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52962 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52963  }
52964  
52965  $HTTP["host"] == "zzz.example.org" {
52966 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52967 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52968    server.name = "zzz.example.org"
52969  }
52970  
52971 --- ../lighttpd-1.4.11/tests/fastcgi-auth.conf  2005-08-27 17:44:19.000000000 +0300
52972 +++ lighttpd-1.4.12/tests/fastcgi-auth.conf     2006-07-16 00:26:05.000000000 +0300
52973 @@ -1,5 +1,5 @@
52974 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52975 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52976 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52977 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52978  
52979  debug.log-request-header   = "enable"
52980  debug.log-response-header  = "enable"
52981 @@ -12,7 +12,7 @@
52982  
52983  ## bind to localhost (default: all interfaces)
52984  server.bind                = "localhost"
52985 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52986 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52987  server.name                = "www.example.org"
52988  server.tag                 = "Apache 1.3.29"
52989  
52990 @@ -61,7 +61,7 @@
52991  ######################## MODULE CONFIG ############################
52992  
52993  
52994 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52995 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52996  
52997  mimetype.assign             = ( ".png"  => "image/png", 
52998                                  ".jpg"  => "image/jpeg",
52999 @@ -79,7 +79,7 @@
53000                                 ".c"    => "text/plain",
53001                                 ".conf" => "text/plain" )
53002  
53003 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
53004 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
53005  compress.filetype           = ("text/plain", "text/html")
53006  
53007  fastcgi.debug               = 0
53008 @@ -87,9 +87,9 @@
53009                                    "grisu" => ( 
53010                                     "host" => "127.0.0.1",
53011                                     "port" => 20000,
53012 -                                   "bin-path" => "@SRCDIR@/fcgi-auth",
53013 +                                   "bin-path" => env.SRCDIR + "/fcgi-auth",
53014                                      "mode" => "authorizer",
53015 -                                    "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
53016 +                                    "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
53017                                     
53018                                   )
53019                                 )
53020 @@ -106,7 +106,7 @@
53021  ssl.pemfile                 = "server.pem"
53022  
53023  auth.backend                = "plain"
53024 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
53025 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53026  auth.backend.plain.groupfile = "lighttpd.group"
53027  
53028  auth.backend.ldap.hostname  = "localhost"
53029 @@ -149,11 +149,11 @@
53030  status.config-url           = "/server-config"
53031  
53032  $HTTP["host"] == "vvv.example.org" {
53033 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53034 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53035  }
53036  
53037  $HTTP["host"] == "zzz.example.org" {
53038 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53039 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53040    server.name = "zzz.example.org"
53041  }
53042  
53043 --- ../lighttpd-1.4.11/tests/fastcgi-responder.conf     2005-08-27 17:44:19.000000000 +0300
53044 +++ lighttpd-1.4.12/tests/fastcgi-responder.conf        2006-07-16 00:26:05.000000000 +0300
53045 @@ -1,5 +1,5 @@
53046 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53047 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
53048 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53049 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53050  
53051  #debug.log-request-header   = "enable"
53052  #debug.log-response-header  = "enable"
53053 @@ -15,7 +15,7 @@
53054  
53055  ## bind to localhost (default: all interfaces)
53056  server.bind                = "localhost"
53057 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
53058 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53059  server.name                = "www.example.org"
53060  server.tag                 = "Apache 1.3.29"
53061  
53062 @@ -64,7 +64,7 @@
53063  ######################## MODULE CONFIG ############################
53064  
53065  
53066 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
53067 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
53068  
53069  mimetype.assign             = ( ".png"  => "image/png", 
53070                                  ".jpg"  => "image/jpeg",
53071 @@ -82,7 +82,7 @@
53072                                 ".c"    => "text/plain",
53073                                 ".conf" => "text/plain" )
53074  
53075 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
53076 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
53077  compress.filetype           = ("text/plain", "text/html")
53078  
53079  fastcgi.debug               = 0
53080 @@ -90,10 +90,11 @@
53081                                    "grisu" => ( 
53082                                     "host" => "127.0.0.1",
53083                                     "port" => 10000,
53084 -                                   "bin-path" => "@SRCDIR@/fcgi-responder",
53085 +                                   "bin-path" => env.SRCDIR + "/fcgi-responder",
53086                                     "check-local" => "disable",
53087                                     "max-procs" => 1,
53088 -                                   "min-procs" => 1
53089 +                                   "min-procs" => 1,
53090 +                                   "allow-x-send-file" => "enable",
53091                                   )
53092                                 )
53093                               )
53094 @@ -109,7 +110,7 @@
53095  ssl.pemfile                 = "server.pem"
53096  
53097  auth.backend                = "plain"
53098 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
53099 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53100  auth.backend.plain.groupfile = "lighttpd.group"
53101  
53102  auth.backend.ldap.hostname  = "localhost"
53103 @@ -152,11 +153,11 @@
53104  status.config-url           = "/server-config"
53105  
53106  $HTTP["host"] == "vvv.example.org" {
53107 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53108 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53109  }
53110  
53111  $HTTP["host"] == "zzz.example.org" {
53112 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53113 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53114    server.name = "zzz.example.org"
53115  }
53116  
53117 --- ../lighttpd-1.4.11/tests/fcgi-responder.c   2005-08-11 01:26:55.000000000 +0300
53118 +++ lighttpd-1.4.12/tests/fcgi-responder.c      2006-07-16 00:26:05.000000000 +0300
53119 @@ -6,11 +6,17 @@
53120  int main () {
53121         int num_requests = 2;
53122         
53123 -       while (num_requests > 0 &&
53124 -              FCGI_Accept() >= 0) {
53125 -               char* p;
53126 -               
53127 -               if (NULL != (p = getenv("QUERY_STRING"))) {
53128 +       while (num_requests > 0 && FCGI_Accept() >= 0) {
53129 +               char* p = NULL;
53130 +               char* doc_root = NULL;
53131 +               char fname[4096];
53132 +               char* pfname = (char *)fname;
53133 +
53134 +               doc_root = getenv("DOCUMENT_ROOT");
53135 +               p = getenv("QUERY_STRING");
53136 +
53137 +               if (NULL != p && NULL != doc_root) {
53138 +                       snprintf(pfname, sizeof(fname), "%s/phpinfo.php", doc_root);
53139                         if (0 == strcmp(p, "lf")) {
53140                                 printf("Status: 200 OK\n\n");
53141                         } else if (0 == strcmp(p, "crlf")) {
53142 @@ -23,6 +29,18 @@
53143                                 printf("Status: 200 OK\r\n");
53144                                 fflush(stdout);
53145                                 printf("\r\n");
53146 +                       } else if (0 == strcmp(p,"x-lighttpd-send-file")) {
53147 +                               printf("Status: 200 OK\r\n");
53148 +                               printf("X-LIGHTTPD-send-file: %s\r\n", pfname);
53149 +                               printf("\r\n");
53150 +                       } else if (0 == strcmp(p,"xsendfile")) {
53151 +                               printf("Status: 200 OK\r\n");
53152 +                               printf("X-Sendfile: %s\r\n", pfname);
53153 +                               printf("\r\n");
53154 +                       } else if (0 == strcmp(p,"xsendfile-mixed-case")) {
53155 +                               printf("Status: 200 OK\r\n");
53156 +                               printf("X-SeNdFiLe: %s\r\n", pfname);
53157 +                               printf("\r\n");
53158                         } else if (0 == strcmp(p, "die-at-end")) {
53159                                 printf("Status: 200 OK\r\n\r\n");
53160                                 num_requests--;
53161 --- ../lighttpd-1.4.11/tests/lighttpd.conf      2006-03-09 15:26:58.000000000 +0200
53162 +++ lighttpd-1.4.12/tests/lighttpd.conf 2006-07-16 00:26:05.000000000 +0300
53163 @@ -1,80 +1,18 @@
53164 -debug.log-request-handling = "enable"
53165 -debug.log-condition-handling = "enable"
53166 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53167 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
53168 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53169 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53170 +server.tag = "Apache 1.3.29"
53171  
53172  ## 64 Mbyte ... nice limit
53173  server.max-request-size = 65000
53174  
53175 -## bind to port (default: 80)
53176 -server.port                 = 2048
53177 +include "default.conf"
53178  
53179 -## bind to localhost (default: all interfaces)
53180 -server.bind                = "localhost"
53181 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
53182 -server.name                = "www.example.org"
53183 -server.tag                 = "Apache 1.3.29"
53184 -
53185 -server.dir-listing          = "enable"
53186 -
53187 -#server.event-handler        = "linux-sysepoll"
53188 -#server.event-handler        = "linux-rtsig"
53189 -
53190 -#server.modules.path         = ""
53191 -server.modules              = ( 
53192 -                               "mod_rewrite",
53193 -                               "mod_setenv",
53194 -                               "mod_secdownload",
53195 -                               "mod_access", 
53196 -                               "mod_auth",
53197 -#                              "mod_httptls",
53198 -                               "mod_status", 
53199 -                               "mod_expire",
53200 -                               "mod_simple_vhost",
53201 -                               "mod_redirect", 
53202 -#                              "mod_evhost",
53203 -#                              "mod_localizer",
53204 -                               "mod_fastcgi",
53205 -                               "mod_cgi",
53206 -                               "mod_compress",
53207 -                               "mod_userdir",
53208 -                               "mod_ssi",
53209 -                               "mod_accesslog" ) 
53210 -
53211 -server.indexfiles           = ( "index.php", "index.html", 
53212 -                                "index.htm", "default.htm" )
53213 -
53214 -
53215 -######################## MODULE CONFIG ############################
53216 -
53217 -ssi.extension = ( ".shtml" )
53218 -
53219 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
53220 -
53221 -mimetype.assign             = ( ".png"  => "image/png", 
53222 -                                ".jpg"  => "image/jpeg",
53223 -                                ".jpeg" => "image/jpeg",
53224 -                                ".gif"  => "image/gif",
53225 -                                ".html" => "text/html",
53226 -                                ".htm"  => "text/html",
53227 -                                ".pdf"  => "application/pdf",
53228 -                                ".swf"  => "application/x-shockwave-flash",
53229 -                                ".spl"  => "application/futuresplash",
53230 -                                ".txt"  => "text/plain",
53231 -                                ".tar.gz" =>   "application/x-tgz",
53232 -                                ".tgz"  => "application/x-tgz",
53233 -                                ".gz"   => "application/x-gzip",
53234 -                               ".c"    => "text/plain",
53235 -                               ".conf" => "text/plain" )
53236 +setenv.add-request-header   = ( "FOO" => "foo")
53237 +setenv.add-response-header  = ( "BAR" => "foo")
53238  
53239  $HTTP["host"] == "cache.example.org" {
53240 -  compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
53241 +  compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
53242  }
53243 -compress.filetype           = ("text/plain", "text/html")
53244 -
53245 -setenv.add-environment      = ( "TRAC_ENV" => "tracenv", "SETENV" => "setenv")
53246 -setenv.add-request-header   = ( "FOO" => "foo")
53247 -setenv.add-response-header  = ( "BAR" => "foo")
53248  
53249  $HTTP["url"] =~ "\.pdf$" {
53250    server.range-requests = "disable"
53251 @@ -85,76 +23,31 @@
53252                                 "/prefix.fcgi" => ( ( "host" => "127.0.0.1", "port" => 1026, "check-local" => "disable", "broken-scriptfilename" => "enable" ) )
53253                               )
53254                 
53255 -
53256 -cgi.assign                  = ( ".pl"  => "/usr/bin/perl",
53257 -                                ".cgi" => "/usr/bin/perl",
53258 -                               ".py"  => "/usr/bin/python" )
53259 -                       
53260 -userdir.include-user = ( "jan" )
53261 -userdir.path = "/"
53262 -
53263 -ssl.engine                  = "disable"
53264 -ssl.pemfile                 = "server.pem"
53265 -
53266  $HTTP["host"] == "auth-htpasswd.example.org" {
53267         auth.backend                = "htpasswd"
53268  }
53269  
53270 -auth.backend                = "plain"
53271 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
53272 -
53273 -auth.backend.htpasswd.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.htpasswd"
53274 -
53275 -
53276 -auth.require                = ( "/server-status" => 
53277 -                                ( 
53278 -                                 "method"  => "digest",
53279 -                                 "realm"   => "download archiv",
53280 -                                 "require" => "group=www|user=jan|host=192.168.2.10"
53281 -                               ),
53282 -                               "/server-config" => 
53283 -                                ( 
53284 -                                 "method"  => "basic",
53285 -                                 "realm"   => "download archiv",
53286 -                                 "require" => "valid-user"
53287 -                               )
53288 -                              )
53289 -
53290 -url.access-deny             = ( "~", ".inc")
53291 -
53292 -url.rewrite                = ( "^/rewrite/foo($|\?.+)" => "/indexfile/rewrite.php$1",
53293 -                               "^/rewrite/bar(?:$|\?(.+))" => "/indexfile/rewrite.php?bar&$1" )
53294 -
53295 -expire.url                  = ( "/expire/access" => "access 2 hours", 
53296 -                               "/expire/modification" => "access plus 1 seconds 2 minutes")
53297 -
53298 -#cache.cache-dir             = "/home/weigon/wwwroot/cache/"
53299 -
53300 -#### status module
53301 -status.status-url           = "/server-status"
53302 -status.config-url           = "/server-config"
53303 -
53304  $HTTP["host"] == "vvv.example.org" {
53305 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53306 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53307    secdownload.secret          = "verysecret"
53308 -  secdownload.document-root   = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53309 +  secdownload.document-root   = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53310    secdownload.uri-prefix      = "/sec/"
53311    secdownload.timeout         = 120
53312  }
53313  
53314  $HTTP["host"] == "zzz.example.org" {
53315 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53316 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53317    server.name = "zzz.example.org"
53318  }
53319  
53320  $HTTP["host"] == "no-simple.example.org" {
53321 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/123.example.org/pages/"
53322 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/123.example.org/pages/"
53323    server.name = "zzz.example.org"
53324  }
53325  
53326  $HTTP["host"] !~ "(no-simple\.example\.org)" {
53327    simple-vhost.document-root  = "pages"
53328 -  simple-vhost.server-root    = "@SRCDIR@/tmp/lighttpd/servers/"
53329 +  simple-vhost.server-root    = env.SRCDIR + "/tmp/lighttpd/servers/"
53330    simple-vhost.default-host   = "www.example.org"
53331  }
53332  
53333 --- ../lighttpd-1.4.11/tests/lowercase.conf     1970-01-01 03:00:00.000000000 +0300
53334 +++ lighttpd-1.4.12/tests/lowercase.conf        2006-07-16 00:26:05.000000000 +0300
53335 @@ -0,0 +1,80 @@
53336 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53337 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53338 +
53339 +## bind to port (default: 80)
53340 +server.port                 = 2048
53341 +
53342 +## bind to localhost (default: all interfaces)
53343 +server.bind                = "localhost"
53344 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53345 +
53346 +server.force-lowercase-filenames = "enable"
53347 +
53348 +server.dir-listing          = "enable"
53349 +
53350 +server.modules              = ( 
53351 +                               "mod_rewrite",
53352 +                               "mod_setenv",
53353 +                               "mod_secdownload",
53354 +                               "mod_access", 
53355 +                               "mod_auth",
53356 +                               "mod_status", 
53357 +                               "mod_expire",
53358 +                               "mod_redirect", 
53359 +                               "mod_fastcgi",
53360 +                               "mod_cgi" ) 
53361 +
53362 +server.indexfiles           = ( "index.php", "index.html", 
53363 +                                "index.htm", "default.htm" )
53364 +
53365 +
53366 +######################## MODULE CONFIG ############################
53367 +
53368 +mimetype.assign             = ( ".png"  => "image/png", 
53369 +                                ".jpg"  => "image/jpeg",
53370 +                                ".jpeg" => "image/jpeg",
53371 +                                ".gif"  => "image/gif",
53372 +                                ".html" => "text/html",
53373 +                                ".htm"  => "text/html",
53374 +                                ".pdf"  => "application/pdf",
53375 +                                ".swf"  => "application/x-shockwave-flash",
53376 +                                ".spl"  => "application/futuresplash",
53377 +                                ".txt"  => "text/plain",
53378 +                                ".tar.gz" =>   "application/x-tgz",
53379 +                                ".tgz"  => "application/x-tgz",
53380 +                                ".gz"   => "application/x-gzip",
53381 +                               ".c"    => "text/plain",
53382 +                               ".conf" => "text/plain" )
53383 +
53384 +fastcgi.debug               = 0
53385 +fastcgi.server              = ( ".php" =>        ( ( "host" => "127.0.0.1", "port" => 1026, "broken-scriptfilename" => "enable" ) ),
53386 +                               "/prefix.fcgi" => ( ( "host" => "127.0.0.1", "port" => 1026, "check-local" => "disable", "broken-scriptfilename" => "enable" ) )
53387 +                             )
53388 +               
53389 +
53390 +cgi.assign                  = ( ".pl"  => "/usr/bin/perl",
53391 +                                ".cgi" => "/usr/bin/perl",
53392 +                               ".py"  => "/usr/bin/python" )
53393 +                       
53394 +auth.backend                = "plain"
53395 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53396 +
53397 +auth.backend.htpasswd.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.htpasswd"
53398 +
53399 +$HTTP["host"] == "lowercase-auth" {
53400 +  auth.require             = ( "/image.jpg" => 
53401 +                                ( 
53402 +                                 "method"  => "digest",
53403 +                                 "realm"   => "download archiv",
53404 +                                 "require" => "valid-user"
53405 +                               )
53406 +                              )
53407 +}
53408 +
53409 +$HTTP["host"] == "lowercase-deny" {
53410 +  url.access-deny             = ( ".jpg")
53411 +}
53412 +
53413 +$HTTP["host"] == "lowercase-exclude" {
53414 +  static-file.exclude-extensions = ( ".jpg" )
53415 +}
53416 --- ../lighttpd-1.4.11/tests/lowercase.t        1970-01-01 03:00:00.000000000 +0300
53417 +++ lighttpd-1.4.12/tests/lowercase.t   2006-07-16 00:26:05.000000000 +0300
53418 @@ -0,0 +1,94 @@
53419 +#!/usr/bin/env perl
53420 +BEGIN {
53421 +    # add current source dir to the include-path
53422 +    # we need this for make distcheck
53423 +   (my $srcdir = $0) =~ s#/[^/]+$#/#;
53424 +   unshift @INC, $srcdir;
53425 +}
53426 +
53427 +use strict;
53428 +use IO::Socket;
53429 +use Test::More tests => 10;
53430 +use LightyTest;
53431 +
53432 +my $tf = LightyTest->new();
53433 +my $t;
53434 +
53435 +$tf->{CONFIGFILE} = 'lowercase.conf';
53436 +    
53437 +ok($tf->start_proc == 0, "Starting lighttpd") or die();
53438 +
53439 +## check if lower-casing works
53440 +
53441 +$t->{REQUEST}  = ( <<EOF
53442 +GET /image.JPG HTTP/1.0
53443 +EOF
53444 + );
53445 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53446 +ok($tf->handle_http($t) == 0, 'uppercase access');
53447 +
53448 +$t->{REQUEST}  = ( <<EOF
53449 +GET /image.jpg HTTP/1.0
53450 +EOF
53451 + );
53452 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53453 +ok($tf->handle_http($t) == 0, 'lowercase access');
53454 +
53455 +## check that mod-auth works
53456 +
53457 +$t->{REQUEST}  = ( <<EOF
53458 +GET /image.JPG HTTP/1.0
53459 +Host: lowercase-auth
53460 +EOF
53461 + );
53462 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ];
53463 +ok($tf->handle_http($t) == 0, 'uppercase access');
53464 +
53465 +$t->{REQUEST}  = ( <<EOF
53466 +GET /image.jpg HTTP/1.0
53467 +Host: lowercase-auth
53468 +EOF
53469 + );
53470 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ];
53471 +ok($tf->handle_http($t) == 0, 'lowercase access');
53472 +
53473 +
53474 +## check that mod-staticfile exclude works
53475 +$t->{REQUEST}  = ( <<EOF
53476 +GET /image.JPG HTTP/1.0
53477 +Host: lowercase-exclude
53478 +EOF
53479 + );
53480 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53481 +ok($tf->handle_http($t) == 0, 'upper case access to staticfile.exclude-extension');
53482 +
53483 +$t->{REQUEST}  = ( <<EOF
53484 +GET /image.jpg HTTP/1.0
53485 +Host: lowercase-exclude
53486 +EOF
53487 + );
53488 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53489 +ok($tf->handle_http($t) == 0, 'lowercase access');
53490 +
53491 +
53492 +## check that mod-access exclude works
53493 +$t->{REQUEST}  = ( <<EOF
53494 +GET /image.JPG HTTP/1.0
53495 +Host: lowercase-deny
53496 +EOF
53497 + );
53498 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53499 +ok($tf->handle_http($t) == 0, 'uppercase access to url.access-deny protected location');
53500 +
53501 +$t->{REQUEST}  = ( <<EOF
53502 +GET /image.jpg HTTP/1.0
53503 +Host: lowercase-deny
53504 +EOF
53505 + );
53506 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53507 +ok($tf->handle_http($t) == 0, 'lowercase access');
53508 +
53509 +
53510 +
53511 +ok($tf->stop_proc == 0, "Stopping lighttpd");
53512 +
53513 --- ../lighttpd-1.4.11/tests/mod-cgi.t  2005-09-01 14:43:05.000000000 +0300
53514 +++ lighttpd-1.4.12/tests/mod-cgi.t     2006-07-18 13:03:40.000000000 +0300
53515 @@ -43,7 +43,7 @@
53516  GET /nph-status.pl HTTP/1.0
53517  EOF
53518   );
53519 -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53520 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 502 } ];
53521  ok($tf->handle_http($t) == 0, 'NPH + perl, Bug #14');
53522  
53523  $t->{REQUEST} = ( <<EOF
53524 --- ../lighttpd-1.4.11/tests/mod-fastcgi.t      2006-03-09 15:30:45.000000000 +0200
53525 +++ lighttpd-1.4.12/tests/mod-fastcgi.t 2006-07-18 13:03:40.000000000 +0300
53526 @@ -7,7 +7,7 @@
53527  }
53528  
53529  use strict;
53530 -use Test::More tests => 47;
53531 +use Test::More tests => 49;
53532  use LightyTest;
53533  
53534  my $tf = LightyTest->new();
53535 @@ -15,7 +15,7 @@
53536  my $t;
53537  
53538  SKIP: {
53539 -       skip "no PHP running on port 1026", 30 unless $tf->listening_on(1026);
53540 +       skip "no PHP running on port 1026", 29 unless $tf->listening_on(1026);
53541  
53542         ok($tf->start_proc == 0, "Starting lighttpd") or die();
53543  
53544 @@ -223,7 +223,7 @@
53545  }
53546  
53547  SKIP: {
53548 -       skip "no php found", 4 unless -x "/home/jan/Documents/php-5.1.0/sapi/cgi/php"; 
53549 +       skip "no php found", 4 unless -x "/home/jan/Documents/php-5.1.4/sapi/cgi/php";
53550         $tf->{CONFIGFILE} = 'fastcgi-13.conf';
53551         ok($tf->start_proc == 0, "Starting lighttpd with $tf->{CONFIGFILE}") or die();
53552         $t->{REQUEST}  = ( <<EOF
53553 @@ -285,6 +285,34 @@
53554         $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => 'test123' } ];
53555         ok($tf->handle_http($t) == 0, 'line-ending \r\n + \r\n');
53556  
53557 +    # X-LIGHTTPD-send-file
53558 +       $t->{REQUEST}  = ( <<EOF
53559 +GET /index.fcgi?x-lighttpd-send-file HTTP/1.0
53560 +Host: www.example.org
53561 +EOF
53562 + );
53563 +       $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
53564 +' } ];
53565 +       ok($tf->handle_http($t) == 0, 'X-LIGHTTPD-send-file');
53566 +    # X-Sendfile
53567 +       $t->{REQUEST}  = ( <<EOF
53568 +GET /index.fcgi?xsendfile HTTP/1.0
53569 +Host: www.example.org
53570 +EOF
53571 + );
53572 +       $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
53573 +' } ];
53574 +       ok($tf->handle_http($t) == 0, 'X-Sendfile');
53575 +
53576 +       $t->{REQUEST}  = ( <<EOF
53577 +GET /index.fcgi?xsendfile-mixed-case HTTP/1.0
53578 +Host: www.example.org
53579 +EOF
53580 + );
53581 +       $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
53582 +' } ];
53583 +       ok($tf->handle_http($t) == 0, 'X-SeNdFiLe in mixed case');
53584 +
53585         $t->{REQUEST}  = ( <<EOF
53586  GET /index.fcgi?die-at-end HTTP/1.0
53587  Host: www.example.org
53588 --- ../lighttpd-1.4.11/tests/mod-proxy.t        1970-01-01 03:00:00.000000000 +0300
53589 +++ lighttpd-1.4.12/tests/mod-proxy.t   2006-07-18 13:03:40.000000000 +0300
53590 @@ -0,0 +1,175 @@
53591 +#!/usr/bin/env perl
53592 +BEGIN {
53593 +    # add current source dir to the include-path
53594 +    # we need this for make distcheck
53595 +   (my $srcdir = $0) =~ s#/[^/]+$#/#;
53596 +   unshift @INC, $srcdir;
53597 +}
53598 +
53599 +use strict;
53600 +use IO::Socket;
53601 +use Test::More tests => 21;
53602 +use LightyTest;
53603 +
53604 +my $tf_proxy = LightyTest->new();
53605 +my $tf_backend1 = LightyTest->new();
53606 +my $tf_backend2 = LightyTest->new();
53607 +
53608 +my $t;
53609 +
53610 +## we need two procs
53611 +## 1. the real webserver
53612 +## 2. the proxy server
53613 +
53614 +SKIP: {
53615 +  skip "disabled for now", 21;
53616 +$tf_proxy->{PORT} = 2048;
53617 +$tf_proxy->{CONFIGFILE} = 'proxy.conf';
53618 +$tf_proxy->{LIGHTTPD_PIDFILE} = $tf_proxy->{SRCDIR}.'/tmp/lighttpd/lighttpd-proxy.pid';
53619 +
53620 +$tf_backend1->{PORT} = 2050;
53621 +$tf_backend1->{CONFIGFILE} = 'proxy-backend-1.conf';
53622 +$tf_backend1->{LIGHTTPD_PIDFILE} = $tf_backend1->{SRCDIR}.'/tmp/lighttpd/lighttpd-backend-1.pid';
53623 +
53624 +$tf_backend2->{PORT} = 2051;
53625 +$tf_backend2->{CONFIGFILE} = 'proxy-backend-2.conf';
53626 +$tf_backend2->{LIGHTTPD_PIDFILE} = $tf_backend2->{SRCDIR}.'/tmp/lighttpd/lighttpd-backend-2.pid';
53627 +
53628 +
53629 +ok($tf_backend1->start_proc == 0, "Starting lighttpd") or die();
53630 +
53631 +ok($tf_proxy->start_proc == 0, "Starting lighttpd as proxy") or die();
53632 +
53633 +sleep(1);
53634 +
53635 +$t->{REQUEST}  = ( <<EOF
53636 +GET /index.html HTTP/1.0
53637 +Host: www.example.org
53638 +EOF
53639 + );
53640 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53641 +ok($tf_proxy->handle_http($t) == 0, 'valid request');
53642 +
53643 +$t->{REQUEST}  = ( <<EOF
53644 +GET /index.html HTTP/1.0
53645 +Host: www.example.org
53646 +EOF
53647 + );
53648 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Server' => 'proxy-backend-1' } ];
53649 +ok($tf_proxy->handle_http($t) == 0, 'drop Server from real server');
53650 +
53651 +$t->{REQUEST}  = ( <<EOF
53652 +GET /balance-rr/foo HTTP/1.0
53653 +Host: www.example.org
53654 +EOF
53655 + );
53656 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53657 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - one backend');
53658 +
53659 +$t->{REQUEST}  = ( <<EOF
53660 +GET /balance-rr/foo HTTP/1.0
53661 +Host: www.example.org
53662 +EOF
53663 + );
53664 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53665 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - one host down, failover');
53666 +
53667 +$t->{REQUEST}  = ( <<EOF
53668 +GET /balance-fair/foo HTTP/1.0
53669 +Host: www.example.org
53670 +EOF
53671 + );
53672 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53673 +ok($tf_proxy->handle_http($t) == 0, 'balance fair - one backend');
53674 +
53675 +## backend 2 starting 
53676 +ok($tf_backend2->start_proc == 0, "Starting second proxy backend") or die();
53677 +
53678 +$t->{REQUEST}  = ( <<EOF
53679 +GET /balance-rr/foo HTTP/1.0
53680 +Host: www.example.org
53681 +EOF
53682 + );
53683 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53684 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - lb, backend 1');
53685 +
53686 +$t->{REQUEST}  = ( <<EOF
53687 +GET /balance-rr/foo HTTP/1.0
53688 +Host: www.example.org
53689 +EOF
53690 + );
53691 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53692 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - lb, backend 2');
53693 +
53694 +$t->{REQUEST}  = ( <<EOF
53695 +GET /balance-hash/foo HTTP/1.0
53696 +Host: www.example.org
53697 +EOF
53698 + );
53699 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53700 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 1');
53701 +
53702 +$t->{REQUEST}  = ( <<EOF
53703 +GET /balance-hash/foo HTTP/1.0
53704 +Host: www.example.org
53705 +EOF
53706 + );
53707 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53708 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 1 - same URL');
53709 +
53710 +$t->{REQUEST}  = ( <<EOF
53711 +GET /balance-hash/bar HTTP/1.0
53712 +Host: www.example.org
53713 +EOF
53714 + );
53715 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53716 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 2');
53717 +
53718 +$t->{REQUEST}  = ( <<EOF
53719 +GET /balance-hash/bar HTTP/1.0
53720 +Host: www.example.org
53721 +EOF
53722 + );
53723 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53724 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 2 - same URL');
53725 +
53726 +## backend 1 stopping, failover 
53727 +ok($tf_backend1->stop_proc == 0, "Stopping backend 1");
53728 +
53729 +$t->{REQUEST}  = ( <<EOF
53730 +GET /balance-hash/foo HTTP/1.0
53731 +Host: www.example.org
53732 +EOF
53733 + );
53734 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53735 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - failover to backend 2');
53736 +
53737 +$t->{REQUEST}  = ( <<EOF
53738 +GET /balance-hash/bar HTTP/1.0
53739 +Host: www.example.org
53740 +EOF
53741 + );
53742 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53743 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - failover to backend 2 - same URL');
53744 +
53745 +$t->{REQUEST}  = ( <<EOF
53746 +GET /balance-rr/foo HTTP/1.0
53747 +Host: www.example.org
53748 +EOF
53749 + );
53750 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53751 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - failover to backend 2');
53752 +
53753 +$t->{REQUEST}  = ( <<EOF
53754 +GET /balance-fair/foo HTTP/1.0
53755 +Host: www.example.org
53756 +EOF
53757 + );
53758 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53759 +ok($tf_proxy->handle_http($t) == 0, 'balance fair - failover to backend 2');
53760 +
53761 +
53762 +ok($tf_backend2->stop_proc == 0, "Stopping lighttpd");
53763 +
53764 +ok($tf_proxy->stop_proc == 0, "Stopping lighttpd proxy");
53765 +}
53766 --- ../lighttpd-1.4.11/tests/proxy-backend-1.conf       1970-01-01 03:00:00.000000000 +0300
53767 +++ lighttpd-1.4.12/tests/proxy-backend-1.conf  2006-07-16 00:26:05.000000000 +0300
53768 @@ -0,0 +1,7 @@
53769 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53770 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd-backend-1.pid"
53771 +
53772 +include "default.conf"
53773 +
53774 +
53775 +server.tag = "proxy-backend-1"
53776 --- ../lighttpd-1.4.11/tests/proxy-backend-2.conf       1970-01-01 03:00:00.000000000 +0300
53777 +++ lighttpd-1.4.12/tests/proxy-backend-2.conf  2006-07-16 00:26:04.000000000 +0300
53778 @@ -0,0 +1,7 @@
53779 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53780 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd-backend-2.pid"
53781 +
53782 +include "default.conf"
53783 +
53784 +
53785 +server.tag = "proxy-backend-2"
53786 --- ../lighttpd-1.4.11/tests/proxy.conf 1970-01-01 03:00:00.000000000 +0300
53787 +++ lighttpd-1.4.12/tests/proxy.conf    2006-07-16 00:26:05.000000000 +0300
53788 @@ -0,0 +1,26 @@
53789 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53790 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd-proxy.pid"
53791 +server.tag = "proxy"
53792 +
53793 +include "default.conf"
53794 +
53795 +## 127.0.0.1 and 127.0.0.2 are the same host
53796 +proxy.server              = ( 
53797 +  "" => (( "host" => "127.0.0.1",
53798 +          "port" => 2050 ),
53799 +         ( "host" => "127.0.0.2",
53800 +           "port" => 2051 )
53801 +  ))
53802 +               
53803 +$HTTP["url"] =~ "^/balance-rr/" {
53804 +  proxy.balance = "round-robin"
53805 +}
53806 +
53807 +$HTTP["url"] =~ "^/balance-hash/" {
53808 +  proxy.balance = "hash"
53809 +}
53810 +
53811 +$HTTP["url"] =~ "^/balance-fair/" {
53812 +  proxy.balance = "fair"
53813 +}
53814 +
53815 --- ../lighttpd-1.4.11/tests/var-include.conf   2005-08-27 17:44:19.000000000 +0300
53816 +++ lighttpd-1.4.12/tests/var-include.conf      2006-07-16 00:26:05.000000000 +0300
53817 @@ -2,15 +2,15 @@
53818  debug.log-request-handling = "enable"
53819  debug.log-condition-handling = "enable"
53820  
53821 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53822 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
53823 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53824 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53825  
53826  ## bind to port (default: 80)
53827  server.port                 = 2048
53828  
53829  ## bind to localhost (default: all interfaces)
53830  server.bind                = "localhost"
53831 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
53832 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53833  server.name                = "www.example.org"
53834  server.tag                 = "Apache 1.3.29"
53835  
53836 @@ -21,19 +21,19 @@
53837  ######################## MODULE CONFIG ############################
53838  
53839  
53840 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
53841 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
53842  
53843  mimetype.assign             = ( ".html" => "text/html" )
53844  
53845  url.redirect = ("^" => "/default")
53846  
53847  $HTTP["host"] == "www.example.org" {
53848 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53849 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53850    server.name = "www.example.org"
53851    url.redirect = ("^" => "/redirect")
53852  }
53853  $HTTP["host"] == "test.example.org" {
53854 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53855 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53856    server.name = "test.example.org"
53857    var.myvar = "good"
53858    var.one = 1
This page took 5.185498 seconds and 4 git commands to generate.