]> git.pld-linux.org Git - packages/lighttpd.git/blob - lighttpd-branch.diff
- svn 1211: fixes nasty crash in mod_cgi
[packages/lighttpd.git] / lighttpd-branch.diff
1 --- ../lighttpd-1.4.11/NEWS     2006-03-09 19:34:33.000000000 +0200
2 +++ lighttpd-1.4.12/NEWS        2006-07-16 00:26:05.000000000 +0300
3 @@ -3,6 +3,23 @@
4  NEWS
5  ====
6  
7 +- 1.4.12 - 2006-..-..
8 +
9 +  * added handling of Content-Range to PUT requests in mod_webdav
10 +  * added handling of ETag and If-Modified-Since to mod_compress if 
11 +    cache-dir is not set
12 +  * added experimental LOCK support for mod_webdav 
13 +  * added support for X-Sendfile as addition to X-LIGHTTPD-send-file.
14 +    This allows compatibility with mod_xsendfile for apache
15 +    (http://celebnamer.celebworld.ws/stuff/mod_xsendfile/)
16 +  * fixed handling of If-Modified-Since if Etag is not set
17 +  * fixed hanging fastcgi connections
18 +  * fixed stalling SSL POST requests 
19 +  * fixed round-robin load-balancing in mod_proxy
20 +  * TODO: add fail-over to mod-proxy
21 +  * TODO: fix CACHE_HIT/MISS in mod_cml
22 +  * TODO: finish LOCK/UNLOCK in mod_webdav
23 +
24  - 1.4.11 - 2006-03-09
25  
26    * added ability to specify which ip address spawn-fci listens on 
27 --- ../lighttpd-1.4.11/configure.in     2006-03-04 16:32:38.000000000 +0200
28 +++ lighttpd-1.4.12/configure.in        2006-07-19 20:02:55.000000000 +0300
29 @@ -1,7 +1,7 @@
30  #                                               -*- Autoconf -*-
31  # Process this file with autoconf to produce a configure script.
32  AC_PREREQ(2.57)
33 -AC_INIT(lighttpd, 1.4.11, jan@kneschke.de)
34 +AC_INIT(lighttpd, 1.4.12, jan@kneschke.de)
35  AC_CONFIG_SRCDIR([src/server.c])
36  
37  AC_CANONICAL_TARGET
38 @@ -66,7 +66,7 @@
39  AC_TYPE_PID_T
40  AC_TYPE_SIZE_T
41  
42 -AC_CHECK_MEMBER(struct tm.tm_gmtoff,AC_DEFINE([HAVE_STRUCT_TM_GMTOFF],[1],[gmtoff in struct tm]),,[#include <time.h>])
43 +AC_CHECK_MEMBER(struct tm.tm_gmtoff,[AC_DEFINE([HAVE_STRUCT_TM_GMTOFF],[1],[gmtoff in struct tm])],,[#include <time.h>])
44  AC_CHECK_TYPES(struct sockaddr_storage,,,[#include <sys/socket.h>])
45  AC_CHECK_TYPES(socklen_t,,,[#include <sys/types.h>
46  #include <sys/socket.h>])
47 @@ -339,6 +339,22 @@
48      AC_DEFINE([HAVE_SQLITE3], [1], [libsqlite3])
49      AC_DEFINE([HAVE_SQLITE3_H], [1], [sqlite3.h])
50   ])
51 +
52 + AC_MSG_CHECKING(for locks in mod_webdav)
53 + AC_ARG_WITH(webdav-locks, AC_HELP_STRING([--with-webdav-locks],[locks in mod_webdav]),
54 + [WITH_WEBDAV_LOCKS=$withval],[WITH_WEBDAV_LOCKS=no])
55 + AC_MSG_RESULT([$WITH_WEBDAV_LOCKS])
56 +
57 + if test "$WITH_WEBDAV_LOCKS" != "no"; then
58 +   AC_CHECK_LIB(uuid, uuid_unparse, [
59 +         AC_CHECK_HEADERS([uuid/uuid.h],[
60 +                 UUID_LIB=-luuid
61 +                 AC_DEFINE([HAVE_UUID], [1], [libuuid])
62 +                AC_DEFINE([HAVE_UUID_H], [1], [uuid/uuid.h is available])
63 +         ])
64 + ])
65 +
66 + fi
67  fi
68  
69  dnl Check for gdbm
70 @@ -381,30 +397,11 @@
71  
72  AC_MSG_RESULT($WITH_LUA)
73  if test "$WITH_LUA" != "no"; then
74 - AC_PATH_PROG(LUACONFIG, lua-config)
75 -
76 - if test x"$LUACONFIG" != x; then
77 -   LUA_CFLAGS=`$LUACONFIG --include`
78 -   LUA_LIBS=`$LUACONFIG --libs --extralibs`
79 + # try pkgconfig
80 + PKG_CHECK_MODULES(LUA, lua >= 5.1, [
81     AC_DEFINE([HAVE_LUA], [1], [liblua])
82     AC_DEFINE([HAVE_LUA_H], [1], [lua.h])
83 - else
84 -   AC_CHECK_LIB(lua, lua_open, [
85 -     AC_CHECK_HEADERS([lua.h],[
86 -       LUA_LIBS="-llua -llualib"
87 -       AC_DEFINE([HAVE_LUA], [1], [liblua])
88 -       AC_DEFINE([HAVE_LUA_H], [1], [lua.h])
89 -     ])
90 -   ])
91 - fi
92 -
93 - if test x"$LUA_LIBS" = x; then
94 -   # try pkgconfig
95 -   PKG_CHECK_MODULES(LUA, lua, [
96 -     AC_DEFINE([HAVE_LUA], [1], [liblua])
97 -     AC_DEFINE([HAVE_LUA_H], [1], [lua.h])
98 -   ])
99 - fi
100 + ])
101  
102   AC_SUBST(LUA_CFLAGS)
103   AC_SUBST(LUA_LIBS)
104 @@ -440,8 +437,8 @@
105  esac
106  
107  AC_CHECK_FUNCS([dup2 getcwd inet_ntoa inet_ntop memset mmap munmap strchr \
108 -                 strdup strerror strstr strtol sendfile  getopt socket \
109 -                 gethostbyname poll sigtimedwait epoll_ctl getrlimit chroot \
110 +                 strdup strerror strstr strtol sendfile  getopt socket lstat \
111 +                 gethostbyname poll sigtimedwait epoll_ctl getrlimit chroot strptime \
112                   getuid select signal pathconf madvise posix_fadvise posix_madvise \
113                   writev sigaction sendfile64 send_file kqueue port_create localtime_r])
114  
115 @@ -519,7 +516,7 @@
116  
117  
118  if test "${GCC}" = "yes"; then
119 -       CFLAGS="${CFLAGS} -Wall -W -Wshadow -pedantic"
120 +       CFLAGS="${CFLAGS} -Wall -W -Wshadow -pedantic -std=gnu99"
121  fi
122  
123  dnl build version-id
124 @@ -538,7 +535,7 @@
125  AC_OUTPUT
126  
127  
128 -do_build="mod_cgi mod_fastcgi mod_proxy mod_evhost mod_simple_vhost mod_access mod_alias mod_setenv mod_usertrack mod_auth mod_status mod_accesslog mod_rrdtool mod_secdownload mod_expire mod_compress mod_dirlisting mod_indexfiles mod_userdir mod_webdav mod_staticfile mod_scgi" 
129 +do_build="mod_cgi mod_fastcgi mod_proxy mod_evhost mod_simple_vhost mod_access mod_alias mod_setenv mod_usertrack mod_auth mod_status mod_accesslog mod_rrdtool mod_secdownload mod_expire mod_compress mod_dirlisting mod_indexfiles mod_userdir mod_webdav mod_staticfile mod_scgi mod_flv_streaming" 
130  
131  plugins="mod_rewrite mod_redirect mod_ssi mod_trigger_b4_dl"
132  features="regex-conditionals"
133 @@ -642,6 +639,14 @@
134         disable_feature="$disable_feature $features"
135  fi
136  
137 +features="webdav-locks"
138 +if test "x$UUID_LIB" \!= x; then
139 +       enable_feature="$enable_feature $features"
140 +else
141 +       disable_feature="$disable_feature $features"
142 +fi
143 +
144 +
145  ## output
146  
147  $ECHO
148 --- ../lighttpd-1.4.11/cygwin/lighttpd.README   2006-03-07 14:22:19.000000000 +0200
149 +++ lighttpd-1.4.12/cygwin/lighttpd.README      2006-07-19 20:09:00.000000000 +0300
150 @@ -1,114 +1,114 @@
151 -lighttpd\r
152 -------------------------------------------\r
153 -A fast, secure and flexible webserver\r
154 -\r
155 -Runtime requirements:\r
156 -  cygwin-1.5.10 or newer\r
157 -  crypt-1.1 or newer\r
158 -  libbz2_1-1.0.2 or newer\r
159 -  libpcre0-4.5 or newer\r
160 -  openssl-0.9.7d or newer\r
161 -  zlib-1.2.1 or newer\r
162 -\r
163 -Build requirements:\r
164 -  cygwin-1.5.10 or newer\r
165 -  gcc-3.3.1-3 or newer\r
166 -  binutils-20030901-1 or newer\r
167 -  crypt\r
168 -  openssl-devel\r
169 -  openssl\r
170 -  openldap\r
171 -  openldap-devel\r
172 -  zlib\r
173 -  bzip2\r
174 -\r
175 -Canonical homepage:\r
176 -  http://jan.kneschke.de/projects/lighttpd/\r
177 -\r
178 -Canonical download:\r
179 -  http://jan.kneschke.de/projects/lighttpd/download\r
180 -\r
181 -------------------------------------\r
182 -\r
183 -Build instructions:\r
184 -  unpack lighttpd-1.4.11-<REL>-src.tar.bz2\r
185 -    if you use setup to install this src package, it will be\r
186 -        unpacked under /usr/src automatically\r
187 -  cd /usr/src\r
188 -  ./lighttpd-1.4.11-<REL>.sh all\r
189 -\r
190 -This will create:\r
191 -  /usr/src/lighttpd-1.4.11-<REL>.tar.bz2\r
192 -  /usr/src/lighttpd-1.4.11-<REL>-src.tar.bz2\r
193 -\r
194 -Or use './lighttpd-1.4.11-<REL>.sh prep' to get a patched source directory\r
195 -\r
196 --------------------------------------------\r
197 -\r
198 -Files included in the binary distribution:\r
199 -\r
200 -  /etc/lighttpd/lighttpd.conf.default\r
201 -  /usr/lib/cyglightcomp.dll\r
202 -  /usr/lib/lighttpd/mod_access.dll\r
203 -  /usr/lib/lighttpd/mod_accesslog.dll\r
204 -  /usr/lib/lighttpd/mod_auth.dll\r
205 -  /usr/lib/lighttpd/mod_cgi.dll\r
206 -  /usr/lib/lighttpd/mod_compress.dll\r
207 -  /usr/lib/lighttpd/mod_evhost.dll\r
208 -  /usr/lib/lighttpd/mod_expire.dll\r
209 -  /usr/lib/lighttpd/mod_fastcgi.dll\r
210 -  /usr/lib/lighttpd/mod_httptls.dll\r
211 -  /usr/lib/lighttpd/mod_maps.dll\r
212 -  /usr/lib/lighttpd/mod_proxy.dll\r
213 -  /usr/lib/lighttpd/mod_redirect.dll\r
214 -  /usr/lib/lighttpd/mod_rewrite.dll\r
215 -  /usr/lib/lighttpd/mod_rrdtool.dll\r
216 -  /usr/lib/lighttpd/mod_secdownload.dll\r
217 -  /usr/lib/lighttpd/mod_simple_vhost.dll\r
218 -  /usr/lib/lighttpd/mod_ssi.dll\r
219 -  /usr/lib/lighttpd/mod_status.dll\r
220 -  /usr/lib/lighttpd/mod_usertrack.dll\r
221 -  /usr/sbin/lighttpd.exe\r
222 -  /usr/share/doc/Cygwin/lighttpd-1.3.0.README\r
223 -  /usr/share/doc/lighttpd-1.3.0/accesslog.txt\r
224 -  /usr/share/doc/lighttpd-1.3.0/authentification.txt\r
225 -  /usr/share/doc/lighttpd-1.3.0/AUTHORS\r
226 -  /usr/share/doc/lighttpd-1.3.0/cgi.txt\r
227 -  /usr/share/doc/lighttpd-1.3.0/ChangeLog\r
228 -  /usr/share/doc/lighttpd-1.3.0/compress.txt\r
229 -  /usr/share/doc/lighttpd-1.3.0/configuration.txt\r
230 -  /usr/share/doc/lighttpd-1.3.0/COPYING\r
231 -  /usr/share/doc/lighttpd-1.3.0/fastcgi-state.txt\r
232 -  /usr/share/doc/lighttpd-1.3.0/fastcgi.txt\r
233 -  /usr/share/doc/lighttpd-1.3.0/features.txt\r
234 -  /usr/share/doc/lighttpd-1.3.0/INSTALL\r
235 -  /usr/share/doc/lighttpd-1.3.0/NEWS\r
236 -  /usr/share/doc/lighttpd-1.3.0/performance.txt\r
237 -  /usr/share/doc/lighttpd-1.3.0/plugins.txt\r
238 -  /usr/share/doc/lighttpd-1.3.0/proxy.txt\r
239 -  /usr/share/doc/lighttpd-1.3.0/README\r
240 -  /usr/share/doc/lighttpd-1.3.0/redirect.txt\r
241 -  /usr/share/doc/lighttpd-1.3.0/rewrite.txt\r
242 -  /usr/share/doc/lighttpd-1.3.0/rrdtool.txt\r
243 -  /usr/share/doc/lighttpd-1.3.0/secdownload.txt\r
244 -  /usr/share/doc/lighttpd-1.3.0/security.txt\r
245 -  /usr/share/doc/lighttpd-1.3.0/simple-vhost.txt\r
246 -  /usr/share/doc/lighttpd-1.3.0/skeleton.txt\r
247 -  /usr/share/doc/lighttpd-1.3.0/ssi.txt\r
248 -  /usr/share/doc/lighttpd-1.3.0/state.txt\r
249 -  /usr/share/man/man1/lighttpd.1.gz\r
250 -\r
251 -------------------\r
252 -\r
253 -Port Notes:\r
254 -\r
255 -----------  lighttpd-1.3.1-1 -----------\r
256 -\r
257 -Updated to 1.3.1\r
258 -\r
259 -----------  lighttpd-1.3.0-1 -----------\r
260 -Initial release\r
261 -\r
262 -Cygwin port maintained by: Jan Kneschke <jan@kneschke.de>\r
263 -Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com>\r
264 -\r
265 +lighttpd
266 +------------------------------------------
267 +A fast, secure and flexible webserver
268 +
269 +Runtime requirements:
270 +  cygwin-1.5.10 or newer
271 +  crypt-1.1 or newer
272 +  libbz2_1-1.0.2 or newer
273 +  libpcre0-4.5 or newer
274 +  openssl-0.9.7d or newer
275 +  zlib-1.2.1 or newer
276 +
277 +Build requirements:
278 +  cygwin-1.5.10 or newer
279 +  gcc-3.3.1-3 or newer
280 +  binutils-20030901-1 or newer
281 +  crypt
282 +  openssl-devel
283 +  openssl
284 +  openldap
285 +  openldap-devel
286 +  zlib
287 +  bzip2
288 +
289 +Canonical homepage:
290 +  http://jan.kneschke.de/projects/lighttpd/
291 +
292 +Canonical download:
293 +  http://jan.kneschke.de/projects/lighttpd/download
294 +
295 +------------------------------------
296 +
297 +Build instructions:
298 +  unpack lighttpd-1.4.12-<REL>-src.tar.bz2
299 +    if you use setup to install this src package, it will be
300 +        unpacked under /usr/src automatically
301 +  cd /usr/src
302 +  ./lighttpd-1.4.12-<REL>.sh all
303 +
304 +This will create:
305 +  /usr/src/lighttpd-1.4.12-<REL>.tar.bz2
306 +  /usr/src/lighttpd-1.4.12-<REL>-src.tar.bz2
307 +
308 +Or use './lighttpd-1.4.12-<REL>.sh prep' to get a patched source directory
309 +
310 +-------------------------------------------
311 +
312 +Files included in the binary distribution:
313 +
314 +  /etc/lighttpd/lighttpd.conf.default
315 +  /usr/lib/cyglightcomp.dll
316 +  /usr/lib/lighttpd/mod_access.dll
317 +  /usr/lib/lighttpd/mod_accesslog.dll
318 +  /usr/lib/lighttpd/mod_auth.dll
319 +  /usr/lib/lighttpd/mod_cgi.dll
320 +  /usr/lib/lighttpd/mod_compress.dll
321 +  /usr/lib/lighttpd/mod_evhost.dll
322 +  /usr/lib/lighttpd/mod_expire.dll
323 +  /usr/lib/lighttpd/mod_fastcgi.dll
324 +  /usr/lib/lighttpd/mod_httptls.dll
325 +  /usr/lib/lighttpd/mod_maps.dll
326 +  /usr/lib/lighttpd/mod_proxy.dll
327 +  /usr/lib/lighttpd/mod_redirect.dll
328 +  /usr/lib/lighttpd/mod_rewrite.dll
329 +  /usr/lib/lighttpd/mod_rrdtool.dll
330 +  /usr/lib/lighttpd/mod_secdownload.dll
331 +  /usr/lib/lighttpd/mod_simple_vhost.dll
332 +  /usr/lib/lighttpd/mod_ssi.dll
333 +  /usr/lib/lighttpd/mod_status.dll
334 +  /usr/lib/lighttpd/mod_usertrack.dll
335 +  /usr/sbin/lighttpd.exe
336 +  /usr/share/doc/Cygwin/lighttpd-1.3.0.README
337 +  /usr/share/doc/lighttpd-1.3.0/accesslog.txt
338 +  /usr/share/doc/lighttpd-1.3.0/authentification.txt
339 +  /usr/share/doc/lighttpd-1.3.0/AUTHORS
340 +  /usr/share/doc/lighttpd-1.3.0/cgi.txt
341 +  /usr/share/doc/lighttpd-1.3.0/ChangeLog
342 +  /usr/share/doc/lighttpd-1.3.0/compress.txt
343 +  /usr/share/doc/lighttpd-1.3.0/configuration.txt
344 +  /usr/share/doc/lighttpd-1.3.0/COPYING
345 +  /usr/share/doc/lighttpd-1.3.0/fastcgi-state.txt
346 +  /usr/share/doc/lighttpd-1.3.0/fastcgi.txt
347 +  /usr/share/doc/lighttpd-1.3.0/features.txt
348 +  /usr/share/doc/lighttpd-1.3.0/INSTALL
349 +  /usr/share/doc/lighttpd-1.3.0/NEWS
350 +  /usr/share/doc/lighttpd-1.3.0/performance.txt
351 +  /usr/share/doc/lighttpd-1.3.0/plugins.txt
352 +  /usr/share/doc/lighttpd-1.3.0/proxy.txt
353 +  /usr/share/doc/lighttpd-1.3.0/README
354 +  /usr/share/doc/lighttpd-1.3.0/redirect.txt
355 +  /usr/share/doc/lighttpd-1.3.0/rewrite.txt
356 +  /usr/share/doc/lighttpd-1.3.0/rrdtool.txt
357 +  /usr/share/doc/lighttpd-1.3.0/secdownload.txt
358 +  /usr/share/doc/lighttpd-1.3.0/security.txt
359 +  /usr/share/doc/lighttpd-1.3.0/simple-vhost.txt
360 +  /usr/share/doc/lighttpd-1.3.0/skeleton.txt
361 +  /usr/share/doc/lighttpd-1.3.0/ssi.txt
362 +  /usr/share/doc/lighttpd-1.3.0/state.txt
363 +  /usr/share/man/man1/lighttpd.1.gz
364 +
365 +------------------
366 +
367 +Port Notes:
368 +
369 +----------  lighttpd-1.3.1-1 -----------
370 +
371 +Updated to 1.3.1
372 +
373 +----------  lighttpd-1.3.0-1 -----------
374 +Initial release
375 +
376 +Cygwin port maintained by: Jan Kneschke <jan@kneschke.de>
377 +Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com>
378 +
379 --- ../lighttpd-1.4.11/cygwin/lighttpd.README.in        2005-08-11 01:26:59.000000000 +0300
380 +++ lighttpd-1.4.12/cygwin/lighttpd.README.in   2006-07-16 00:26:04.000000000 +0300
381 @@ -1,114 +1,114 @@
382 -lighttpd\r
383 -------------------------------------------\r
384 -A fast, secure and flexible webserver\r
385 -\r
386 -Runtime requirements:\r
387 -  cygwin-1.5.10 or newer\r
388 -  crypt-1.1 or newer\r
389 -  libbz2_1-1.0.2 or newer\r
390 -  libpcre0-4.5 or newer\r
391 -  openssl-0.9.7d or newer\r
392 -  zlib-1.2.1 or newer\r
393 -\r
394 -Build requirements:\r
395 -  cygwin-1.5.10 or newer\r
396 -  gcc-3.3.1-3 or newer\r
397 -  binutils-20030901-1 or newer\r
398 -  crypt\r
399 -  openssl-devel\r
400 -  openssl\r
401 -  openldap\r
402 -  openldap-devel\r
403 -  zlib\r
404 -  bzip2\r
405 -\r
406 -Canonical homepage:\r
407 -  http://jan.kneschke.de/projects/lighttpd/\r
408 -\r
409 -Canonical download:\r
410 -  http://jan.kneschke.de/projects/lighttpd/download\r
411 -\r
412 -------------------------------------\r
413 -\r
414 -Build instructions:\r
415 -  unpack lighttpd-@VERSION@-<REL>-src.tar.bz2\r
416 -    if you use setup to install this src package, it will be\r
417 -        unpacked under /usr/src automatically\r
418 -  cd /usr/src\r
419 -  ./lighttpd-@VERSION@-<REL>.sh all\r
420 -\r
421 -This will create:\r
422 -  /usr/src/lighttpd-@VERSION@-<REL>.tar.bz2\r
423 -  /usr/src/lighttpd-@VERSION@-<REL>-src.tar.bz2\r
424 -\r
425 -Or use './lighttpd-@VERSION@-<REL>.sh prep' to get a patched source directory\r
426 -\r
427 --------------------------------------------\r
428 -\r
429 -Files included in the binary distribution:\r
430 -\r
431 -  /etc/lighttpd/lighttpd.conf.default\r
432 -  /usr/lib/cyglightcomp.dll\r
433 -  /usr/lib/lighttpd/mod_access.dll\r
434 -  /usr/lib/lighttpd/mod_accesslog.dll\r
435 -  /usr/lib/lighttpd/mod_auth.dll\r
436 -  /usr/lib/lighttpd/mod_cgi.dll\r
437 -  /usr/lib/lighttpd/mod_compress.dll\r
438 -  /usr/lib/lighttpd/mod_evhost.dll\r
439 -  /usr/lib/lighttpd/mod_expire.dll\r
440 -  /usr/lib/lighttpd/mod_fastcgi.dll\r
441 -  /usr/lib/lighttpd/mod_httptls.dll\r
442 -  /usr/lib/lighttpd/mod_maps.dll\r
443 -  /usr/lib/lighttpd/mod_proxy.dll\r
444 -  /usr/lib/lighttpd/mod_redirect.dll\r
445 -  /usr/lib/lighttpd/mod_rewrite.dll\r
446 -  /usr/lib/lighttpd/mod_rrdtool.dll\r
447 -  /usr/lib/lighttpd/mod_secdownload.dll\r
448 -  /usr/lib/lighttpd/mod_simple_vhost.dll\r
449 -  /usr/lib/lighttpd/mod_ssi.dll\r
450 -  /usr/lib/lighttpd/mod_status.dll\r
451 -  /usr/lib/lighttpd/mod_usertrack.dll\r
452 -  /usr/sbin/lighttpd.exe\r
453 -  /usr/share/doc/Cygwin/lighttpd-1.3.0.README\r
454 -  /usr/share/doc/lighttpd-1.3.0/accesslog.txt\r
455 -  /usr/share/doc/lighttpd-1.3.0/authentification.txt\r
456 -  /usr/share/doc/lighttpd-1.3.0/AUTHORS\r
457 -  /usr/share/doc/lighttpd-1.3.0/cgi.txt\r
458 -  /usr/share/doc/lighttpd-1.3.0/ChangeLog\r
459 -  /usr/share/doc/lighttpd-1.3.0/compress.txt\r
460 -  /usr/share/doc/lighttpd-1.3.0/configuration.txt\r
461 -  /usr/share/doc/lighttpd-1.3.0/COPYING\r
462 -  /usr/share/doc/lighttpd-1.3.0/fastcgi-state.txt\r
463 -  /usr/share/doc/lighttpd-1.3.0/fastcgi.txt\r
464 -  /usr/share/doc/lighttpd-1.3.0/features.txt\r
465 -  /usr/share/doc/lighttpd-1.3.0/INSTALL\r
466 -  /usr/share/doc/lighttpd-1.3.0/NEWS\r
467 -  /usr/share/doc/lighttpd-1.3.0/performance.txt\r
468 -  /usr/share/doc/lighttpd-1.3.0/plugins.txt\r
469 -  /usr/share/doc/lighttpd-1.3.0/proxy.txt\r
470 -  /usr/share/doc/lighttpd-1.3.0/README\r
471 -  /usr/share/doc/lighttpd-1.3.0/redirect.txt\r
472 -  /usr/share/doc/lighttpd-1.3.0/rewrite.txt\r
473 -  /usr/share/doc/lighttpd-1.3.0/rrdtool.txt\r
474 -  /usr/share/doc/lighttpd-1.3.0/secdownload.txt\r
475 -  /usr/share/doc/lighttpd-1.3.0/security.txt\r
476 -  /usr/share/doc/lighttpd-1.3.0/simple-vhost.txt\r
477 -  /usr/share/doc/lighttpd-1.3.0/skeleton.txt\r
478 -  /usr/share/doc/lighttpd-1.3.0/ssi.txt\r
479 -  /usr/share/doc/lighttpd-1.3.0/state.txt\r
480 -  /usr/share/man/man1/lighttpd.1.gz\r
481 -\r
482 -------------------\r
483 -\r
484 -Port Notes:\r
485 -\r
486 -----------  lighttpd-1.3.1-1 -----------\r
487 -\r
488 -Updated to 1.3.1\r
489 -\r
490 -----------  lighttpd-1.3.0-1 -----------\r
491 -Initial release\r
492 -\r
493 -Cygwin port maintained by: Jan Kneschke <jan@kneschke.de>\r
494 -Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com>\r
495 -\r
496 +lighttpd
497 +------------------------------------------
498 +A fast, secure and flexible webserver
499 +
500 +Runtime requirements:
501 +  cygwin-1.5.10 or newer
502 +  crypt-1.1 or newer
503 +  libbz2_1-1.0.2 or newer
504 +  libpcre0-4.5 or newer
505 +  openssl-0.9.7d or newer
506 +  zlib-1.2.1 or newer
507 +
508 +Build requirements:
509 +  cygwin-1.5.10 or newer
510 +  gcc-3.3.1-3 or newer
511 +  binutils-20030901-1 or newer
512 +  crypt
513 +  openssl-devel
514 +  openssl
515 +  openldap
516 +  openldap-devel
517 +  zlib
518 +  bzip2
519 +
520 +Canonical homepage:
521 +  http://jan.kneschke.de/projects/lighttpd/
522 +
523 +Canonical download:
524 +  http://jan.kneschke.de/projects/lighttpd/download
525 +
526 +------------------------------------
527 +
528 +Build instructions:
529 +  unpack lighttpd-@VERSION@-<REL>-src.tar.bz2
530 +    if you use setup to install this src package, it will be
531 +        unpacked under /usr/src automatically
532 +  cd /usr/src
533 +  ./lighttpd-@VERSION@-<REL>.sh all
534 +
535 +This will create:
536 +  /usr/src/lighttpd-@VERSION@-<REL>.tar.bz2
537 +  /usr/src/lighttpd-@VERSION@-<REL>-src.tar.bz2
538 +
539 +Or use './lighttpd-@VERSION@-<REL>.sh prep' to get a patched source directory
540 +
541 +-------------------------------------------
542 +
543 +Files included in the binary distribution:
544 +
545 +  /etc/lighttpd/lighttpd.conf.default
546 +  /usr/lib/cyglightcomp.dll
547 +  /usr/lib/lighttpd/mod_access.dll
548 +  /usr/lib/lighttpd/mod_accesslog.dll
549 +  /usr/lib/lighttpd/mod_auth.dll
550 +  /usr/lib/lighttpd/mod_cgi.dll
551 +  /usr/lib/lighttpd/mod_compress.dll
552 +  /usr/lib/lighttpd/mod_evhost.dll
553 +  /usr/lib/lighttpd/mod_expire.dll
554 +  /usr/lib/lighttpd/mod_fastcgi.dll
555 +  /usr/lib/lighttpd/mod_httptls.dll
556 +  /usr/lib/lighttpd/mod_maps.dll
557 +  /usr/lib/lighttpd/mod_proxy.dll
558 +  /usr/lib/lighttpd/mod_redirect.dll
559 +  /usr/lib/lighttpd/mod_rewrite.dll
560 +  /usr/lib/lighttpd/mod_rrdtool.dll
561 +  /usr/lib/lighttpd/mod_secdownload.dll
562 +  /usr/lib/lighttpd/mod_simple_vhost.dll
563 +  /usr/lib/lighttpd/mod_ssi.dll
564 +  /usr/lib/lighttpd/mod_status.dll
565 +  /usr/lib/lighttpd/mod_usertrack.dll
566 +  /usr/sbin/lighttpd.exe
567 +  /usr/share/doc/Cygwin/lighttpd-1.3.0.README
568 +  /usr/share/doc/lighttpd-1.3.0/accesslog.txt
569 +  /usr/share/doc/lighttpd-1.3.0/authentification.txt
570 +  /usr/share/doc/lighttpd-1.3.0/AUTHORS
571 +  /usr/share/doc/lighttpd-1.3.0/cgi.txt
572 +  /usr/share/doc/lighttpd-1.3.0/ChangeLog
573 +  /usr/share/doc/lighttpd-1.3.0/compress.txt
574 +  /usr/share/doc/lighttpd-1.3.0/configuration.txt
575 +  /usr/share/doc/lighttpd-1.3.0/COPYING
576 +  /usr/share/doc/lighttpd-1.3.0/fastcgi-state.txt
577 +  /usr/share/doc/lighttpd-1.3.0/fastcgi.txt
578 +  /usr/share/doc/lighttpd-1.3.0/features.txt
579 +  /usr/share/doc/lighttpd-1.3.0/INSTALL
580 +  /usr/share/doc/lighttpd-1.3.0/NEWS
581 +  /usr/share/doc/lighttpd-1.3.0/performance.txt
582 +  /usr/share/doc/lighttpd-1.3.0/plugins.txt
583 +  /usr/share/doc/lighttpd-1.3.0/proxy.txt
584 +  /usr/share/doc/lighttpd-1.3.0/README
585 +  /usr/share/doc/lighttpd-1.3.0/redirect.txt
586 +  /usr/share/doc/lighttpd-1.3.0/rewrite.txt
587 +  /usr/share/doc/lighttpd-1.3.0/rrdtool.txt
588 +  /usr/share/doc/lighttpd-1.3.0/secdownload.txt
589 +  /usr/share/doc/lighttpd-1.3.0/security.txt
590 +  /usr/share/doc/lighttpd-1.3.0/simple-vhost.txt
591 +  /usr/share/doc/lighttpd-1.3.0/skeleton.txt
592 +  /usr/share/doc/lighttpd-1.3.0/ssi.txt
593 +  /usr/share/doc/lighttpd-1.3.0/state.txt
594 +  /usr/share/man/man1/lighttpd.1.gz
595 +
596 +------------------
597 +
598 +Port Notes:
599 +
600 +----------  lighttpd-1.3.1-1 -----------
601 +
602 +Updated to 1.3.1
603 +
604 +----------  lighttpd-1.3.0-1 -----------
605 +Initial release
606 +
607 +Cygwin port maintained by: Jan Kneschke <jan@kneschke.de>
608 +Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com>
609 +
610 --- ../lighttpd-1.4.11/doc/authentication.txt   2006-01-12 20:34:26.000000000 +0200
611 +++ lighttpd-1.4.12/doc/authentication.txt      2006-07-16 00:26:05.000000000 +0300
612 @@ -7,8 +7,8 @@
613  ----------------
614  
615  :Author: Jan Kneschke
616 -:Date: $Date$
617 -:Revision: $Revision$
618 +:Date: $Date$
619 +:Revision: $Revision$
620  
621  :abstract:
622    The auth module provides ...
623 --- ../lighttpd-1.4.11/doc/compress.txt 2005-08-11 01:26:16.000000000 +0300
624 +++ lighttpd-1.4.12/doc/compress.txt    2006-07-16 00:26:05.000000000 +0300
625 @@ -22,12 +22,38 @@
626  ===========
627  
628  Output compression reduces the network load and can improve the overall
629 -throughput of the webserver. 
630 +throughput of the webserver. All major http-clients support compression by
631 +announcing it in the Accept-Encoding header. This is used to negotiate the 
632 +most suitable compression method. We support deflate, gzip and bzip2.
633  
634 -Only static content is supported up to now.
635 +deflate (RFC1950, RFC1951) and gzip (RFC1952) depend on zlib while bzip2 
636 +depends on libbzip2. bzip2 is only supported by lynx and some other console
637 +text-browsers.
638  
639 -The server negotiates automaticly which compression method is used.
640 -Supported are gzip, deflate, bzip.
641 +Currently we limit to compression support to static files.
642 +
643 +Caching
644 +-------
645 +
646 +mod_compress can stored compressed files on disk to optimized the compression
647 +on a second request away. As soon as compress.cache-dir is set the files are
648 +compressed. 
649 +
650 +The names of the cache files are made of the filename, the compression method
651 +and the etag associated to the file.
652 +
653 +Cleaning the cache is left to the user. A cron job deleting files older than
654 +10 days should do fine.
655 +
656 +Limitations
657 +-----------
658 +
659 +The module limits the compression of files to files larger than 128 Byte and
660 +smaller than 128 MByte.
661 +
662 +The lower limit is set as small files tend to become larger by compressing due
663 +to the compression headers, the upper limit is set to work sensable with
664 +memory and cpu-time.
665  
666  Options
667  =======
668 @@ -47,15 +73,28 @@
669    Default: not set, compress the file for every request
670  
671  compress.filetype
672 -  mimetypes where might get compressed
673 +  mimetypes which might get compressed
674    
675    e.g.: ::
676    
677      compress.filetype           = ("text/plain", "text/html")
678  
679 +  Keep in mind that compressed JavaScript and CSS files are broken in some
680 +  browsers.
681 +
682    Default: not set
683  
684 +compress.max-file-size 
685 +  maximum size of the original file to be compressed kBytes.
686 +
687 +  This is meant to protect the server against DoSing as compressing large
688 +  (let's say 1Gbyte) takes a lot of time and would delay the whole operation
689 +  of the server.
690  
691 +  There is a hard upper limit of 128Mbyte.
692 +
693 +  Default: unlimited (== hard-limit of 128MByte)
694 +  
695  Compressing Dynamic Content
696  ===========================
697  
698 --- ../lighttpd-1.4.11/doc/configuration.txt    2006-03-09 02:10:40.000000000 +0200
699 +++ lighttpd-1.4.12/doc/configuration.txt       2006-07-16 00:26:05.000000000 +0300
700 @@ -7,8 +7,8 @@
701  ------------
702  
703  :Author: Jan Kneschke
704 -:Date: $Date$
705 -:Revision: $Revision$
706 +:Date: $Date$
707 +:Revision: $Revision$
708  
709  :abstract:
710    the layout of the configuration file
711 @@ -511,3 +511,10 @@
712  
713  debug.log-request-handling
714    default: disabled 
715 +
716 +debug.log-condition-handling
717 +  default: disabled 
718 +
719 +debug.log-condition-cache-handling
720 +  for developers only
721 +  default: disabled 
722 --- ../lighttpd-1.4.11/doc/fastcgi.txt  2006-02-16 17:03:52.000000000 +0200
723 +++ lighttpd-1.4.12/doc/fastcgi.txt     2006-07-16 00:26:05.000000000 +0300
724 @@ -144,8 +144,8 @@
725                  PHP can extract PATH_INFO from it (default: disabled)
726    :"disable-time": time to wait before a disabled backend is checked
727                  again
728 -  :"allow-x-send-file": controls if X-LIGHTTPD-send-file headers
729 -                are allowed 
730 +  :"allow-x-send-file": controls if X-LIGHTTPD-send-file and X-Sendfile
731 +                headers are allowed 
732  
733    If bin-path is set:
734  
735 --- ../lighttpd-1.4.11/doc/lighttpd.conf        2006-03-04 14:41:12.000000000 +0200
736 +++ lighttpd-1.4.12/doc/lighttpd.conf   2006-07-16 00:26:05.000000000 +0300
737 @@ -172,10 +172,11 @@
738  #dir-listing.activate       = "enable"
739  
740  ## enable debugging
741 -#debug.log-request-header   = "enable"
742 -#debug.log-response-header  = "enable"
743 -#debug.log-request-handling = "enable"
744 -#debug.log-file-not-found   = "enable"
745 +#debug.log-request-header     = "enable"
746 +#debug.log-response-header    = "enable"
747 +#debug.log-request-handling   = "enable"
748 +#debug.log-file-not-found     = "enable"
749 +#debug.log-condition-handling = "enable"
750  
751  ### only root can use these options
752  #
753 --- ../lighttpd-1.4.11/doc/performance.txt      2006-02-02 13:01:08.000000000 +0200
754 +++ lighttpd-1.4.12/doc/performance.txt 2006-07-16 00:26:05.000000000 +0300
755 @@ -183,6 +183,8 @@
756  
757    server.stat-cache-engine = "fam"   # either fam, simple or disabled
758  
759 +See http://oss.sgi.com/projects/fam/faq.html for information about FAM.
760 +See http://www.gnome.org/~veillard/gamin/overview.html for information about gamin.
761  
762  Platform-Specific Notes
763  =======================
764 --- ../lighttpd-1.4.11/doc/secdownload.txt      2005-12-20 15:58:58.000000000 +0200
765 +++ lighttpd-1.4.12/doc/secdownload.txt 2006-07-16 00:26:05.000000000 +0300
766 @@ -118,7 +118,7 @@
767    $secret = "verysecret";
768    $uri_prefix = "/dl/";
769    
770 -  # filename
771 +  # filename, make sure it's started with a "/" or you'll get 404 in the browser
772    $f = "/secret-file.txt";
773    
774    # current timestamp
775 --- ../lighttpd-1.4.11/lighttpd.spec    2006-03-07 14:22:18.000000000 +0200
776 +++ lighttpd-1.4.12/lighttpd.spec       2006-07-19 20:09:00.000000000 +0300
777 @@ -1,6 +1,6 @@
778  Summary: A fast webserver with minimal memory-footprint (lighttpd)
779  Name: lighttpd
780 -Version: 1.4.11
781 +Version: 1.4.12
782  Release: 1
783  Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-%version.tar.gz
784  Packager: Jan Kneschke <jan@kneschke.de>
785 --- ../lighttpd-1.4.11/openwrt/control  2006-03-07 14:22:19.000000000 +0200
786 +++ lighttpd-1.4.12/openwrt/control     2006-07-19 20:09:00.000000000 +0300
787 @@ -1,8 +1,8 @@
788  Package: lighttpd
789 -Version: 1.4.11
790 +Version: 1.4.12
791  Architecture: mipsel
792  Maintainer: Jan Kneschke <jan@kneschke.de>
793 -Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-1.4.11.tar.gz
794 +Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-1.4.12.tar.gz
795  Section: net
796  Priority: optional
797  Depends:
798 --- ../lighttpd-1.4.11/openwrt/lighttpd.mk      2006-03-07 14:22:19.000000000 +0200
799 +++ lighttpd-1.4.12/openwrt/lighttpd.mk 2006-07-19 20:09:00.000000000 +0300
800 @@ -10,7 +10,7 @@
801  
802  #  For this example we'll use a fairly simple package that compiles easily
803  #  and has sources available for download at sourceforge
804 -LIGHTTPD=lighttpd-1.4.11
805 +LIGHTTPD=lighttpd-1.4.12
806  LIGHTTPD_TARGET=.built
807  LIGHTTPD_DIR=$(BUILD_DIR)/$(LIGHTTPD)
808  LIGHTTPD_IPK=$(BUILD_DIR)/$(LIGHTTPD)_mipsel.ipk
809 --- ../lighttpd-1.4.11/src/Makefile.am  2006-03-07 14:20:20.000000000 +0200
810 +++ lighttpd-1.4.12/src/Makefile.am     2006-07-19 20:02:55.000000000 +0300
811 @@ -16,18 +16,24 @@
812  else
813  configparser.y: lemon
814  mod_ssi_exprparser.y: lemon
815 +http_resp_parser.y: lemon
816  
817  configparser.c configparser.h: configparser.y
818         rm -f configparser.h
819 -       $(LEMON) -q $(srcdir)/configparser.y $(srcdir)/lempar.c
820 +       $(LEMON) -q $(srcdir)/$< $(srcdir)/lempar.c
821 +
822 +http_resp_parser.c http_resp_parser.h: http_resp_parser.y
823 +       rm -f http_resp_parser.h
824 +       $(LEMON) -q $(srcdir)/$< $(srcdir)/lempar.c
825  
826  mod_ssi_exprparser.c mod_ssi_exprparser.h: mod_ssi_exprparser.y 
827         rm -f mod_ssi_exprparser.h
828 -       $(LEMON) -q $(srcdir)/mod_ssi_exprparser.y $(srcdir)/lempar.c
829 +       $(LEMON) -q $(srcdir)/$< $(srcdir)/lempar.c
830  endif
831  
832  configfile.c: configparser.h
833  mod_ssi_expr.c: mod_ssi_exprparser.h
834 +http_resp.c: http_resp_parser.h
835  
836  common_src=buffer.c log.c \
837        keyvalue.c chunk.c  \
838 @@ -40,13 +46,13 @@
839        fdevent_solaris_devpoll.c fdevent_freebsd_kqueue.c \
840        data_config.c bitset.c \
841        inet_ntop_cache.c crc32.c \
842 -      connections-glue.c \
843 -      configfile-glue.c \
844 +      connections-glue.c iosocket.c \
845 +      configfile-glue.c status_counter.c \
846        http-header-glue.c \
847        network_write.c network_linux_sendfile.c \
848        network_freebsd_sendfile.c network_writev.c \
849        network_solaris_sendfilev.c network_openssl.c \
850 -      splaytree.c 
851 +      splaytree.c http_resp.c http_resp_parser.c 
852        
853  src = server.c response.c connections.c network.c \
854        configfile.c configparser.c request.c proc_open.c
855 @@ -82,9 +88,9 @@
856  
857  lib_LTLIBRARIES += mod_webdav.la
858  mod_webdav_la_SOURCES = mod_webdav.c
859 -mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS)
860 +mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS) 
861  mod_webdav_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
862 -mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS)
863 +mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS) $(UUID_LIB)
864  
865  lib_LTLIBRARIES += mod_cml.la
866  mod_cml_la_SOURCES = mod_cml.c mod_cml_lua.c mod_cml_funcs.c
867 @@ -103,6 +109,11 @@
868  mod_mysql_vhost_la_LIBADD = $(MYSQL_LIBS) $(common_libadd)
869  mod_mysql_vhost_la_CPPFLAGS = $(MYSQL_INCLUDE)
870  
871 +lib_LTLIBRARIES += mod_sql_vhost_core.la
872 +mod_sql_vhost_core_la_SOURCES = mod_sql_vhost_core.c
873 +mod_sql_vhost_core_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
874 +mod_sql_vhost_core_la_LIBADD = $(common_libadd)
875 +
876  lib_LTLIBRARIES += mod_cgi.la
877  mod_cgi_la_SOURCES = mod_cgi.c 
878  mod_cgi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
879 @@ -158,6 +169,14 @@
880  mod_proxy_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
881  mod_proxy_la_LIBADD = $(common_libadd)
882  
883 +lib_LTLIBRARIES += mod_proxy_core.la
884 +mod_proxy_core_la_SOURCES = mod_proxy_core.c mod_proxy_core_pool.c \
885 +                           mod_proxy_core_backend.c mod_proxy_core_address.c \
886 +                           mod_proxy_core_backlog.c mod_proxy_core_rewrites.c
887 +mod_proxy_core_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
888 +mod_proxy_core_la_LIBADD = $(common_libadd) $(PCRE_LIB)
889 +
890 +
891  lib_LTLIBRARIES += mod_ssi.la
892  mod_ssi_la_SOURCES = mod_ssi_exprparser.c mod_ssi_expr.c mod_ssi.c 
893  mod_ssi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
894 @@ -240,7 +259,13 @@
895        mod_ssi.h mod_ssi_expr.h inet_ntop_cache.h \
896        configparser.h mod_ssi_exprparser.h \
897        sys-mmap.h sys-socket.h mod_cml.h mod_cml_funcs.h \
898 -      splaytree.h proc_open.h
899 +      splaytree.h proc_open.h http_resp.h mod_sql_vhost_core.h \
900 +      sys-files.h sys-process.h sys-strings.h http_resp_parser.h \
901 +      iosocket.h array-static.h \
902 +      mod_proxy_core_address.h mod_proxy_core_backend.h \
903 +      mod_proxy_core_backlog.h mod_proxy_core.h  \
904 +      mod_proxy_core_pool.h mod_proxy_core_rewrites.h \
905 +      status_counter.h
906  
907  DEFS= @DEFS@ -DLIBRARY_DIR="\"$(libdir)\""
908  
909 @@ -267,4 +292,4 @@
910  #ajp_SOURCES = ajp.c
911  
912  noinst_HEADERS   = $(hdr)
913 -EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c
914 +EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c http_resp_parser.y
915 --- ../lighttpd-1.4.11/src/array-static.h       1970-01-01 03:00:00.000000000 +0300
916 +++ lighttpd-1.4.12/src/array-static.h  2006-07-18 13:03:40.000000000 +0300
917 @@ -0,0 +1,33 @@
918 +#ifndef _ARRAY_STATIC_H_
919 +#define _ARRAY_STATIC_H_
920 +
921 +/* define a generic array of <type>
922 + * */
923 +
924 +#define ARRAY_STATIC_DEF(name, type, extra) \
925 +typedef struct { \
926 +       type **ptr; \
927 +       size_t used; \
928 +       size_t size; \
929 +       extra\
930 +} name
931 +
932 +/* all append operations need a 'resize' for the +1 */
933 +
934 +#define ARRAY_STATIC_PREPARE_APPEND(a) \
935 +        if (a->size == 0) { \
936 +               a->size = 16; \
937 +               a->ptr = malloc(a->size * sizeof(*(a->ptr))); \
938 +       } else if (a->size == a->used) { \
939 +               a->size += 16; \
940 +               a->ptr = realloc(a->ptr, a->size * sizeof(*(a->ptr))); \
941 +       }
942 +       
943 +#define FOREACH(array, element, func) \
944 +do { size_t _i; for (_i = 0; _i < array->used; _i++) { void *element = array->ptr[_i]; func; } } while(0);
945 +
946 +#define STRUCT_INIT(type, var) \
947 +       type *var;\
948 +       var = calloc(1, sizeof(*var))
949 +
950 +#endif
951 --- ../lighttpd-1.4.11/src/array.c      2005-11-18 13:58:32.000000000 +0200
952 +++ lighttpd-1.4.12/src/array.c 2006-07-16 00:26:03.000000000 +0300
953 @@ -11,12 +11,12 @@
954  
955  array *array_init(void) {
956         array *a;
957 -       
958 +
959         a = calloc(1, sizeof(*a));
960         assert(a);
961 -       
962 +
963         a->next_power_of_2 = 1;
964 -       
965 +
966         return a;
967  }
968  
969 @@ -43,29 +43,29 @@
970  void array_free(array *a) {
971         size_t i;
972         if (!a) return;
973 -       
974 +
975         if (!a->is_weakref) {
976                 for (i = 0; i < a->size; i++) {
977                         if (a->data[i]) a->data[i]->free(a->data[i]);
978                 }
979         }
980 -       
981 +
982         if (a->data) free(a->data);
983         if (a->sorted) free(a->sorted);
984 -       
985 +
986         free(a);
987  }
988  
989  void array_reset(array *a) {
990         size_t i;
991         if (!a) return;
992 -       
993 +
994         if (!a->is_weakref) {
995                 for (i = 0; i < a->used; i++) {
996                         a->data[i]->reset(a->data[i]);
997                 }
998         }
999 -       
1000 +
1001         a->used = 0;
1002  }
1003  
1004 @@ -84,20 +84,20 @@
1005  static int array_get_index(array *a, const char *key, size_t keylen, int *rndx) {
1006         int ndx = -1;
1007         int i, pos = 0;
1008 -       
1009 +
1010         if (key == NULL) return -1;
1011 -       
1012 +
1013         /* try to find the string */
1014         for (i = pos = a->next_power_of_2 / 2; ; i >>= 1) {
1015                 int cmp;
1016 -               
1017 +
1018                 if (pos < 0) {
1019                         pos += i;
1020                 } else if (pos >= (int)a->used) {
1021                         pos -= i;
1022                 } else {
1023                         cmp = buffer_caseless_compare(key, keylen, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used);
1024 -                       
1025 +
1026                         if (cmp == 0) {
1027                                 /* found */
1028                                 ndx = a->sorted[pos];
1029 @@ -110,46 +110,46 @@
1030                 }
1031                 if (i == 0) break;
1032         }
1033 -       
1034 +
1035         if (rndx) *rndx = pos;
1036 -       
1037 +
1038         return ndx;
1039  }
1040  
1041  data_unset *array_get_element(array *a, const char *key) {
1042         int ndx;
1043 -       
1044 +
1045         if (-1 != (ndx = array_get_index(a, key, strlen(key) + 1, NULL))) {
1046                 /* found, leave here */
1047 -               
1048 +
1049                 return a->data[ndx];
1050 -       } 
1051 -       
1052 +       }
1053 +
1054         return NULL;
1055  }
1056  
1057  data_unset *array_get_unused_element(array *a, data_type_t t) {
1058         data_unset *ds = NULL;
1059 -       
1060 +
1061         UNUSED(t);
1062  
1063         if (a->size == 0) return NULL;
1064 -       
1065 +
1066         if (a->used == a->size) return NULL;
1067  
1068         if (a->data[a->used]) {
1069                 ds = a->data[a->used];
1070 -               
1071 +
1072                 a->data[a->used] = NULL;
1073         }
1074 -       
1075 +
1076         return ds;
1077  }
1078  
1079  /* replace or insert data, return the old one with the same key */
1080  data_unset *array_replace(array *a, data_unset *du) {
1081         int ndx;
1082 -       
1083 +
1084         if (-1 == (ndx = array_get_index(a, du->key->ptr, du->key->used, NULL))) {
1085                 array_insert_unique(a, du);
1086                 return NULL;
1087 @@ -164,13 +164,13 @@
1088         int ndx = -1;
1089         int pos = 0;
1090         size_t j;
1091 -       
1092 -       /* generate unique index if neccesary */
1093 +
1094 +       /* generate unique index if necessary */
1095         if (str->key->used == 0 || str->is_index_key) {
1096                 buffer_copy_long(str->key, a->unique_ndx++);
1097                 str->is_index_key = 1;
1098         }
1099 -       
1100 +
1101         /* try to find the string */
1102         if (-1 != (ndx = array_get_index(a, str->key->ptr, str->key->used, &pos))) {
1103                 /* found, leave here */
1104 @@ -181,14 +181,14 @@
1105                 }
1106                 return 0;
1107         }
1108 -       
1109 +
1110         /* insert */
1111 -       
1112 +
1113         if (a->used+1 > INT_MAX) {
1114                 /* we can't handle more then INT_MAX entries: see array_get_index() */
1115                 return -1;
1116         }
1117 -       
1118 +
1119         if (a->size == 0) {
1120                 a->size   = 16;
1121                 a->data   = malloc(sizeof(*a->data)     * a->size);
1122 @@ -204,27 +204,27 @@
1123                 assert(a->sorted);
1124                 for (j = a->used; j < a->size; j++) a->data[j] = NULL;
1125         }
1126 -       
1127 +
1128         ndx = (int) a->used;
1129 -       
1130 +
1131         a->data[a->used++] = str;
1132 -       
1133 +
1134         if (pos != ndx &&
1135 -           ((pos < 0) || 
1136 +           ((pos < 0) ||
1137              buffer_caseless_compare(str->key->ptr, str->key->used, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used) > 0)) {
1138                 pos++;
1139 -       } 
1140 -       
1141 -       /* move everything on step to the right */
1142 +       }
1143 +
1144 +       /* move everything one step to the right */
1145         if (pos != ndx) {
1146                 memmove(a->sorted + (pos + 1), a->sorted + (pos), (ndx - pos) * sizeof(*a->sorted));
1147         }
1148 -       
1149 +
1150         /* insert */
1151         a->sorted[pos] = ndx;
1152 -       
1153 +
1154         if (a->next_power_of_2 == (size_t)ndx) a->next_power_of_2 <<= 1;
1155 -       
1156 +
1157         return 0;
1158  }
1159  
1160 @@ -254,7 +254,7 @@
1161         size_t i;
1162         size_t maxlen;
1163         int oneline = 1;
1164 -       
1165 +
1166         if (a->used > 5) {
1167                 oneline = 0;
1168         }
1169 @@ -314,7 +314,7 @@
1170         }
1171         array_print_indent(depth);
1172         fprintf(stderr, ")");
1173 -       
1174 +
1175         return 0;
1176  }
1177  
1178 @@ -323,47 +323,47 @@
1179         array *a;
1180         data_string *ds;
1181         data_count *dc;
1182 -       
1183 +
1184         UNUSED(argc);
1185         UNUSED(argv);
1186  
1187         a = array_init();
1188 -       
1189 +
1190         ds = data_string_init();
1191         buffer_copy_string(ds->key, "abc");
1192         buffer_copy_string(ds->value, "alfrag");
1193 -       
1194 +
1195         array_insert_unique(a, (data_unset *)ds);
1196 -       
1197 +
1198         ds = data_string_init();
1199         buffer_copy_string(ds->key, "abc");
1200         buffer_copy_string(ds->value, "hameplman");
1201 -       
1202 +
1203         array_insert_unique(a, (data_unset *)ds);
1204 -       
1205 +
1206         ds = data_string_init();
1207         buffer_copy_string(ds->key, "123");
1208         buffer_copy_string(ds->value, "alfrag");
1209 -       
1210 +
1211         array_insert_unique(a, (data_unset *)ds);
1212 -       
1213 +
1214         dc = data_count_init();
1215         buffer_copy_string(dc->key, "def");
1216 -       
1217 +
1218         array_insert_unique(a, (data_unset *)dc);
1219 -       
1220 +
1221         dc = data_count_init();
1222         buffer_copy_string(dc->key, "def");
1223 -       
1224 +
1225         array_insert_unique(a, (data_unset *)dc);
1226 -       
1227 +
1228         array_print(a, 0);
1229 -       
1230 +
1231         array_free(a);
1232 -       
1233 +
1234         fprintf(stderr, "%d\n",
1235                buffer_caseless_compare(CONST_STR_LEN("Content-Type"), CONST_STR_LEN("Content-type")));
1236 -       
1237 +
1238         return 0;
1239  }
1240  #endif
1241 --- ../lighttpd-1.4.11/src/array.h      2005-09-23 21:24:18.000000000 +0300
1242 +++ lighttpd-1.4.12/src/array.h 2006-07-16 00:26:03.000000000 +0300
1243 @@ -16,7 +16,7 @@
1244  #define DATA_UNSET \
1245         data_type_t type; \
1246         buffer *key; \
1247 -       int is_index_key; /* 1 if key is a array index (autogenerated keys) */ \
1248 +       int is_index_key; /* 1 if key is an array index (auto-generated keys) */ \
1249         struct data_unset *(*copy)(const struct data_unset *src); \
1250         void (* free)(struct data_unset *p); \
1251         void (* reset)(struct data_unset *p); \
1252 @@ -29,21 +29,21 @@
1253  
1254  typedef struct {
1255         data_unset  **data;
1256 -       
1257 +
1258         size_t *sorted;
1259 -       
1260 +
1261         size_t used;
1262         size_t size;
1263 -       
1264 +
1265         size_t unique_ndx;
1266 -       
1267 +
1268         size_t next_power_of_2;
1269         int is_weakref; /* data is weakref, don't bother the data */
1270  } array;
1271  
1272  typedef struct {
1273         DATA_UNSET;
1274 -       
1275 +
1276         int count;
1277  } data_count;
1278  
1279 @@ -51,7 +51,7 @@
1280  
1281  typedef struct {
1282         DATA_UNSET;
1283 -       
1284 +
1285         buffer *value;
1286  } data_string;
1287  
1288 @@ -60,7 +60,7 @@
1289  
1290  typedef struct {
1291         DATA_UNSET;
1292 -       
1293 +
1294         array *value;
1295  } data_array;
1296  
1297 @@ -74,7 +74,7 @@
1298         COMP_SERVER_SOCKET, COMP_HTTP_URL, COMP_HTTP_HOST, COMP_HTTP_REFERER, COMP_HTTP_USERAGENT, COMP_HTTP_COOKIE, COMP_HTTP_REMOTEIP
1299  } comp_key_t;
1300  
1301 -/* $HTTP["host"] ==    "incremental.home.kneschke.de" { ... } 
1302 +/* $HTTP["host"] ==    "incremental.home.kneschke.de" { ... }
1303   * for print:   comp_key      op    string
1304   * for compare: comp          cond  string/regex
1305   */
1306 @@ -82,15 +82,15 @@
1307  typedef struct _data_config data_config;
1308  struct _data_config {
1309         DATA_UNSET;
1310 -       
1311 +
1312         array *value;
1313 -       
1314 +
1315         buffer *comp_key;
1316         comp_key_t comp;
1317 -       
1318 +
1319         config_cond_t cond;
1320         buffer *op;
1321 -       
1322 +
1323         int context_ndx; /* more or less like an id */
1324         array *childs;
1325         /* nested */
1326 @@ -98,7 +98,7 @@
1327         /* for chaining only */
1328         data_config *prev;
1329         data_config *next;
1330 -       
1331 +
1332         buffer *string;
1333  #ifdef HAVE_PCRE_H
1334         pcre   *regex;
1335 @@ -110,7 +110,7 @@
1336  
1337  typedef struct {
1338         DATA_UNSET;
1339 -       
1340 +
1341         int value;
1342  } data_integer;
1343  
1344 @@ -120,13 +120,13 @@
1345         DATA_UNSET;
1346  
1347         buffer *host;
1348 -       
1349 +
1350         unsigned short port;
1351  
1352         time_t disable_ts;
1353         int is_disabled;
1354         size_t balance;
1355 -               
1356 +
1357         int usage; /* fair-balancing needs the no. of connections active on this host */
1358         int last_used_ndx; /* round robin */
1359  } data_fastcgi;
1360 --- ../lighttpd-1.4.11/src/base.h       2006-01-11 16:51:04.000000000 +0200
1361 +++ lighttpd-1.4.12/src/base.h  2006-07-19 20:02:55.000000000 +0300
1362 @@ -2,7 +2,6 @@
1363  #define _BASE_H_
1364  
1365  #include <sys/types.h>
1366 -#include <sys/time.h>
1367  #include <sys/stat.h>
1368  
1369  #ifdef HAVE_CONFIG_H
1370 @@ -26,10 +25,9 @@
1371  #include "sys-socket.h"
1372  #include "splaytree.h"
1373  
1374 -
1375  #if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
1376  # define USE_OPENSSL
1377 -# include <openssl/ssl.h> 
1378 +# include <openssl/ssl.h>
1379  #endif
1380  
1381  #ifdef HAVE_FAM_H
1382 @@ -40,10 +38,6 @@
1383  # define O_BINARY 0
1384  #endif
1385  
1386 -#ifndef O_LARGEFILE
1387 -# define O_LARGEFILE 0
1388 -#endif
1389 -
1390  #ifndef SIZE_MAX
1391  # ifdef SIZE_T_MAX
1392  #  define SIZE_MAX SIZE_T_MAX
1393 @@ -70,7 +64,8 @@
1394  
1395  /* solaris and NetBSD 1.3.x again */
1396  #if (!defined(HAVE_STDINT_H)) && (!defined(HAVE_INTTYPES_H)) && (!defined(uint32_t))
1397 -# define uint32_t u_int32_t
1398 +/* # define uint32_t u_int32_t */
1399 +typedef unsigned __int32 uint32_t;
1400  #endif
1401  
1402  
1403 @@ -80,24 +75,24 @@
1404  
1405  #include "settings.h"
1406  
1407 -typedef enum { T_CONFIG_UNSET, 
1408 -               T_CONFIG_STRING, 
1409 -               T_CONFIG_SHORT, 
1410 -               T_CONFIG_BOOLEAN, 
1411 -               T_CONFIG_ARRAY, 
1412 -               T_CONFIG_LOCAL, 
1413 +typedef enum { T_CONFIG_UNSET,
1414 +               T_CONFIG_STRING,
1415 +               T_CONFIG_SHORT,
1416 +               T_CONFIG_BOOLEAN,
1417 +               T_CONFIG_ARRAY,
1418 +               T_CONFIG_LOCAL,
1419                 T_CONFIG_DEPRECATED
1420  } config_values_type_t;
1421  
1422 -typedef enum { T_CONFIG_SCOPE_UNSET, 
1423 -               T_CONFIG_SCOPE_SERVER, 
1424 +typedef enum { T_CONFIG_SCOPE_UNSET,
1425 +               T_CONFIG_SCOPE_SERVER,
1426                 T_CONFIG_SCOPE_CONNECTION
1427  } config_scope_type_t;
1428  
1429  typedef struct {
1430         const char *key;
1431         void *destination;
1432 -       
1433 +
1434         config_values_type_t type;
1435         config_scope_type_t scope;
1436  } config_values_t;
1437 @@ -118,18 +113,6 @@
1438         short factor;
1439  } fcgi_connections;
1440  
1441 -
1442 -typedef union {
1443 -#ifdef HAVE_IPV6
1444 -       struct sockaddr_in6 ipv6;
1445 -#endif
1446 -       struct sockaddr_in ipv4;
1447 -#ifdef HAVE_SYS_UN_H
1448 -       struct sockaddr_un un;
1449 -#endif
1450 -       struct sockaddr plain;
1451 -} sock_addr;
1452 -
1453  /* fcgi_response_header contains ... */
1454  #define HTTP_STATUS         BV(0)
1455  #define HTTP_CONNECTION     BV(1)
1456 @@ -142,40 +125,40 @@
1457         /* the request-line */
1458         buffer *request;
1459         buffer *uri;
1460 -       
1461 +
1462         buffer *orig_uri;
1463 -       
1464 +
1465         http_method_t  http_method;
1466         http_version_t http_version;
1467 -       
1468 +
1469         buffer *request_line;
1470 -       
1471 +
1472         /* strings to the header */
1473         buffer *http_host; /* not alloced */
1474         const char   *http_range;
1475         const char   *http_content_type;
1476         const char   *http_if_modified_since;
1477         const char   *http_if_none_match;
1478 -       
1479 +
1480         array  *headers;
1481 -       
1482 +
1483         /* CONTENT */
1484         size_t content_length; /* returned by strtoul() */
1485 -       
1486 +
1487         /* internal representation */
1488         int     accept_encoding;
1489 -       
1490 +
1491         /* internal */
1492         buffer *pathinfo;
1493  } request;
1494  
1495  typedef struct {
1496         off_t   content_length;
1497 -       int     keep_alive;               /* used by  the subrequests in proxy, cgi and fcgi to say the subrequest was keep-alive or not */
1498 -       
1499 +       int     keep_alive;               /* used by the subrequests in proxy, cgi and fcgi to say whether the subrequest was keep-alive or not */
1500 +
1501         array  *headers;
1502 -       
1503 -       enum { 
1504 +
1505 +       enum {
1506                 HTTP_TRANSFER_ENCODING_IDENTITY, HTTP_TRANSFER_ENCODING_CHUNKED
1507         } transfer_encoding;
1508  } response;
1509 @@ -191,21 +174,21 @@
1510  typedef struct {
1511         buffer *path;
1512         buffer *basedir; /* path = "(basedir)(.*)" */
1513 -       
1514 +
1515         buffer *doc_root; /* path = doc_root + rel_path */
1516         buffer *rel_path;
1517 -       
1518 +
1519         buffer *etag;
1520  } physical;
1521  
1522  typedef struct {
1523         buffer *name;
1524         buffer *etag;
1525 -       
1526 +
1527         struct stat st;
1528 -       
1529 +
1530         time_t stat_ts;
1531 -       
1532 +
1533  #ifdef HAVE_FAM_H
1534         int    dir_version;
1535         int    dir_ndx;
1536 @@ -215,20 +198,20 @@
1537  } stat_cache_entry;
1538  
1539  typedef struct {
1540 -       splay_tree *files; /* the nodes of the tree are stat_cache_entry's */
1541 -       
1542 +       splay_tree *files; /* the nodes of the tree are stat_cache_entries */
1543 +
1544         buffer *dir_name; /* for building the dirname from the filename */
1545  #ifdef HAVE_FAM_H
1546         splay_tree *dirs; /* the nodes of the tree are fam_dir_entry */
1547  
1548         FAMConnection *fam;
1549 -       int    fam_fcce_ndx;
1550 +       iosocket *sock;
1551  #endif
1552  } stat_cache;
1553  
1554  typedef struct {
1555         array *mimetypes;
1556 -       
1557 +
1558         /* virtual-servers */
1559         buffer *document_root;
1560         buffer *server_name;
1561 @@ -236,7 +219,7 @@
1562         buffer *server_tag;
1563         buffer *dirlist_encoding;
1564         buffer *errorfile_prefix;
1565 -       
1566 +
1567         unsigned short max_keep_alive_requests;
1568         unsigned short max_keep_alive_idle;
1569         unsigned short max_read_idle;
1570 @@ -244,16 +227,17 @@
1571         unsigned short use_xattr;
1572         unsigned short follow_symlink;
1573         unsigned short range_requests;
1574 -       
1575 +
1576         /* debug */
1577 -       
1578 +
1579         unsigned short log_file_not_found;
1580         unsigned short log_request_header;
1581         unsigned short log_request_handling;
1582         unsigned short log_response_header;
1583         unsigned short log_condition_handling;
1584 -       
1585 -       
1586 +       unsigned short log_condition_cache_handling;
1587 +
1588 +
1589         /* server wide */
1590         buffer *ssl_pemfile;
1591         buffer *ssl_ca_file;
1592 @@ -268,22 +252,22 @@
1593         /* configside */
1594         unsigned short global_kbytes_per_second; /*  */
1595  
1596 -       off_t  global_bytes_per_second_cnt; 
1597 +       off_t  global_bytes_per_second_cnt;
1598         /* server-wide traffic-shaper
1599 -        * 
1600 +        *
1601          * each context has the counter which is inited once
1602 -        * a second by the global_kbytes_per_second config-var
1603 +        * per second by the global_kbytes_per_second config-var
1604          *
1605          * as soon as global_kbytes_per_second gets below 0
1606          * the connected conns are "offline" a little bit
1607          *
1608          * the problem:
1609 -        * we somehow have to loose our "we are writable" signal 
1610 +        * we somehow have to lose our "we are writable" signal
1611          * on the way.
1612 -        * 
1613 +        *
1614          */
1615         off_t *global_bytes_per_second_cnt_ptr; /*  */
1616 -       
1617 +
1618  #ifdef USE_OPENSSL
1619         SSL_CTX *ssl_ctx;
1620  #endif
1621 @@ -291,18 +275,18 @@
1622  
1623  /* the order of the items should be the same as they are processed
1624   * read before write as we use this later */
1625 -typedef enum { 
1626 -       CON_STATE_CONNECT, 
1627 -       CON_STATE_REQUEST_START, 
1628 -       CON_STATE_READ, 
1629 -       CON_STATE_REQUEST_END, 
1630 -       CON_STATE_READ_POST, 
1631 -       CON_STATE_HANDLE_REQUEST, 
1632 -       CON_STATE_RESPONSE_START, 
1633 -       CON_STATE_WRITE, 
1634 -       CON_STATE_RESPONSE_END, 
1635 -       CON_STATE_ERROR, 
1636 -       CON_STATE_CLOSE 
1637 +typedef enum {
1638 +       CON_STATE_CONNECT,
1639 +       CON_STATE_REQUEST_START,
1640 +       CON_STATE_READ,
1641 +       CON_STATE_REQUEST_END,
1642 +       CON_STATE_READ_POST,
1643 +       CON_STATE_HANDLE_REQUEST,
1644 +       CON_STATE_RESPONSE_START,
1645 +       CON_STATE_WRITE,
1646 +       CON_STATE_RESPONSE_END,
1647 +       CON_STATE_ERROR,
1648 +       CON_STATE_CLOSE
1649  } connection_state_t;
1650  
1651  typedef enum { COND_RESULT_UNSET, COND_RESULT_FALSE, COND_RESULT_TRUE } cond_result_t;
1652 @@ -315,91 +299,86 @@
1653  
1654  typedef struct {
1655         connection_state_t state;
1656 -       
1657 +
1658         /* timestamps */
1659         time_t read_idle_ts;
1660         time_t close_timeout_ts;
1661         time_t write_request_ts;
1662 -       
1663 +
1664         time_t connection_start;
1665         time_t request_start;
1666 -       
1667 +
1668         struct timeval start_tv;
1669 -       
1670 +
1671         size_t request_count;        /* number of requests handled in this connection */
1672         size_t loops_per_request;    /* to catch endless loops in a single request
1673 -                                     * 
1674 +                                     *
1675                                       * used by mod_rewrite, mod_fastcgi, ... and others
1676                                       * this is self-protection
1677                                       */
1678 -       
1679 -       int fd;                      /* the FD for this connection */
1680 -       int fde_ndx;                 /* index for the fdevent-handler */
1681 +
1682 +       iosocket *sock;
1683         int ndx;                     /* reverse mapping to server->connection[ndx] */
1684 -       
1685 +
1686         /* fd states */
1687         int is_readable;
1688         int is_writable;
1689 -       
1690 -       int     keep_alive;           /* only request.c can enable it, all other just disable */
1691 -       
1692 +
1693 +       int     keep_alive;           /* only request.c can enable it, all others just disable */
1694 +
1695         int file_started;
1696         int file_finished;
1697 -       
1698 +
1699         chunkqueue *write_queue;      /* a large queue for low-level write ( HTTP response ) [ file, mem ] */
1700         chunkqueue *read_queue;       /* a small queue for low-level read ( HTTP request ) [ mem ] */
1701         chunkqueue *request_content_queue; /* takes request-content into tempfile if necessary [ tempfile, mem ]*/
1702 -       
1703 +
1704         int traffic_limit_reached;
1705 -       
1706 +
1707         off_t bytes_written;          /* used by mod_accesslog, mod_rrd */
1708         off_t bytes_written_cur_second; /* used by mod_accesslog, mod_rrd */
1709         off_t bytes_read;             /* used by mod_accesslog, mod_rrd */
1710         off_t bytes_header;
1711 -       
1712 +
1713         int http_status;
1714 -       
1715 +
1716         sock_addr dst_addr;
1717         buffer *dst_addr_buf;
1718  
1719         /* request */
1720         buffer *parse_request;
1721         unsigned int parsed_response; /* bitfield which contains the important header-fields of the parsed response header */
1722 -       
1723 +
1724         request  request;
1725         request_uri uri;
1726 -       physical physical; 
1727 +       physical physical;
1728         response response;
1729 -       
1730 +
1731         size_t header_len;
1732 -       
1733 +
1734         buffer *authed_user;
1735         array  *environment; /* used to pass lighttpd internal stuff to the FastCGI/CGI apps, setenv does that */
1736 -       
1737 +
1738         /* response */
1739         int    got_response;
1740 -       
1741 +
1742         int    in_joblist;
1743 -       
1744 +
1745         connection_type mode;
1746 -       
1747 +
1748         void **plugin_ctx;           /* plugin connection specific config */
1749 -       
1750 +
1751         specific_config conf;        /* global connection specific config */
1752         cond_cache_t *cond_cache;
1753 -       
1754 +
1755         buffer *server_name;
1756 -       
1757 +
1758         /* error-handler */
1759         buffer *error_handler;
1760         int error_handler_saved_status;
1761         int in_error_handler;
1762 -       
1763 +
1764         void *srv_socket;   /* reference to the server-socket (typecast to server_socket) */
1765 -       
1766 -#ifdef USE_OPENSSL
1767 -       SSL *ssl;
1768 -#endif
1769  } connection;
1770  
1771  typedef struct {
1772 @@ -439,55 +418,63 @@
1773         size_t size;
1774  } buffer_plugin;
1775  
1776 +typedef enum {
1777 +    NETWORK_STATUS_UNSET,
1778 +    NETWORK_STATUS_SUCCESS,
1779 +    NETWORK_STATUS_FATAL_ERROR,
1780 +    NETWORK_STATUS_CONNECTION_CLOSE,
1781 +    NETWORK_STATUS_WAIT_FOR_EVENT,
1782 +    NETWORK_STATUS_INTERRUPTED
1783 +} network_status_t;
1784 +
1785  typedef struct {
1786         unsigned short port;
1787         buffer *bindhost;
1788 -       
1789 -       buffer *errorlog_file;
1790 -       unsigned short errorlog_use_syslog;
1791 -       
1792 +
1793         unsigned short dont_daemonize;
1794         buffer *changeroot;
1795         buffer *username;
1796         buffer *groupname;
1797 -       
1798 +
1799         buffer *pid_file;
1800 -       
1801 +
1802         buffer *event_handler;
1803 -       
1804 +
1805         buffer *modules_dir;
1806         buffer *network_backend;
1807         array *modules;
1808         array *upload_tempdirs;
1809 -       
1810 +
1811         unsigned short max_worker;
1812         unsigned short max_fds;
1813         unsigned short max_conns;
1814         unsigned short max_request_size;
1815 -       
1816 +
1817         unsigned short log_request_header_on_error;
1818         unsigned short log_state_handling;
1819 -       
1820 -       enum { STAT_CACHE_ENGINE_UNSET, 
1821 -                       STAT_CACHE_ENGINE_NONE, 
1822 -                       STAT_CACHE_ENGINE_SIMPLE, 
1823 -                       STAT_CACHE_ENGINE_FAM 
1824 +
1825 +       enum { STAT_CACHE_ENGINE_UNSET,
1826 +                       STAT_CACHE_ENGINE_NONE,
1827 +                       STAT_CACHE_ENGINE_SIMPLE,
1828 +                       STAT_CACHE_ENGINE_FAM
1829         } stat_cache_engine;
1830         unsigned short enable_cores;
1831 +
1832 +       buffer *errorlog_file;
1833 +       unsigned short errorlog_use_syslog;
1834  } server_config;
1835  
1836  typedef struct {
1837         sock_addr addr;
1838 -       int       fd;
1839 -       int       fde_ndx;
1840 -       
1841 +       iosocket *sock;
1842 +
1843         buffer *ssl_pemfile;
1844         buffer *ssl_ca_file;
1845         unsigned short use_ipv6;
1846         unsigned short is_ssl;
1847 -       
1848 +
1849         buffer *srv_token;
1850 -       
1851 +
1852  #ifdef USE_OPENSSL
1853         SSL_CTX *ssl_ctx;
1854  #endif
1855 @@ -495,37 +482,32 @@
1856  
1857  typedef struct {
1858         server_socket **ptr;
1859 -       
1860 +
1861         size_t size;
1862         size_t used;
1863  } server_socket_array;
1864  
1865  typedef struct server {
1866         server_socket_array srv_sockets;
1867 -       
1868 -       /* the errorlog */
1869 -       int errorlog_fd;
1870 -       enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG } errorlog_mode;
1871 -       buffer *errorlog_buf;
1872 -       
1873 +
1874         fdevents *ev, *ev_ins;
1875 -       
1876 +
1877         buffer_plugin plugins;
1878         void *plugin_slots;
1879 -       
1880 +
1881         /* counters */
1882         int con_opened;
1883         int con_read;
1884         int con_written;
1885         int con_closed;
1886 -       
1887 +
1888         int ssl_is_init;
1889 -       
1890 +
1891         int max_fds;    /* max possible fds */
1892         int cur_fds;    /* currently used fds */
1893         int want_fds;   /* waiting fds */
1894         int sockets_disabled;
1895 -       
1896 +
1897         size_t max_conns;
1898  
1899         /* buffers */
1900 @@ -533,13 +515,13 @@
1901         buffer *response_header;
1902         buffer *response_range;
1903         buffer *tmp_buf;
1904 -       
1905 +
1906         buffer *tmp_chunk_len;
1907 -       
1908 +
1909         buffer *empty_string; /* is necessary for cond_match */
1910  
1911         buffer *cond_check_buf;
1912 -       
1913 +
1914         /* caches */
1915  #ifdef HAVE_IPV6
1916         inet_ntop_cache_type inet_ntop_cache[INET_NTOP_CACHE_MAX];
1917 @@ -547,59 +529,46 @@
1918         mtime_cache_type mtime_cache[FILE_CACHE_MAX];
1919  
1920         array *split_vals;
1921 -       
1922 +
1923         /* Timestamps */
1924         time_t cur_ts;
1925         time_t last_generated_date_ts;
1926         time_t last_generated_debug_ts;
1927         time_t startup_ts;
1928 -       
1929 +
1930         buffer *ts_debug_str;
1931         buffer *ts_date_str;
1932 -       
1933 +
1934         /* config-file */
1935         array *config;
1936         array *config_touched;
1937 -       
1938 +
1939         array *config_context;
1940         specific_config **config_storage;
1941 -       
1942 +
1943         server_config  srvconf;
1944 -       
1945 +
1946         int config_deprecated;
1947 -       
1948 +
1949         connections *conns;
1950         connections *joblist;
1951         connections *fdwaitqueue;
1952 -       
1953 +
1954         stat_cache  *stat_cache;
1955  
1956 -       /**
1957 -        * The status array can carry all the status information you want
1958 -        * the key to the array is <module-prefix>.<name>
1959 -        * and the values are counters
1960 -        *
1961 -        * example:
1962 -        *   fastcgi.backends        = 10
1963 -        *   fastcgi.active-backends = 6
1964 -        *   fastcgi.backend.<key>.load = 24
1965 -        *   fastcgi.backend.<key>....
1966 -        *
1967 -        *   fastcgi.backend.<key>.disconnects = ...
1968 -        */
1969 -       array *status;
1970 -       
1971         fdevent_handler_t event_handler;
1972  
1973 -       int (* network_backend_write)(struct server *srv, connection *con, int fd, chunkqueue *cq);
1974 -       int (* network_backend_read)(struct server *srv, connection *con, int fd, chunkqueue *cq);
1975 +       network_status_t (* network_backend_write)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1976 +       network_status_t (* network_backend_read)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1977  #ifdef USE_OPENSSL
1978 -       int (* network_ssl_backend_write)(struct server *srv, connection *con, SSL *ssl, chunkqueue *cq);
1979 -       int (* network_ssl_backend_read)(struct server *srv, connection *con, SSL *ssl, chunkqueue *cq);
1980 +       network_status_t (* network_ssl_backend_write)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1981 +       network_status_t (* network_ssl_backend_read)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1982  #endif
1983  
1984 +#ifdef HAVE_PWD_H
1985         uid_t uid;
1986         gid_t gid;
1987 +#endif
1988  } server;
1989  
1990  
1991 --- ../lighttpd-1.4.11/src/bitset.c     2005-08-22 01:54:12.000000000 +0300
1992 +++ lighttpd-1.4.12/src/bitset.c        2006-07-18 13:03:40.000000000 +0300
1993 @@ -6,6 +6,7 @@
1994  
1995  #include "bitset.h"
1996  #include "buffer.h"
1997 +#include "log.h"
1998  
1999  #define BITSET_BITS \
2000         ( CHAR_BIT * sizeof(size_t) )
2001 --- ../lighttpd-1.4.11/src/buffer.c     2006-01-13 00:00:45.000000000 +0200
2002 +++ lighttpd-1.4.12/src/buffer.c        2006-07-18 13:03:40.000000000 +0300
2003 @@ -12,20 +12,20 @@
2004  
2005  
2006  /**
2007 - * init the buffer 
2008 - * 
2009 + * init the buffer
2010 + *
2011   */
2012  
2013  buffer* buffer_init(void) {
2014         buffer *b;
2015 -       
2016 +
2017         b = malloc(sizeof(*b));
2018         assert(b);
2019 -       
2020 +
2021         b->ptr = NULL;
2022         b->size = 0;
2023         b->used = 0;
2024 -       
2025 +
2026         return b;
2027  }
2028  
2029 @@ -36,8 +36,8 @@
2030  }
2031  
2032  /**
2033 - * free the buffer 
2034 - * 
2035 + * free the buffer
2036 + *
2037   */
2038  
2039  void buffer_free(buffer *b) {
2040 @@ -49,39 +49,39 @@
2041  
2042  void buffer_reset(buffer *b) {
2043         if (!b) return;
2044 -       
2045 +
2046         /* limit don't reuse buffer larger than ... bytes */
2047         if (b->size > BUFFER_MAX_REUSE_SIZE) {
2048                 free(b->ptr);
2049                 b->ptr = NULL;
2050                 b->size = 0;
2051         }
2052 -       
2053 +
2054         b->used = 0;
2055  }
2056  
2057  
2058  /**
2059 - * 
2060 - * allocate (if neccessary) enough space for 'size' bytes and 
2061 + *
2062 + * allocate (if necessary) enough space for 'size' bytes and
2063   * set the 'used' counter to 0
2064 - * 
2065 + *
2066   */
2067  
2068  #define BUFFER_PIECE_SIZE 64
2069  
2070  int buffer_prepare_copy(buffer *b, size_t size) {
2071         if (!b) return -1;
2072 -       
2073 -       if ((0 == b->size) || 
2074 +
2075 +       if ((0 == b->size) ||
2076             (size > b->size)) {
2077                 if (b->size) free(b->ptr);
2078 -               
2079 +
2080                 b->size = size;
2081 -               
2082 -               /* always allocate a multiply of BUFFER_PIECE_SIZE */
2083 +
2084 +               /* always allocate a multiple of BUFFER_PIECE_SIZE */
2085                 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2086 -               
2087 +
2088                 b->ptr = malloc(b->size);
2089                 assert(b->ptr);
2090         }
2091 @@ -90,30 +90,30 @@
2092  }
2093  
2094  /**
2095 - * 
2096 - * increase the internal buffer (if neccessary) to append another 'size' byte
2097 + *
2098 + * increase the internal buffer (if necessary) to append another 'size' byte
2099   * ->used isn't changed
2100 - * 
2101 + *
2102   */
2103  
2104  int buffer_prepare_append(buffer *b, size_t size) {
2105         if (!b) return -1;
2106 -       
2107 +
2108         if (0 == b->size) {
2109                 b->size = size;
2110 -               
2111 -               /* always allocate a multiply of BUFFER_PIECE_SIZE */
2112 +
2113 +               /* always allocate a multiple of BUFFER_PIECE_SIZE */
2114                 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2115 -               
2116 +
2117                 b->ptr = malloc(b->size);
2118                 b->used = 0;
2119                 assert(b->ptr);
2120         } else if (b->used + size > b->size) {
2121                 b->size += size;
2122 -               
2123 -               /* always allocate a multiply of BUFFER_PIECE_SIZE */
2124 +
2125 +               /* always allocate a multiple of BUFFER_PIECE_SIZE */
2126                 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2127 -               
2128 +
2129                 b->ptr = realloc(b->ptr, b->size);
2130                 assert(b->ptr);
2131         }
2132 @@ -122,7 +122,7 @@
2133  
2134  int buffer_copy_string(buffer *b, const char *s) {
2135         size_t s_len;
2136 -       
2137 +
2138         if (!s || !b) return -1;
2139  
2140         s_len = strlen(s) + 1;
2141 @@ -136,26 +136,26 @@
2142  
2143  int buffer_copy_string_len(buffer *b, const char *s, size_t s_len) {
2144         if (!s || !b) return -1;
2145 -#if 0  
2146 -       /* removed optimization as we have to keep the empty string 
2147 +#if 0
2148 +       /* removed optimization as we have to keep the empty string
2149          * in some cases for the config handling
2150 -        * 
2151 +        *
2152          * url.access-deny = ( "" )
2153          */
2154         if (s_len == 0) return 0;
2155 -#endif 
2156 +#endif
2157         buffer_prepare_copy(b, s_len + 1);
2158 -       
2159 +
2160         memcpy(b->ptr, s, s_len);
2161         b->ptr[s_len] = '\0';
2162         b->used = s_len + 1;
2163 -       
2164 +
2165         return 0;
2166  }
2167  
2168  int buffer_copy_string_buffer(buffer *b, const buffer *src) {
2169         if (!src) return -1;
2170 -       
2171 +
2172         if (src->used == 0) {
2173                 b->used = 0;
2174                 return 0;
2175 @@ -201,10 +201,10 @@
2176  
2177  /**
2178   * append a string to the end of the buffer
2179 - * 
2180 - * the resulting buffer is terminated with a '\0' 
2181 - * s is treated as a un-terminated string (a \0 is handled a normal character)
2182 - * 
2183 + *
2184 + * the resulting buffer is terminated with a '\0'
2185 + * s is treated as an un-terminated string (a \0 is handled as a normal character)
2186 + *
2187   * @param b a buffer
2188   * @param s the string
2189   * @param s_len size of the string (without the terminating \0)
2190 @@ -228,7 +228,7 @@
2191  int buffer_append_string_buffer(buffer *b, const buffer *src) {
2192         if (!src) return -1;
2193         if (src->used == 0) return 0;
2194 -       
2195 +
2196         return buffer_append_string_len(b, src->ptr, src->used - 1);
2197  }
2198  
2199 @@ -245,9 +245,9 @@
2200  
2201  int buffer_copy_memory(buffer *b, const char *s, size_t s_len) {
2202         if (!s || !b) return -1;
2203 -       
2204 +
2205         b->used = 0;
2206 -       
2207 +
2208         return buffer_append_memory(b, s, s_len);
2209  }
2210  
2211 @@ -402,46 +402,115 @@
2212  
2213  
2214  /**
2215 - * init the buffer 
2216 - * 
2217 + * init the ptr buffer
2218 + *
2219 + */
2220 +buffer_ptr *buffer_ptr_init(buffer_ptr_free_t freer)
2221 +{
2222 +       buffer_ptr *l = calloc(1, sizeof(buffer_ptr));
2223 +       l->free = freer;
2224 +
2225 +       return l;
2226 +}
2227 +
2228 +/**
2229 + * free the buffer_array
2230 + *
2231 + */
2232 +void buffer_ptr_free(buffer_ptr *l)
2233 +{
2234 +       if (NULL != l) {
2235 +               buffer_ptr_clear(l);
2236 +               free(l);
2237 +       }
2238 +}
2239 +
2240 +void buffer_ptr_clear(buffer_ptr *l)
2241 +{
2242 +       assert(NULL != l);
2243 +
2244 +       if (l->free && l->used) {
2245 +               size_t i;
2246 +               for (i = 0; i < l->used; i ++) {
2247 +                       l->free(l->ptr[i]);
2248 +               }
2249 +       }
2250 +
2251 +       if (l->ptr) {
2252 +               free(l->ptr);
2253 +               l->ptr = NULL;
2254 +       }
2255 +       l->used = 0;
2256 +       l->size = 0;
2257 +}
2258 +
2259 +void buffer_ptr_append(buffer_ptr* l, void *item)
2260 +{
2261 +       assert(NULL != l);
2262 +       if (l->ptr == NULL) {
2263 +               l->size = 16;
2264 +               l->ptr = (void **)malloc(sizeof(void *) * l->size);
2265 +       }
2266 +       else if (l->used == l->size) {
2267 +               l->size += 16;
2268 +               l->ptr = realloc(l->ptr, sizeof(void *) * l->size);
2269 +       }
2270 +       l->ptr[l->used++] = item;
2271 +}
2272 +
2273 +void *buffer_ptr_pop(buffer_ptr* l)
2274 +{
2275 +       assert(NULL != l && l->used > 0);
2276 +       return l->ptr[--l->used];
2277 +}
2278 +
2279 +void *buffer_ptr_top(buffer_ptr* l)
2280 +{
2281 +       assert(NULL != l && l->used > 0);
2282 +       return l->ptr[l->used-1];
2283 +}
2284 +
2285 +/**
2286 + * init the buffer
2287 + *
2288   */
2289  
2290  buffer_array* buffer_array_init(void) {
2291         buffer_array *b;
2292 -       
2293 +
2294         b = malloc(sizeof(*b));
2295 -       
2296 +
2297         assert(b);
2298         b->ptr = NULL;
2299         b->size = 0;
2300         b->used = 0;
2301 -       
2302 +
2303         return b;
2304  }
2305  
2306  void buffer_array_reset(buffer_array *b) {
2307         size_t i;
2308 -       
2309 +
2310         if (!b) return;
2311 -       
2312 +
2313         /* if they are too large, reduce them */
2314         for (i = 0; i < b->used; i++) {
2315                 buffer_reset(b->ptr[i]);
2316         }
2317 -       
2318 +
2319         b->used = 0;
2320  }
2321  
2322  
2323  /**
2324 - * free the buffer_array 
2325 - * 
2326 + * free the buffer_array
2327 + *
2328   */
2329  
2330  void buffer_array_free(buffer_array *b) {
2331         size_t i;
2332         if (!b) return;
2333 -       
2334 +
2335         for (i = 0; i < b->size; i++) {
2336                 if (b->ptr[i]) buffer_free(b->ptr[i]);
2337         }
2338 @@ -451,7 +520,7 @@
2339  
2340  buffer *buffer_array_append_get_buffer(buffer_array *b) {
2341         size_t i;
2342 -       
2343 +
2344         if (b->size == 0) {
2345                 b->size = 16;
2346                 b->ptr = malloc(sizeof(*b->ptr) * b->size);
2347 @@ -467,13 +536,13 @@
2348                         b->ptr[i] = NULL;
2349                 }
2350         }
2351 -       
2352 +
2353         if (b->ptr[b->used] == NULL) {
2354                 b->ptr[b->used] = buffer_init();
2355         }
2356 -       
2357 +
2358         b->ptr[b->used]->used = 0;
2359 -       
2360 +
2361         return b->ptr[b->used++];
2362  }
2363  
2364 @@ -482,23 +551,23 @@
2365         size_t i;
2366         if (len == 0) return NULL;
2367         if (needle == NULL) return NULL;
2368 -       
2369 +
2370         if (b->used < len) return NULL;
2371 -       
2372 +
2373         for(i = 0; i < b->used - len; i++) {
2374                 if (0 == memcmp(b->ptr + i, needle, len)) {
2375                         return b->ptr + i;
2376                 }
2377         }
2378 -       
2379 +
2380         return NULL;
2381  }
2382  
2383  buffer *buffer_init_string(const char *str) {
2384         buffer *b = buffer_init();
2385 -       
2386 +
2387         buffer_copy_string(b, str);
2388 -       
2389 +
2390         return b;
2391  }
2392  
2393 @@ -507,8 +576,8 @@
2394  }
2395  
2396  /**
2397 - * check if two buffer contain the same data
2398 - * 
2399 + * check if two buffers contain the same data
2400 + *
2401   * HISTORY: this function was pretty much optimized, but didn't handled
2402   * alignment properly.
2403   */
2404 @@ -517,105 +586,105 @@
2405         if (a->used != b->used) return 0;
2406         if (a->used == 0) return 1;
2407  
2408 -       return (0 == strcmp(a->ptr, b->ptr));
2409 +       return (0 == strncmp(a->ptr, b->ptr, a->used - 1));
2410  }
2411  
2412  int buffer_is_equal_string(buffer *a, const char *s, size_t b_len) {
2413         buffer b;
2414 -       
2415 +
2416         b.ptr = (char *)s;
2417         b.used = b_len + 1;
2418 -       
2419 +
2420         return buffer_is_equal(a, &b);
2421  }
2422  
2423  /* simple-assumption:
2424 - * 
2425 - * most parts are equal and doing a case conversion needs time
2426 - * 
2427 + *
2428 + * most parts are equal and doing a case conversion takes time
2429 + *
2430   */
2431  int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b_len) {
2432         size_t ndx = 0, max_ndx;
2433         size_t *al, *bl;
2434         size_t mask = sizeof(*al) - 1;
2435 -       
2436 +
2437         al = (size_t *)a;
2438         bl = (size_t *)b;
2439 -       
2440 -       /* is the alignment correct ? */
2441 +
2442 +       /* is the alignment correct? */
2443         if ( ((size_t)al & mask) == 0 &&
2444              ((size_t)bl & mask) == 0 ) {
2445 -               
2446 +
2447                 max_ndx = ((a_len < b_len) ? a_len : b_len) & ~mask;
2448 -               
2449 +
2450                 for (; ndx < max_ndx; ndx += sizeof(*al)) {
2451                         if (*al != *bl) break;
2452                         al++; bl++;
2453 -                       
2454 +
2455                 }
2456 -               
2457 +
2458         }
2459 -       
2460 +
2461         a = (char *)al;
2462         b = (char *)bl;
2463 -       
2464 +
2465         max_ndx = ((a_len < b_len) ? a_len : b_len);
2466 -       
2467 +
2468         for (; ndx < max_ndx; ndx++) {
2469                 char a1 = *a++, b1 = *b++;
2470 -               
2471 +
2472                 if (a1 != b1) {
2473                         if ((a1 >= 'A' && a1 <= 'Z') && (b1 >= 'a' && b1 <= 'z'))
2474                                 a1 |= 32;
2475                         else if ((a1 >= 'a' && a1 <= 'z') && (b1 >= 'A' && b1 <= 'Z'))
2476                                 b1 |= 32;
2477                         if ((a1 - b1) != 0) return (a1 - b1);
2478 -                       
2479 +
2480                 }
2481         }
2482 -       
2483 +
2484         return 0;
2485  }
2486  
2487  
2488  /**
2489   * check if the rightmost bytes of the string are equal.
2490 - * 
2491 - * 
2492 + *
2493 + *
2494   */
2495  
2496  int buffer_is_equal_right_len(buffer *b1, buffer *b2, size_t len) {
2497         /* no, len -> equal */
2498         if (len == 0) return 1;
2499 -       
2500 +
2501         /* len > 0, but empty buffers -> not equal */
2502         if (b1->used == 0 || b2->used == 0) return 0;
2503 -       
2504 +
2505         /* buffers too small -> not equal */
2506 -       if (b1->used - 1 < len || b1->used - 1 < len) return 0;
2507 -       
2508 -       if (0 == strncmp(b1->ptr + b1->used - 1 - len, 
2509 +       if (b1->used - 1 < len || b2->used - 1 < len) return 0;
2510 +
2511 +       if (0 == strncmp(b1->ptr + b1->used - 1 - len,
2512                          b2->ptr + b2->used - 1 - len, len)) {
2513                 return 1;
2514         }
2515 -       
2516 +
2517         return 0;
2518  }
2519  
2520  int buffer_copy_string_hex(buffer *b, const char *in, size_t in_len) {
2521         size_t i;
2522 -       
2523 +
2524         /* BO protection */
2525         if (in_len * 2 < in_len) return -1;
2526 -       
2527 +
2528         buffer_prepare_copy(b, in_len * 2 + 1);
2529 -       
2530 +
2531         for (i = 0; i < in_len; i++) {
2532                 b->ptr[b->used++] = hex_chars[(in[i] >> 4) & 0x0F];
2533                 b->ptr[b->used++] = hex_chars[in[i] & 0x0F];
2534         }
2535         b->ptr[b->used++] = '\0';
2536 -       
2537 +
2538         return 0;
2539  }
2540  
2541 @@ -624,7 +693,7 @@
2542         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2543         */
2544         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2545 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2546 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2547         1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1,  /*  20 -  2F space " # $ % & ' + , / */
2548         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,  /*  30 -  3F : ; = ? @ < > */
2549         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
2550 @@ -646,7 +715,7 @@
2551         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2552         */
2553         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2554 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2555 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2556         1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0,  /*  20 -  2F space " # $ % & ' + , / */
2557         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,  /*  30 -  3F : ; = ? @ < > */
2558         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
2559 @@ -668,7 +737,7 @@
2560         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2561         */
2562         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2563 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2564 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2565         0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  20 -  2F & */
2566         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,  /*  30 -  3F < > */
2567         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
2568 @@ -690,7 +759,7 @@
2569         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2570         */
2571         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2572 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2573 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2574         0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  20 -  2F & */
2575         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,  /*  30 -  3F < > */
2576         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
2577 @@ -712,12 +781,12 @@
2578         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2579         */
2580         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2581 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2582 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  20 -  2F */ 
2583 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  30 -  3F */ 
2584 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  40 -  4F */ 
2585 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  50 -  5F */ 
2586 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  60 -  6F */ 
2587 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2588 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  20 -  2F */
2589 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  30 -  3F */
2590 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  40 -  4F */
2591 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  50 -  5F */
2592 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  60 -  6F */
2593         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  70 -  7F */
2594         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */
2595         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  90 -  9F */
2596 @@ -734,13 +803,12 @@
2597         unsigned char *ds, *d;
2598         size_t d_len, ndx;
2599         const char *map = NULL;
2600 -       
2601 +
2602         if (!s || !b) return -1;
2603 -       
2604 -       if (b->ptr[b->used - 1] != '\0') {
2605 -               SEGFAULT();
2606 -       }
2607 -       
2608 +       if (b->used == 0) return -1;
2609 +
2610 +       if (b->ptr[b->used - 1] != '\0') return -1;
2611 +
2612         if (s_len == 0) return 0;
2613  
2614         switch(encoding) {
2615 @@ -760,12 +828,12 @@
2616                 map = encoded_chars_hex;
2617                 break;
2618         case ENCODING_UNSET:
2619 -               break;
2620 +               return buffer_append_string_len(b, s, s_len);
2621         }
2622  
2623         assert(map != NULL);
2624 -       
2625 -       /* count to-be-encoded-characters */
2626 +
2627 +       /* count to-be-encoded characters */
2628         for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
2629                 if (map[*ds]) {
2630                         switch(encoding) {
2631 @@ -787,9 +855,9 @@
2632                         d_len ++;
2633                 }
2634         }
2635 -       
2636 +
2637         buffer_prepare_append(b, d_len);
2638 -       
2639 +
2640         for (ds = (unsigned char *)s, d = (unsigned char *)b->ptr + b->used - 1, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
2641                 if (map[*ds]) {
2642                         switch(encoding) {
2643 @@ -820,16 +888,16 @@
2644                 }
2645         }
2646  
2647 -       /* terminate buffer and calculate new length */ 
2648 +       /* terminate buffer and calculate new length */
2649         b->ptr[b->used + d_len - 1] = '\0';
2650 -       
2651 +
2652         b->used += d_len;
2653  
2654         return 0;
2655  }
2656  
2657  
2658 -/* decodes url-special-chars inplace.
2659 +/* decodes url-special chars in-place.
2660   * replaces non-printable characters with '_'
2661   */
2662  
2663 @@ -854,10 +922,10 @@
2664                                 low = hex2int(*(src + 2));
2665                                 if (low != 0xFF) {
2666                                         high = (high << 4) | low;
2667 -                                       
2668 -                                       /* map control-characters out */        
2669 +
2670 +                                       /* map out control characters */
2671                                         if (high < 32 || high == 127) high = '_';
2672 -                                       
2673 +
2674                                         *dst = high;
2675                                         src += 2;
2676                                 }
2677 @@ -891,7 +959,7 @@
2678   * /abc/./xyz       gets  /abc/xyz
2679   * /abc//xyz        gets  /abc/xyz
2680   *
2681 - * NOTE: src and dest can point to the same buffer, in which case,
2682 + * NOTE: src and dest can point to the same buffer, in which case
2683   *       the operation is performed in-place.
2684   */
2685  
2686 @@ -979,7 +1047,7 @@
2687  
2688  int light_isxdigit(int c) {
2689         if (light_isdigit(c)) return 1;
2690 -       
2691 +
2692         c |= 32;
2693         return (c >= 'a' && c <= 'f');
2694  }
2695 @@ -993,31 +1061,56 @@
2696         return light_isdigit(c) || light_isalpha(c);
2697  }
2698  
2699 +#undef BUFFER_CTYPE_FUNC
2700 +#define BUFFER_CTYPE_FUNC(type) \
2701 +       int buffer_is##type(buffer *b) { \
2702 +               size_t i, len; \
2703 +               if (b->used < 2) return 0; \
2704 +               /* strlen */ \
2705 +               len = b->used - 1; \
2706 +               /* c-string only */ \
2707 +               if (b->ptr[len] != '\0') { \
2708 +                       return 0; \
2709 +               } \
2710 +               /* check on the whole string */ \
2711 +               for (i = 0; i < len; i ++) { \
2712 +                       if (!light_is##type(b->ptr[i])) { \
2713 +                               return 0; \
2714 +                       } \
2715 +               } \
2716 +               return 1; \
2717 +       }
2718 +
2719 +BUFFER_CTYPE_FUNC(digit)
2720 +BUFFER_CTYPE_FUNC(xdigit)
2721 +BUFFER_CTYPE_FUNC(alpha)
2722 +BUFFER_CTYPE_FUNC(alnum)
2723 +
2724  int buffer_to_lower(buffer *b) {
2725         char *c;
2726 -       
2727 +
2728         if (b->used == 0) return 0;
2729 -       
2730 +
2731         for (c = b->ptr; *c; c++) {
2732                 if (*c >= 'A' && *c <= 'Z') {
2733                         *c |= 32;
2734                 }
2735         }
2736 -       
2737 +
2738         return 0;
2739  }
2740  
2741  
2742  int buffer_to_upper(buffer *b) {
2743         char *c;
2744 -       
2745 +
2746         if (b->used == 0) return 0;
2747 -       
2748 +
2749         for (c = b->ptr; *c; c++) {
2750                 if (*c >= 'a' && *c <= 'z') {
2751                         *c &= ~32;
2752                 }
2753         }
2754 -       
2755 +
2756         return 0;
2757  }
2758 --- ../lighttpd-1.4.11/src/buffer.h     2006-01-13 00:00:45.000000000 +0200
2759 +++ lighttpd-1.4.12/src/buffer.h        2006-07-18 13:03:40.000000000 +0300
2760 @@ -12,27 +12,43 @@
2761  
2762  typedef struct {
2763         char *ptr;
2764 -       
2765 +
2766         size_t used;
2767         size_t size;
2768  } buffer;
2769  
2770 +typedef void (*buffer_ptr_free_t)(void *p);
2771 +
2772 +typedef struct {
2773 +       void **ptr;
2774 +       size_t size;
2775 +       size_t used;
2776 +       buffer_ptr_free_t free;
2777 +} buffer_ptr;
2778 +
2779  typedef struct {
2780         buffer **ptr;
2781 -       
2782 +
2783         size_t used;
2784         size_t size;
2785  } buffer_array;
2786  
2787  typedef struct {
2788         char *ptr;
2789 -       
2790 -       size_t offset; /* input-pointer */
2791 -       
2792 -       size_t used;   /* output-pointer */
2793 +
2794 +       size_t offset; /* input pointer */
2795 +
2796 +       size_t used;   /* output pointer */
2797         size_t size;
2798  } read_buffer;
2799  
2800 +buffer_ptr *buffer_ptr_init(buffer_ptr_free_t freer);
2801 +void buffer_ptr_free(buffer_ptr *b);
2802 +void buffer_ptr_clear(buffer_ptr *b);
2803 +void buffer_ptr_append(buffer_ptr *b, void *item);
2804 +void *buffer_ptr_pop(buffer_ptr *b);
2805 +void *buffer_ptr_top(buffer_ptr *b);
2806 +
2807  buffer_array* buffer_array_init(void);
2808  void buffer_array_free(buffer_array *b);
2809  void buffer_array_reset(buffer_array *b);
2810 @@ -43,7 +59,7 @@
2811  buffer* buffer_init_string(const char *str);
2812  void buffer_free(buffer *b);
2813  void buffer_reset(buffer *b);
2814 -       
2815 +
2816  int buffer_prepare_copy(buffer *b, size_t size);
2817  int buffer_prepare_append(buffer *b, size_t size);
2818  
2819 @@ -85,9 +101,9 @@
2820  
2821  typedef enum {
2822         ENCODING_UNSET,
2823 -       ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of a href */
2824 -       ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus coding / too as %2F */
2825 -       ENCODING_HTML,    /* & becomes &amp; and so on */
2826 +       ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of an href */
2827 +       ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus encoding "/" as "%2F" */
2828 +       ENCODING_HTML,    /* "&" becomes "&amp;" and so on */
2829         ENCODING_MINIMAL_XML, /* minimal encoding for xml */
2830         ENCODING_HEX      /* encode string as hex */
2831  } buffer_encoding_t;
2832 @@ -111,20 +127,23 @@
2833  int light_isalpha(int c);
2834  int light_isalnum(int c);
2835  
2836 +#define BUFFER_CTYPE_FUNC(type) int buffer_is##type(buffer *b);
2837 +BUFFER_CTYPE_FUNC(digit)
2838 +BUFFER_CTYPE_FUNC(xdigit)
2839 +BUFFER_CTYPE_FUNC(alpha)
2840 +BUFFER_CTYPE_FUNC(alnum)
2841 +
2842 +#define BUF_STR(x) x->ptr
2843  #define BUFFER_APPEND_STRING_CONST(x, y) \
2844         buffer_append_string_len(x, y, sizeof(y) - 1)
2845  
2846  #define BUFFER_COPY_STRING_CONST(x, y) \
2847         buffer_copy_string_len(x, y, sizeof(y) - 1)
2848  
2849 -#define BUFFER_APPEND_SLASH(x) \
2850 -       if (x->used > 1 && x->ptr[x->used - 2] != '/') { BUFFER_APPEND_STRING_CONST(x, "/"); }
2851 -
2852  #define CONST_STR_LEN(x) x, x ? sizeof(x) - 1 : 0
2853 -#define CONST_BUF_LEN(x) x->ptr, x->used ? x->used - 1 : 0
2854 +#define CONST_BUF_LEN(x) BUF_STR(x), x->used ? x->used - 1 : 0
2855  
2856 -
2857 -#define SEGFAULT() do { fprintf(stderr, "%s.%d: aborted\n", __FILE__, __LINE__); abort(); } while(0)
2858 +       
2859  #define UNUSED(x) ( (void)(x) )
2860  
2861  #endif
2862 --- ../lighttpd-1.4.11/src/chunk.c      2005-11-18 15:18:19.000000000 +0200
2863 +++ lighttpd-1.4.12/src/chunk.c 2006-07-18 13:03:40.000000000 +0300
2864 @@ -1,16 +1,14 @@
2865  /**
2866   * the network chunk-API
2867 - * 
2868 - * 
2869 + *
2870 + *
2871   */
2872  
2873  #include <sys/types.h>
2874  #include <sys/stat.h>
2875 -#include <sys/mman.h>
2876  
2877  #include <stdlib.h>
2878  #include <fcntl.h>
2879 -#include <unistd.h>
2880  
2881  #include <stdio.h>
2882  #include <errno.h>
2883 @@ -18,36 +16,39 @@
2884  
2885  #include "chunk.h"
2886  
2887 +#include "sys-mmap.h"
2888 +#include "sys-files.h"
2889 +
2890  chunkqueue *chunkqueue_init(void) {
2891         chunkqueue *cq;
2892 -       
2893 +
2894         cq = calloc(1, sizeof(*cq));
2895 -       
2896 +
2897         cq->first = NULL;
2898         cq->last = NULL;
2899 -       
2900 +
2901         cq->unused = NULL;
2902 -       
2903 +
2904         return cq;
2905  }
2906  
2907  static chunk *chunk_init(void) {
2908         chunk *c;
2909 -       
2910 +
2911         c = calloc(1, sizeof(*c));
2912 -       
2913 +
2914         c->mem = buffer_init();
2915         c->file.name = buffer_init();
2916         c->file.fd = -1;
2917         c->file.mmap.start = MAP_FAILED;
2918         c->next = NULL;
2919 -       
2920 +
2921         return c;
2922  }
2923  
2924  static void chunk_free(chunk *c) {
2925         if (!c) return;
2926 -       
2927 +
2928         buffer_free(c->mem);
2929         buffer_free(c->file.name);
2930  
2931 @@ -56,13 +57,13 @@
2932  
2933  static void chunk_reset(chunk *c) {
2934         if (!c) return;
2935 -       
2936 +
2937         buffer_reset(c->mem);
2938  
2939         if (c->file.is_temp && !buffer_is_empty(c->file.name)) {
2940                 unlink(c->file.name->ptr);
2941         }
2942 -       
2943 +
2944         buffer_reset(c->file.name);
2945  
2946         if (c->file.fd != -1) {
2947 @@ -78,28 +79,28 @@
2948  
2949  void chunkqueue_free(chunkqueue *cq) {
2950         chunk *c, *pc;
2951 -       
2952 +
2953         if (!cq) return;
2954 -       
2955 +
2956         for (c = cq->first; c; ) {
2957                 pc = c;
2958                 c = c->next;
2959                 chunk_free(pc);
2960         }
2961 -       
2962 +
2963         for (c = cq->unused; c; ) {
2964                 pc = c;
2965                 c = c->next;
2966                 chunk_free(pc);
2967         }
2968 -       
2969 +
2970         free(cq);
2971  }
2972  
2973  static chunk *chunkqueue_get_unused_chunk(chunkqueue *cq) {
2974         chunk *c;
2975 -       
2976 -       /* check if we have a unused chunk */
2977 +
2978 +       /* check if we have an unused chunk */
2979         if (!cq->unused) {
2980                 c = chunk_init();
2981         } else {
2982 @@ -109,18 +110,18 @@
2983                 c->next = NULL;
2984                 cq->unused_chunks--;
2985         }
2986 -       
2987 +
2988         return c;
2989  }
2990  
2991  static int chunkqueue_prepend_chunk(chunkqueue *cq, chunk *c) {
2992         c->next = cq->first;
2993         cq->first = c;
2994 -       
2995 +
2996         if (cq->last == NULL) {
2997                 cq->last = c;
2998         }
2999 -       
3000 +
3001         return 0;
3002  }
3003  
3004 @@ -129,19 +130,19 @@
3005                 cq->last->next = c;
3006         }
3007         cq->last = c;
3008 -       
3009 +
3010         if (cq->first == NULL) {
3011                 cq->first = c;
3012         }
3013 -       
3014 +
3015         return 0;
3016  }
3017  
3018  void chunkqueue_reset(chunkqueue *cq) {
3019         chunk *c;
3020         /* move everything to the unused queue */
3021 -       
3022 -       /* mark all read written */ 
3023 +
3024 +       /* mark all read written */
3025         for (c = cq->first; c; c = c->next) {
3026                 switch(c->type) {
3027                 case MEM_CHUNK:
3028 @@ -150,7 +151,7 @@
3029                 case FILE_CHUNK:
3030                         c->offset = c->file.length;
3031                         break;
3032 -               default: 
3033 +               default:
3034                         break;
3035                 }
3036         }
3037 @@ -162,93 +163,93 @@
3038  
3039  int chunkqueue_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len) {
3040         chunk *c;
3041 -       
3042 +
3043         if (len == 0) return 0;
3044 -       
3045 +
3046         c = chunkqueue_get_unused_chunk(cq);
3047 -       
3048 +
3049         c->type = FILE_CHUNK;
3050 -       
3051 +
3052         buffer_copy_string_buffer(c->file.name, fn);
3053         c->file.start = offset;
3054         c->file.length = len;
3055         c->offset = 0;
3056 -       
3057 +
3058         chunkqueue_append_chunk(cq, c);
3059 -       
3060 +
3061         return 0;
3062  }
3063  
3064  int chunkqueue_append_buffer(chunkqueue *cq, buffer *mem) {
3065         chunk *c;
3066 -       
3067 +
3068         if (mem->used == 0) return 0;
3069 -       
3070 +
3071         c = chunkqueue_get_unused_chunk(cq);
3072         c->type = MEM_CHUNK;
3073         c->offset = 0;
3074         buffer_copy_string_buffer(c->mem, mem);
3075 -       
3076 +
3077         chunkqueue_append_chunk(cq, c);
3078 -       
3079 +
3080         return 0;
3081  }
3082  
3083  int chunkqueue_prepend_buffer(chunkqueue *cq, buffer *mem) {
3084         chunk *c;
3085 -       
3086 +
3087         if (mem->used == 0) return 0;
3088 -       
3089 +
3090         c = chunkqueue_get_unused_chunk(cq);
3091         c->type = MEM_CHUNK;
3092         c->offset = 0;
3093         buffer_copy_string_buffer(c->mem, mem);
3094 -       
3095 +
3096         chunkqueue_prepend_chunk(cq, c);
3097 -       
3098 +
3099         return 0;
3100  }
3101  
3102  int chunkqueue_append_mem(chunkqueue *cq, const char * mem, size_t len) {
3103         chunk *c;
3104 -       
3105 +
3106         if (len == 0) return 0;
3107 -       
3108 +
3109         c = chunkqueue_get_unused_chunk(cq);
3110         c->type = MEM_CHUNK;
3111         c->offset = 0;
3112         buffer_copy_string_len(c->mem, mem, len - 1);
3113 -       
3114 +
3115         chunkqueue_append_chunk(cq, c);
3116 -       
3117 +
3118         return 0;
3119  }
3120  
3121  buffer * chunkqueue_get_prepend_buffer(chunkqueue *cq) {
3122         chunk *c;
3123 -       
3124 +
3125         c = chunkqueue_get_unused_chunk(cq);
3126 -       
3127 +
3128         c->type = MEM_CHUNK;
3129         c->offset = 0;
3130         buffer_reset(c->mem);
3131 -       
3132 +
3133         chunkqueue_prepend_chunk(cq, c);
3134 -       
3135 +
3136         return c->mem;
3137  }
3138  
3139  buffer *chunkqueue_get_append_buffer(chunkqueue *cq) {
3140         chunk *c;
3141 -       
3142 +
3143         c = chunkqueue_get_unused_chunk(cq);
3144 -       
3145 +
3146         c->type = MEM_CHUNK;
3147         c->offset = 0;
3148         buffer_reset(c->mem);
3149 -       
3150 +
3151         chunkqueue_append_chunk(cq, c);
3152 -       
3153 +
3154         return c->mem;
3155  }
3156  
3157 @@ -263,7 +264,7 @@
3158  chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) {
3159         chunk *c;
3160         buffer *template = buffer_init_string("/var/tmp/lighttpd-upload-XXXXXX");
3161 -       
3162 +
3163         c = chunkqueue_get_unused_chunk(cq);
3164  
3165         c->type = FILE_CHUNK;
3166 @@ -273,12 +274,12 @@
3167                 size_t i;
3168  
3169                 /* we have several tempdirs, only if all of them fail we jump out */
3170 -               
3171 +
3172                 for (i = 0; i < cq->tempdirs->used; i++) {
3173                         data_string *ds = (data_string *)cq->tempdirs->data[i];
3174  
3175                         buffer_copy_string_buffer(template, ds->value);
3176 -                       BUFFER_APPEND_SLASH(template);
3177 +                       PATHNAME_APPEND_SLASH(template);
3178                         BUFFER_APPEND_STRING_CONST(template, "lighttpd-upload-XXXXXX");
3179  
3180                         if (-1 != (c->file.fd = mkstemp(template->ptr))) {
3181 @@ -300,7 +301,7 @@
3182         chunkqueue_append_chunk(cq, c);
3183  
3184         buffer_free(template);
3185 -       
3186 +
3187         return c;
3188  }
3189  
3190 @@ -308,7 +309,7 @@
3191  off_t chunkqueue_length(chunkqueue *cq) {
3192         off_t len = 0;
3193         chunk *c;
3194 -       
3195 +
3196         for (c = cq->first; c; c = c->next) {
3197                 switch (c->type) {
3198                 case MEM_CHUNK:
3199 @@ -321,14 +322,14 @@
3200                         break;
3201                 }
3202         }
3203 -       
3204 +
3205         return len;
3206  }
3207  
3208  off_t chunkqueue_written(chunkqueue *cq) {
3209         off_t len = 0;
3210         chunk *c;
3211 -       
3212 +
3213         for (c = cq->first; c; c = c->next) {
3214                 switch (c->type) {
3215                 case MEM_CHUNK:
3216 @@ -339,7 +340,7 @@
3217                         break;
3218                 }
3219         }
3220 -       
3221 +
3222         return len;
3223  }
3224  
3225 @@ -355,12 +356,13 @@
3226  
3227                 switch (c->type) {
3228                 case MEM_CHUNK:
3229 +                       if (c->mem->used == 0) is_finished = 1;
3230                         if (c->offset == (off_t)c->mem->used - 1) is_finished = 1;
3231                         break;
3232                 case FILE_CHUNK:
3233 -                       if (c->offset == c->file.length) is_finished = 1; 
3234 +                       if (c->offset == c->file.length) is_finished = 1;
3235                         break;
3236 -               default: 
3237 +               default:
3238                         break;
3239                 }
3240  
3241 @@ -383,3 +385,50 @@
3242  
3243         return 0;
3244  }
3245 +
3246 +void chunkqueue_print(chunkqueue *cq) {
3247 +       chunk *c;
3248 +
3249 +       for (c = cq->first; c; c = c->next) {
3250 +               fprintf(stderr, "(mem) %s", c->mem->ptr + c->offset);
3251 +       }
3252 +       fprintf(stderr, "\r\n");
3253 +}
3254 +
3255 +
3256 +/**
3257 + * remove the last chunk if it is empty
3258 + */
3259 +
3260 +void chunkqueue_remove_empty_last_chunk(chunkqueue *cq) {
3261 +       chunk *c;
3262 +       if (!cq->last) return;
3263 +       if (!cq->first) return;
3264 +
3265 +       if (cq->first == cq->last) {
3266 +               c = cq->first;
3267 +
3268 +               if (c->type != MEM_CHUNK) return;
3269 +               if (c->mem->used == 0) {
3270 +                       chunk_free(c);
3271 +                       cq->first = cq->last = NULL;
3272 +               }
3273 +               return;
3274 +       }
3275 +
3276 +       for (c = cq->first; c->next; c = c->next) {
3277 +               if (c->type != MEM_CHUNK) continue;
3278 +               if (c->mem->used != 0) continue;
3279 +
3280 +               if (c->next == cq->last) {
3281 +                       cq->last = c;
3282 +
3283 +                       chunk_free(c->next);
3284 +                       c->next = NULL;
3285 +
3286 +                       return;
3287 +               }
3288 +       }
3289 +}
3290 +
3291 +
3292 --- ../lighttpd-1.4.11/src/chunk.h      2005-11-01 09:32:21.000000000 +0200
3293 +++ lighttpd-1.4.12/src/chunk.h 2006-07-18 13:03:40.000000000 +0300
3294 @@ -6,7 +6,7 @@
3295  
3296  typedef struct chunk {
3297         enum { UNUSED_CHUNK, MEM_CHUNK, FILE_CHUNK } type;
3298 -       
3299 +
3300         buffer *mem; /* either the storage of the mem-chunk or the read-ahead buffer */
3301  
3302         struct {
3303 @@ -16,28 +16,28 @@
3304                 off_t  length; /* octets to send from the starting offset */
3305  
3306                 int    fd;
3307 -               struct { 
3308 +               struct {
3309                         char   *start; /* the start pointer of the mmap'ed area */
3310                         size_t length; /* size of the mmap'ed area */
3311 -                       off_t  offset; /* start is <n> octet away from the start of the file */
3312 +                       off_t  offset; /* start is <n> octets away from the start of the file */
3313                 } mmap;
3314  
3315 -               int is_temp; /* file is temporary and will be deleted if on cleanup */
3316 +               int is_temp; /* file is temporary and will be deleted on cleanup */
3317         } file;
3318 -       
3319 -       off_t  offset; /* octets sent from this chunk 
3320 -                         the size of the chunk is either 
3321 +
3322 +       off_t  offset; /* octets sent from this chunk
3323 +                         the size of the chunk is either
3324                           - mem-chunk: mem->used - 1
3325                           - file-chunk: file.length
3326                         */
3327 -       
3328 +
3329         struct chunk *next;
3330  } chunk;
3331  
3332  typedef struct {
3333         chunk *first;
3334         chunk *last;
3335 -       
3336 +
3337         chunk *unused;
3338         size_t unused_chunks;
3339  
3340 @@ -56,6 +56,7 @@
3341  buffer * chunkqueue_get_append_buffer(chunkqueue *c);
3342  buffer * chunkqueue_get_prepend_buffer(chunkqueue *c);
3343  chunk * chunkqueue_get_append_tempfile(chunkqueue *cq);
3344 +void chunkqueue_remove_empty_last_chunk(chunkqueue *cq);
3345  
3346  int chunkqueue_remove_finished_chunks(chunkqueue *cq);
3347  
3348 @@ -66,4 +67,6 @@
3349  
3350  int chunkqueue_is_empty(chunkqueue *c);
3351  
3352 +void chunkqueue_print(chunkqueue *cq);
3353 +
3354  #endif
3355 --- ../lighttpd-1.4.11/src/configfile-glue.c    2006-03-03 20:14:56.000000000 +0200
3356 +++ lighttpd-1.4.12/src/configfile-glue.c       2006-07-16 00:26:03.000000000 +0300
3357 @@ -1,4 +1,5 @@
3358  #include <string.h>
3359 +#include <ctype.h>
3360  
3361  #include "base.h"
3362  #include "buffer.h"
3363 @@ -11,10 +12,10 @@
3364   * are the external interface of lighttpd. The functions
3365   * are used by the server itself and the plugins.
3366   *
3367 - * The main-goal is to have a small library in the end 
3368 - * which is linked against both and which will define 
3369 + * The main-goal is to have a small library in the end
3370 + * which is linked against both and which will define
3371   * the interface itself in the end.
3372 - * 
3373 + *
3374   */
3375  
3376  
3377 @@ -24,56 +25,60 @@
3378  int config_insert_values_internal(server *srv, array *ca, const config_values_t cv[]) {
3379         size_t i;
3380         data_unset *du;
3381 -       
3382 +
3383         for (i = 0; cv[i].key; i++) {
3384 -               
3385 +
3386                 if (NULL == (du = array_get_element(ca, cv[i].key))) {
3387                         /* no found */
3388 -                       
3389 +
3390                         continue;
3391                 }
3392 -               
3393 +
3394                 switch (cv[i].type) {
3395                 case T_CONFIG_ARRAY:
3396                         if (du->type == TYPE_ARRAY) {
3397                                 size_t j;
3398                                 data_array *da = (data_array *)du;
3399 -                               
3400 +
3401                                 for (j = 0; j < da->value->used; j++) {
3402                                         if (da->value->data[j]->type == TYPE_STRING) {
3403                                                 data_string *ds = data_string_init();
3404 -                                               
3405 +
3406                                                 buffer_copy_string_buffer(ds->value, ((data_string *)(da->value->data[j]))->value);
3407                                                 if (!da->is_index_key) {
3408                                                         /* the id's were generated automaticly, as we copy now we might have to renumber them
3409 -                                                        * this is used to prepend server.modules by mod_indexfiles as it has to be loaded 
3410 +                                                        * this is used to prepend server.modules by mod_indexfiles as it has to be loaded
3411                                                          * before mod_fastcgi and friends */
3412                                                         buffer_copy_string_buffer(ds->key, ((data_string *)(da->value->data[j]))->key);
3413                                                 }
3414 -                                               
3415 +
3416                                                 array_insert_unique(cv[i].destination, (data_unset *)ds);
3417                                         } else {
3418 -                                               log_error_write(srv, __FILE__, __LINE__, "sssd", 
3419 -                                                               "the key of and array can only be a string or a integer, variable:", 
3420 -                                                               cv[i].key, "type:", da->value->data[j]->type); 
3421 -                                               
3422 +                                               log_error_write(srv, __FILE__, __LINE__, "sssd",
3423 +                                                               "the key of and array can only be a string or a integer, variable:",
3424 +                                                               cv[i].key, "type:", da->value->data[j]->type);
3425 +
3426                                                 return -1;
3427                                         }
3428                                 }
3429                         } else {
3430                                 log_error_write(srv, __FILE__, __LINE__, "sss", "unexpected type for key: ", cv[i].key, "array of strings");
3431 -                               
3432 +
3433                                 return -1;
3434                         }
3435                         break;
3436                 case T_CONFIG_STRING:
3437                         if (du->type == TYPE_STRING) {
3438                                 data_string *ds = (data_string *)du;
3439 -                               
3440 +
3441                                 buffer_copy_string_buffer(cv[i].destination, ds->value);
3442 +                       } else if (du->type == TYPE_INTEGER) {
3443 +                               data_integer *di = (data_integer *)du;
3444 +
3445 +                               buffer_copy_long(cv[i].destination, di->value);
3446                         } else {
3447                                 log_error_write(srv, __FILE__, __LINE__, "ssss", "unexpected type for key: ", cv[i].key, "(string)", "\"...\"");
3448 -                               
3449 +
3450                                 return -1;
3451                         }
3452                         break;
3453 @@ -81,15 +86,20 @@
3454                         switch(du->type) {
3455                         case TYPE_INTEGER: {
3456                                 data_integer *di = (data_integer *)du;
3457 -                               
3458 +
3459                                 *((unsigned short *)(cv[i].destination)) = di->value;
3460                                 break;
3461                         }
3462                         case TYPE_STRING: {
3463                                 data_string *ds = (data_string *)du;
3464 -                                       
3465 +
3466 +                               if (buffer_isdigit(ds->value)) {
3467 +                                       *((unsigned short *)(cv[i].destination)) = strtol(ds->value->ptr, NULL, 10);
3468 +                                       break;
3469 +                               }
3470 +
3471                                 log_error_write(srv, __FILE__, __LINE__, "ssb", "get a string but expected a short:", cv[i].key, ds->value);
3472 -                               
3473 +
3474                                 return -1;
3475                         }
3476                         default:
3477 @@ -100,19 +110,19 @@
3478                 case T_CONFIG_BOOLEAN:
3479                         if (du->type == TYPE_STRING) {
3480                                 data_string *ds = (data_string *)du;
3481 -                               
3482 +
3483                                 if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable"))) {
3484                                         *((unsigned short *)(cv[i].destination)) = 1;
3485                                 } else if (buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))) {
3486                                         *((unsigned short *)(cv[i].destination)) = 0;
3487                                 } else {
3488                                         log_error_write(srv, __FILE__, __LINE__, "ssbs", "ERROR: unexpected value for key:", cv[i].key, ds->value, "(enable|disable)");
3489 -                                               
3490 +
3491                                         return -1;
3492                                 }
3493                         } else {
3494                                 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: unexpected type for key:", cv[i].key, "(string)", "\"(enable|disable)\"");
3495 -                               
3496 +
3497                                 return -1;
3498                         }
3499                         break;
3500 @@ -121,9 +131,9 @@
3501                         break;
3502                 case T_CONFIG_DEPRECATED:
3503                         log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found deprecated key:", cv[i].key, "-", (char *)(cv[i].destination));
3504 -                       
3505 +
3506                         srv->config_deprecated = 1;
3507 -                       
3508 +
3509                         break;
3510                 }
3511         }
3512 @@ -133,25 +143,25 @@
3513  int config_insert_values_global(server *srv, array *ca, const config_values_t cv[]) {
3514         size_t i;
3515         data_unset *du;
3516 -       
3517 +
3518         for (i = 0; cv[i].key; i++) {
3519                 data_string *touched;
3520 -               
3521 +
3522                 if (NULL == (du = array_get_element(ca, cv[i].key))) {
3523                         /* no found */
3524 -                       
3525 +
3526                         continue;
3527                 }
3528 -               
3529 +
3530                 /* touched */
3531                 touched = data_string_init();
3532 -               
3533 +
3534                 buffer_copy_string(touched->value, "");
3535                 buffer_copy_string_buffer(touched->key, du->key);
3536 -               
3537 +
3538                 array_insert_unique(srv->config_touched, (data_unset *)touched);
3539         }
3540 -       
3541 +
3542         return config_insert_values_internal(srv, ca, cv);
3543  }
3544  
3545 @@ -191,25 +201,25 @@
3546         }
3547  
3548         /* pass the rules */
3549 -       
3550 +
3551         switch (dc->comp) {
3552         case COMP_HTTP_HOST: {
3553                 char *ck_colon = NULL, *val_colon = NULL;
3554 -               
3555 +
3556                 if (!buffer_is_empty(con->uri.authority)) {
3557 -               
3558 -                       /* 
3559 +
3560 +                       /*
3561                          * append server-port to the HTTP_POST if necessary
3562                          */
3563 -                       
3564 +
3565                         l = con->uri.authority;
3566 -                       
3567 +
3568                         switch(dc->cond) {
3569                         case CONFIG_COND_NE:
3570                         case CONFIG_COND_EQ:
3571                                 ck_colon = strchr(dc->string->ptr, ':');
3572                                 val_colon = strchr(l->ptr, ':');
3573 -                               
3574 +
3575                                 if (ck_colon == val_colon) {
3576                                         /* nothing to do with it */
3577                                         break;
3578 @@ -230,21 +240,21 @@
3579                                 break;
3580                         }
3581                 } else {
3582 -                       l = NULL;
3583 +                       l = srv->empty_string;
3584                 }
3585                 break;
3586         }
3587         case COMP_HTTP_REMOTEIP: {
3588                 char *nm_slash;
3589 -               /* handle remoteip limitations 
3590 -                * 
3591 +               /* handle remoteip limitations
3592 +                *
3593                  * "10.0.0.1" is provided for all comparisions
3594 -                * 
3595 +                *
3596                  * only for == and != we support
3597 -                * 
3598 +                *
3599                  * "10.0.0.1/24"
3600                  */
3601 -               
3602 +
3603                 if ((dc->cond == CONFIG_COND_EQ ||
3604                      dc->cond == CONFIG_COND_NE) &&
3605                     (con->dst_addr.plain.sa_family == AF_INET) &&
3606 @@ -253,41 +263,48 @@
3607                         long nm;
3608                         char *err;
3609                         struct in_addr val_inp;
3610 -                       
3611 +
3612 +                       if (con->conf.log_condition_handling) {
3613 +                               l = srv->empty_string;
3614 +
3615 +                               log_error_write(srv, __FILE__, __LINE__,  "bsbsb", dc->comp_key,
3616 +                                               "(", l, ") compare to", dc->string);
3617 +                       }
3618 +
3619                         if (*(nm_slash+1) == '\0') {
3620                                 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: no number after / ", dc->string);
3621 -                                       
3622 +
3623                                 return COND_RESULT_FALSE;
3624                         }
3625 -                       
3626 +
3627                         nm_bits = strtol(nm_slash + 1, &err, 10);
3628 -                       
3629 +
3630                         if (*err) {
3631                                 log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", dc->string, *err);
3632 -                               
3633 +
3634                                 return COND_RESULT_FALSE;
3635                         }
3636 -                       
3637 +
3638                         /* take IP convert to the native */
3639                         buffer_copy_string_len(srv->cond_check_buf, dc->string->ptr, nm_slash - dc->string->ptr);
3640 -#ifdef __WIN32                 
3641 +#ifdef _WIN32
3642                         if (INADDR_NONE == (val_inp.s_addr = inet_addr(srv->cond_check_buf->ptr))) {
3643                                 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
3644 -                               
3645 +
3646                                 return COND_RESULT_FALSE;
3647                         }
3648  
3649  #else
3650                         if (0 == inet_aton(srv->cond_check_buf->ptr, &val_inp)) {
3651                                 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
3652 -                               
3653 +
3654                                 return COND_RESULT_FALSE;
3655                         }
3656  #endif
3657 -                       
3658 +
3659                         /* build netmask */
3660                         nm = htonl(~((1 << (32 - nm_bits)) - 1));
3661 -                       
3662 +
3663                         if ((val_inp.s_addr & nm) == (con->dst_addr.ipv4.sin_addr.s_addr & nm)) {
3664                                 return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
3665                         } else {
3666 @@ -308,7 +325,7 @@
3667  
3668         case COMP_HTTP_REFERER: {
3669                 data_string *ds;
3670 -               
3671 +
3672                 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Referer"))) {
3673                         l = ds->value;
3674                 } else {
3675 @@ -338,7 +355,7 @@
3676         default:
3677                 return COND_RESULT_FALSE;
3678         }
3679 -       
3680 +
3681         if (NULL == l) {
3682                 if (con->conf.log_condition_handling) {
3683                         log_error_write(srv, __FILE__, __LINE__,  "bsbs", dc->comp_key,
3684 @@ -346,10 +363,10 @@
3685                 }
3686                 return COND_RESULT_FALSE;
3687         }
3688 -       
3689 +
3690         if (con->conf.log_condition_handling) {
3691                 log_error_write(srv, __FILE__, __LINE__,  "bsbsb", dc->comp_key,
3692 -                               "(", l, ") compare to ", dc->string);
3693 +                               "(", l, ") compare to", dc->string);
3694         }
3695         switch(dc->cond) {
3696         case CONFIG_COND_NE:
3697 @@ -365,13 +382,13 @@
3698         case CONFIG_COND_MATCH: {
3699                 cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
3700                 int n;
3701 -               
3702 +
3703  #ifndef elementsof
3704  #define elementsof(x) (sizeof(x) / sizeof(x[0]))
3705  #endif
3706                 n = pcre_exec(dc->regex, dc->regex_study, l->ptr, l->used - 1, 0, 0,
3707                                 cache->matches, elementsof(cache->matches));
3708 -               
3709 +
3710                 cache->patterncount = n;
3711                 if (n > 0) {
3712                         cache->comp_value = l;
3713 @@ -387,7 +404,7 @@
3714                 /* no way */
3715                 break;
3716         }
3717 -       
3718 +
3719         return COND_RESULT_FALSE;
3720  }
3721  
3722 @@ -395,6 +412,9 @@
3723         cond_cache_t *caches = con->cond_cache;
3724  
3725         if (COND_RESULT_UNSET == caches[dc->context_ndx].result) {
3726 +               if (con->conf.log_condition_handling) {
3727 +                       log_error_write(srv, __FILE__, __LINE__,  "sds",  "=== start of", dc->context_ndx, "condition block ===");
3728 +               }
3729                 if (COND_RESULT_TRUE == (caches[dc->context_ndx].result = config_check_cond_nocache(srv, con, dc))) {
3730                         if (dc->next) {
3731                                 data_config *c;
3732 @@ -409,11 +429,11 @@
3733                 }
3734                 if (con->conf.log_condition_handling) {
3735                         log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
3736 -                                       "(uncached) result:",
3737 +                                       "result:",
3738                                         caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
3739                 }
3740         } else {
3741 -               if (con->conf.log_condition_handling) {
3742 +               if (con->conf.log_condition_cache_handling) {
3743                         log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
3744                                         "(cached) result:",
3745                                         caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
3746 @@ -423,9 +443,6 @@
3747  }
3748  
3749  int config_check_cond(server *srv, connection *con, data_config *dc) {
3750 -       if (con->conf.log_condition_handling) {
3751 -               log_error_write(srv, __FILE__, __LINE__,  "s",  "=== start of condition block ===");
3752 -       }
3753         return (config_check_cond_cached(srv, con, dc) == COND_RESULT_TRUE);
3754  }
3755  
3756 @@ -443,3 +460,85 @@
3757         return 1;
3758  }
3759  
3760 +/* return <0 on error
3761 + * return 0-x if matched (and replaced)
3762 + */
3763 +int config_exec_pcre_keyvalue_buffer(connection *con, pcre_keyvalue_buffer *kvb, data_config *context, buffer *match_buf, buffer *result)
3764 +{
3765 +#ifdef HAVE_PCRE_H
3766 +       pcre *match;
3767 +       pcre_extra *extra;
3768 +       const char *pattern;
3769 +       size_t pattern_len;
3770 +       int n;
3771 +       size_t i;
3772 +       pcre_keyvalue *kv;
3773 +# define N 10
3774 +       int ovec[N * 3];
3775 +
3776 +       for (i = 0; i < kvb->used; i++) {
3777 +               kv = kvb->kv[i];
3778 +
3779 +               match       = kv->key;
3780 +               extra       = kv->key_extra;
3781 +               pattern     = kv->value->ptr;
3782 +               pattern_len = kv->value->used - 1;
3783 +
3784 +               if ((n = pcre_exec(match, extra, match_buf->ptr, match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
3785 +                       if (n != PCRE_ERROR_NOMATCH) {
3786 +                               return n;
3787 +                       }
3788 +               } else {
3789 +                       const char **list;
3790 +                       size_t start, end;
3791 +                       size_t k;
3792 +
3793 +                       /* it matched */
3794 +                       pcre_get_substring_list(match_buf->ptr, ovec, n, &list);
3795 +
3796 +                       /* search for $[0-9] */
3797 +
3798 +                       buffer_reset(result);
3799 +
3800 +                       start = 0; end = pattern_len;
3801 +                       for (k = 0; k < pattern_len; k++) {
3802 +                               if ((pattern[k] == '$' || pattern[k] == '%') &&
3803 +                                   isdigit((unsigned char)pattern[k + 1])) {
3804 +                                       /* got one */
3805 +
3806 +                                       size_t num = pattern[k + 1] - '0';
3807 +
3808 +                                       end = k;
3809 +
3810 +                                       buffer_append_string_len(result, pattern + start, end - start);
3811 +
3812 +                                       if (pattern[k] == '$') {
3813 +                                               /* n is always > 0 */
3814 +                                               if (num < (size_t)n) {
3815 +                                                       buffer_append_string(result, list[num]);
3816 +                                               }
3817 +                                       } else {
3818 +                                               config_append_cond_match_buffer(con, context, result, num);
3819 +                                       }
3820 +
3821 +                                       k++;
3822 +                                       start = k + 1;
3823 +                               }
3824 +                       }
3825 +
3826 +                       buffer_append_string_len(result, pattern + start, pattern_len - start);
3827 +
3828 +                       pcre_free(list);
3829 +
3830 +                       return i;
3831 +               }
3832 +       }
3833 +
3834 +       return PCRE_ERROR_NOMATCH;
3835 +#undef N
3836 +#else
3837 +       UNUSED(kvb);
3838 +       return -2;
3839 +#endif
3840 +}
3841 +
3842 --- ../lighttpd-1.4.11/src/configfile.c 2006-02-15 14:26:42.000000000 +0200
3843 +++ lighttpd-1.4.12/src/configfile.c    2006-07-18 13:03:40.000000000 +0300
3844 @@ -2,7 +2,6 @@
3845  
3846  #include <stdlib.h>
3847  #include <fcntl.h>
3848 -#include <unistd.h>
3849  #include <errno.h>
3850  #include <string.h>
3851  #include <stdio.h>
3852 @@ -13,21 +12,24 @@
3853  #include "log.h"
3854  #include "stream.h"
3855  #include "plugin.h"
3856 -#ifdef USE_LICENSE
3857 -#include "license.h"
3858 -#endif
3859 -
3860  #include "configparser.h"
3861  #include "configfile.h"
3862  #include "proc_open.h"
3863  
3864 +#include "sys-files.h"
3865 +#include "sys-process.h"
3866 +
3867 +#ifndef PATH_MAX
3868 +/* win32 */
3869 +#define PATH_MAX 64
3870 +#endif
3871  
3872  static int config_insert(server *srv) {
3873         size_t i;
3874         int ret = 0;
3875         buffer *stat_cache_string;
3876 -       
3877 -       config_values_t cv[] = { 
3878 +
3879 +       config_values_t cv[] = {
3880                 { "server.bind",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 0 */
3881                 { "server.errorlog",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 1 */
3882                 { "server.errorfile-prefix",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 2 */
3883 @@ -38,7 +40,7 @@
3884                 { "server.tag",                  NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 7 */
3885                 { "server.use-ipv6",             NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
3886                 { "server.modules",              NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_SERVER },       /* 9 */
3887 -               
3888 +
3889                 { "server.event-handler",        NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 10 */
3890                 { "server.pid-file",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 11 */
3891                 { "server.max-request-size",     NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 12 */
3892 @@ -49,7 +51,7 @@
3893                 { "server.max-keep-alive-requests", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 17 */
3894                 { "server.name",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 18 */
3895                 { "server.max-keep-alive-idle",  NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 19 */
3896 -               
3897 +
3898                 { "server.max-read-idle",        NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 20 */
3899                 { "server.max-write-idle",       NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 21 */
3900                 { "server.error-handler-404",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 22 */
3901 @@ -60,19 +62,19 @@
3902                 { "mimetype.use-xattr",          NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 27 */
3903                 { "mimetype.assign",             NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },   /* 28 */
3904                 { "ssl.pemfile",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 29 */
3905 -               
3906 +
3907                 { "ssl.engine",                  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 30 */
3908 -               
3909 +
3910                 { "debug.log-file-not-found",    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 31 */
3911                 { "debug.log-request-handling",  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 32 */
3912                 { "debug.log-response-header",   NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 33 */
3913                 { "debug.log-request-header",    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 34 */
3914 -               
3915 +
3916                 { "server.protocol-http11",      NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 35 */
3917                 { "debug.log-request-header-on-error", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 36 */
3918                 { "debug.log-state-handling",    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 37 */
3919                 { "ssl.ca-file",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 38 */
3920 -               
3921 +
3922                 { "server.errorlog-use-syslog",  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 39 */
3923                 { "server.range-requests",       NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 40 */
3924                 { "server.stat-cache-engine",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 41 */
3925 @@ -80,7 +82,8 @@
3926                 { "server.network-backend",      NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 43 */
3927                 { "server.upload-dirs",          NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },   /* 44 */
3928                 { "server.core-files",           NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 45 */
3929 -               
3930 +               { "debug.log-condition-cache-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },    /* 46 */
3931 +
3932                 { "server.host",                 "use server.bind instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3933                 { "server.docroot",              "use server.document-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3934                 { "server.virtual-root",         "load mod_simple_vhost and use simple-vhost.server-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3935 @@ -90,11 +93,11 @@
3936                 { "server.groupid",              "use server.groupname instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3937                 { "server.use-keep-alive",       "use server.max-keep-alive-requests = 0 instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3938                 { "server.force-lower-case-files",       "use server.force-lowercase-filenames instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3939 -               
3940 +
3941                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
3942         };
3943  
3944 -       
3945 +
3946         /* 0 */
3947         cv[0].destination = srv->srvconf.bindhost;
3948         cv[1].destination = srv->srvconf.errorlog_file;
3949 @@ -102,33 +105,33 @@
3950         cv[4].destination = srv->srvconf.username;
3951         cv[5].destination = srv->srvconf.groupname;
3952         cv[6].destination = &(srv->srvconf.port);
3953 -       
3954 +
3955         cv[9].destination = srv->srvconf.modules;
3956         cv[10].destination = srv->srvconf.event_handler;
3957         cv[11].destination = srv->srvconf.pid_file;
3958 -       
3959 +
3960         cv[13].destination = &(srv->srvconf.max_worker);
3961         cv[23].destination = &(srv->srvconf.max_fds);
3962         cv[36].destination = &(srv->srvconf.log_request_header_on_error);
3963         cv[37].destination = &(srv->srvconf.log_state_handling);
3964 -       
3965 +
3966         cv[39].destination = &(srv->srvconf.errorlog_use_syslog);
3967 -       
3968 +
3969         stat_cache_string = buffer_init();
3970         cv[41].destination = stat_cache_string;
3971         cv[43].destination = srv->srvconf.network_backend;
3972         cv[44].destination = srv->srvconf.upload_tempdirs;
3973         cv[45].destination = &(srv->srvconf.enable_cores);
3974 -       
3975 +
3976         cv[42].destination = &(srv->srvconf.max_conns);
3977         cv[12].destination = &(srv->srvconf.max_request_size);
3978         srv->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
3979  
3980         assert(srv->config_storage);
3981 -       
3982 +
3983         for (i = 0; i < srv->config_context->used; i++) {
3984                 specific_config *s;
3985 -               
3986 +
3987                 s = calloc(1, sizeof(specific_config));
3988                 assert(s);
3989                 s->document_root = buffer_init();
3990 @@ -154,17 +157,18 @@
3991                 s->global_kbytes_per_second = 0;
3992                 s->global_bytes_per_second_cnt = 0;
3993                 s->global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
3994 -               
3995 +
3996                 cv[2].destination = s->errorfile_prefix;
3997 -               
3998 +
3999                 cv[7].destination = s->server_tag;
4000                 cv[8].destination = &(s->use_ipv6);
4001 -               
4002 -               
4003 +
4004 +
4005                 /* 13 max-worker */
4006                 cv[14].destination = s->document_root;
4007                 cv[15].destination = &(s->force_lowercase_filenames);
4008                 cv[16].destination = &(s->log_condition_handling);
4009 +               cv[46].destination = &(s->log_condition_cache_handling);
4010                 cv[17].destination = &(s->max_keep_alive_requests);
4011                 cv[18].destination = s->server_name;
4012                 cv[19].destination = &(s->max_keep_alive_idle);
4013 @@ -179,23 +183,23 @@
4014                 cv[28].destination = s->mimetypes;
4015                 cv[29].destination = s->ssl_pemfile;
4016                 cv[30].destination = &(s->is_ssl);
4017 -               
4018 +
4019                 cv[31].destination = &(s->log_file_not_found);
4020                 cv[32].destination = &(s->log_request_handling);
4021                 cv[33].destination = &(s->log_response_header);
4022                 cv[34].destination = &(s->log_request_header);
4023 -               
4024 +
4025                 cv[35].destination = &(s->allow_http11);
4026                 cv[38].destination = s->ssl_ca_file;
4027                 cv[40].destination = &(s->range_requests);
4028 -               
4029 +
4030                 srv->config_storage[i] = s;
4031 -       
4032 +
4033                 if (0 != (ret = config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv))) {
4034                         break;
4035                 }
4036         }
4037 -       
4038 +
4039         if (buffer_is_empty(stat_cache_string)) {
4040                 srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
4041         } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("simple"))) {
4042 @@ -205,22 +209,22 @@
4043         } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("disable"))) {
4044                 srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_NONE;
4045         } else {
4046 -               log_error_write(srv, __FILE__, __LINE__, "sb", 
4047 +               log_error_write(srv, __FILE__, __LINE__, "sb",
4048                                 "server.stat-cache-engine can be one of \"disable\", \"simple\", \"fam\", but not:", stat_cache_string);
4049                 ret = HANDLER_ERROR;
4050         }
4051 -       
4052 +
4053         buffer_free(stat_cache_string);
4054 -       
4055 +
4056         return ret;
4057 -                                                                
4058 -}
4059  
4060 +}
4061  
4062 -#define PATCH(x) con->conf.x = s->x
4063 +#define PATCH(x) \
4064 +       con->conf.x = s->x
4065  int config_setup_connection(server *srv, connection *con) {
4066         specific_config *s = srv->config_storage[0];
4067 -       
4068 +
4069         PATCH(allow_http11);
4070         PATCH(mimetypes);
4071         PATCH(document_root);
4072 @@ -236,20 +240,21 @@
4073         PATCH(kbytes_per_second);
4074         PATCH(global_kbytes_per_second);
4075         PATCH(global_bytes_per_second_cnt);
4076 -       
4077 +
4078         con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
4079         buffer_copy_string_buffer(con->server_name, s->server_name);
4080 -       
4081 +
4082         PATCH(log_request_header);
4083         PATCH(log_response_header);
4084         PATCH(log_request_handling);
4085         PATCH(log_condition_handling);
4086 +       PATCH(log_condition_cache_handling);
4087         PATCH(log_file_not_found);
4088 -       
4089 +
4090         PATCH(range_requests);
4091         PATCH(force_lowercase_filenames);
4092         PATCH(is_ssl);
4093 -       
4094 +
4095         PATCH(ssl_pemfile);
4096         PATCH(ssl_ca_file);
4097         return 0;
4098 @@ -257,22 +262,22 @@
4099  
4100  int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
4101         size_t i, j;
4102 -       
4103 +
4104         /* skip the first, the global context */
4105         for (i = 1; i < srv->config_context->used; i++) {
4106                 data_config *dc = (data_config *)srv->config_context->data[i];
4107                 specific_config *s = srv->config_storage[i];
4108 -               
4109 +
4110                 /* not our stage */
4111                 if (comp != dc->comp) continue;
4112 -               
4113 +
4114                 /* condition didn't match */
4115                 if (!config_check_cond(srv, con, dc)) continue;
4116 -               
4117 +
4118                 /* merge config */
4119                 for (j = 0; j < dc->value->used; j++) {
4120                         data_unset *du = dc->value->data[j];
4121 -                       
4122 +
4123                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.document-root"))) {
4124                                 PATCH(document_root);
4125                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.range-requests"))) {
4126 @@ -315,11 +320,13 @@
4127                                 PATCH(log_response_header);
4128                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-condition-handling"))) {
4129                                 PATCH(log_condition_handling);
4130 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-condition-cache-handling"))) {
4131 +                               PATCH(log_condition_cache_handling);
4132                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-file-not-found"))) {
4133                                 PATCH(log_file_not_found);
4134                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.protocol-http11"))) {
4135                                 PATCH(allow_http11);
4136 -                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {  
4137 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {
4138                                 PATCH(force_lowercase_filenames);
4139                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.kbytes-per-second"))) {
4140                                 PATCH(global_kbytes_per_second);
4141 @@ -328,7 +335,7 @@
4142                         }
4143                 }
4144         }
4145 -       
4146 +
4147         return 0;
4148  }
4149  #undef PATCH
4150 @@ -336,15 +343,15 @@
4151  typedef struct {
4152         int foo;
4153         int bar;
4154 -       
4155 +
4156         const buffer *source;
4157         const char *input;
4158         size_t offset;
4159         size_t size;
4160 -       
4161 +
4162         int line_pos;
4163         int line;
4164 -       
4165 +
4166         int in_key;
4167         int in_brace;
4168         int in_cond;
4169 @@ -362,7 +369,7 @@
4170         }
4171  
4172         if (0 != stream_open(&(t->s), t->file)) {
4173 -               log_error_write(srv, __FILE__, __LINE__, "sbss", 
4174 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
4175                                 "opening configfile ", t->file, "failed:", strerror(errno));
4176                 buffer_free(t->file);
4177                 return -1;
4178 @@ -373,7 +380,7 @@
4179         t->size = t->s.size;
4180         t->line = 1;
4181         t->line_pos = 1;
4182 -       
4183 +
4184         t->in_key = 1;
4185         t->in_brace = 0;
4186         t->in_cond = 0;
4187 @@ -401,7 +408,7 @@
4188  static int config_skip_comment(tokenizer_t *t) {
4189         int i;
4190         assert(t->input[t->offset] == '#');
4191 -       for (i = 1; t->input[t->offset + i] && 
4192 +       for (i = 1; t->input[t->offset + i] &&
4193              (t->input[t->offset + i] != '\n' && t->input[t->offset + i] != '\r');
4194              i++);
4195         t->offset += i;
4196 @@ -411,44 +418,44 @@
4197  static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *token) {
4198         int tid = 0;
4199         size_t i;
4200 -       
4201 +
4202         for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
4203                 char c = t->input[t->offset];
4204                 const char *start = NULL;
4205 -               
4206 +
4207                 switch (c) {
4208 -               case '=': 
4209 +               case '=':
4210                         if (t->in_brace) {
4211                                 if (t->input[t->offset + 1] == '>') {
4212                                         t->offset += 2;
4213 -                                       
4214 +
4215                                         buffer_copy_string(token, "=>");
4216 -                                       
4217 +
4218                                         tid = TK_ARRAY_ASSIGN;
4219                                 } else {
4220 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4221 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4222                                                         "source:", t->source,
4223 -                                                       "line:", t->line, "pos:", t->line_pos, 
4224 +                                                       "line:", t->line, "pos:", t->line_pos,
4225                                                         "use => for assignments in arrays");
4226                                         return -1;
4227                                 }
4228                         } else if (t->in_cond) {
4229                                 if (t->input[t->offset + 1] == '=') {
4230                                         t->offset += 2;
4231 -                                       
4232 +
4233                                         buffer_copy_string(token, "==");
4234 -                                       
4235 +
4236                                         tid = TK_EQ;
4237                                 } else if (t->input[t->offset + 1] == '~') {
4238                                         t->offset += 2;
4239 -                                       
4240 +
4241                                         buffer_copy_string(token, "=~");
4242 -                                       
4243 +
4244                                         tid = TK_MATCH;
4245                                 } else {
4246 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4247 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4248                                                         "source:", t->source,
4249 -                                                       "line:", t->line, "pos:", t->line_pos, 
4250 +                                                       "line:", t->line, "pos:", t->line_pos,
4251                                                         "only =~ and == are allowed in the condition");
4252                                         return -1;
4253                                 }
4254 @@ -456,51 +463,51 @@
4255                                 t->in_cond = 0;
4256                         } else if (t->in_key) {
4257                                 tid = TK_ASSIGN;
4258 -                               
4259 +
4260                                 buffer_copy_string_len(token, t->input + t->offset, 1);
4261 -                               
4262 +
4263                                 t->offset++;
4264                                 t->line_pos++;
4265                         } else {
4266 -                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4267 +                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4268                                                 "source:", t->source,
4269 -                                               "line:", t->line, "pos:", t->line_pos, 
4270 +                                               "line:", t->line, "pos:", t->line_pos,
4271                                                 "unexpected equal-sign: =");
4272                                 return -1;
4273                         }
4274 -                       
4275 +
4276                         break;
4277 -               case '!': 
4278 +               case '!':
4279                         if (t->in_cond) {
4280                                 if (t->input[t->offset + 1] == '=') {
4281                                         t->offset += 2;
4282 -                                       
4283 +
4284                                         buffer_copy_string(token, "!=");
4285 -                                       
4286 +
4287                                         tid = TK_NE;
4288                                 } else if (t->input[t->offset + 1] == '~') {
4289                                         t->offset += 2;
4290 -                                       
4291 +
4292                                         buffer_copy_string(token, "!~");
4293 -                                       
4294 +
4295                                         tid = TK_NOMATCH;
4296                                 } else {
4297 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4298 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4299                                                         "source:", t->source,
4300 -                                                       "line:", t->line, "pos:", t->line_pos, 
4301 +                                                       "line:", t->line, "pos:", t->line_pos,
4302                                                         "only !~ and != are allowed in the condition");
4303                                         return -1;
4304                                 }
4305                                 t->in_key = 1;
4306                                 t->in_cond = 0;
4307                         } else {
4308 -                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4309 +                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4310                                                 "source:", t->source,
4311 -                                               "line:", t->line, "pos:", t->line_pos, 
4312 +                                               "line:", t->line, "pos:", t->line_pos,
4313                                                 "unexpected exclamation-marks: !");
4314                                 return -1;
4315                         }
4316 -                       
4317 +
4318                         break;
4319                 case '\t':
4320                 case ' ':
4321 @@ -546,10 +553,10 @@
4322                 case ',':
4323                         if (t->in_brace > 0) {
4324                                 tid = TK_COMMA;
4325 -                               
4326 +
4327                                 buffer_copy_string(token, "(COMMA)");
4328                         }
4329 -                       
4330 +
4331                         t->offset++;
4332                         t->line_pos++;
4333                         break;
4334 @@ -557,70 +564,70 @@
4335                         /* search for the terminating " */
4336                         start = t->input + t->offset + 1;
4337                         buffer_copy_string(token, "");
4338 -                       
4339 +
4340                         for (i = 1; t->input[t->offset + i]; i++) {
4341                                 if (t->input[t->offset + i] == '\\' &&
4342                                     t->input[t->offset + i + 1] == '"') {
4343 -                                       
4344 +
4345                                         buffer_append_string_len(token, start, t->input + t->offset + i - start);
4346 -                                       
4347 +
4348                                         start = t->input + t->offset + i + 1;
4349 -                                       
4350 +
4351                                         /* skip the " */
4352                                         i++;
4353                                         continue;
4354                                 }
4355 -                               
4356 -                               
4357 +
4358 +
4359                                 if (t->input[t->offset + i] == '"') {
4360                                         tid = TK_STRING;
4361 -                               
4362 +
4363                                         buffer_append_string_len(token, start, t->input + t->offset + i - start);
4364 -                                       
4365 +
4366                                         break;
4367                                 }
4368                         }
4369  
4370                         if (t->input[t->offset + i] == '\0') {
4371                                 /* ERROR */
4372 -                               
4373 -                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4374 +
4375 +                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4376                                                 "source:", t->source,
4377 -                                               "line:", t->line, "pos:", t->line_pos, 
4378 +                                               "line:", t->line, "pos:", t->line_pos,
4379                                                 "missing closing quote");
4380 -                               
4381 +
4382                                 return -1;
4383                         }
4384 -                       
4385 +
4386                         t->offset += i + 1;
4387                         t->line_pos += i + 1;
4388 -                       
4389 +
4390                         break;
4391                 case '(':
4392                         t->offset++;
4393                         t->in_brace++;
4394 -                               
4395 +
4396                         tid = TK_LPARAN;
4397 -                               
4398 +
4399                         buffer_copy_string(token, "(");
4400                         break;
4401                 case ')':
4402                         t->offset++;
4403                         t->in_brace--;
4404 -                               
4405 +
4406                         tid = TK_RPARAN;
4407 -                               
4408 +
4409                         buffer_copy_string(token, ")");
4410                         break;
4411                 case '$':
4412                         t->offset++;
4413 -                               
4414 +
4415                         tid = TK_DOLLAR;
4416                         t->in_cond = 1;
4417                         t->in_key = 0;
4418 -                               
4419 +
4420                         buffer_copy_string(token, "$");
4421 -                       
4422 +
4423                         break;
4424  
4425                 case '+':
4426 @@ -637,115 +644,107 @@
4427  
4428                 case '{':
4429                         t->offset++;
4430 -                               
4431 +
4432                         tid = TK_LCURLY;
4433 -                               
4434 +
4435                         buffer_copy_string(token, "{");
4436 -                       
4437 +
4438                         break;
4439 -                       
4440 +
4441                 case '}':
4442                         t->offset++;
4443 -                               
4444 +
4445                         tid = TK_RCURLY;
4446 -                               
4447 +
4448                         buffer_copy_string(token, "}");
4449 -                       
4450 +
4451                         break;
4452  
4453                 case '[':
4454                         t->offset++;
4455 -                               
4456 +
4457                         tid = TK_LBRACKET;
4458 -                               
4459 +
4460                         buffer_copy_string(token, "[");
4461 -                       
4462 +
4463                         break;
4464 -                       
4465 +
4466                 case ']':
4467                         t->offset++;
4468 -                               
4469 +
4470                         tid = TK_RBRACKET;
4471 -                               
4472 +
4473                         buffer_copy_string(token, "]");
4474 -                       
4475 +
4476                         break;
4477                 case '#':
4478                         t->line_pos += config_skip_comment(t);
4479 -                       
4480 +
4481                         break;
4482                 default:
4483                         if (t->in_cond) {
4484 -                               for (i = 0; t->input[t->offset + i] && 
4485 +                               for (i = 0; t->input[t->offset + i] &&
4486                                      (isalpha((unsigned char)t->input[t->offset + i])
4487                                       ); i++);
4488 -                               
4489 +
4490                                 if (i && t->input[t->offset + i]) {
4491                                         tid = TK_SRVVARNAME;
4492                                         buffer_copy_string_len(token, t->input + t->offset, i);
4493 -                                       
4494 +
4495                                         t->offset += i;
4496                                         t->line_pos += i;
4497                                 } else {
4498                                         /* ERROR */
4499 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4500 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4501                                                         "source:", t->source,
4502 -                                                       "line:", t->line, "pos:", t->line_pos, 
4503 +                                                       "line:", t->line, "pos:", t->line_pos,
4504                                                         "invalid character in condition");
4505                                         return -1;
4506                                 }
4507                         } else if (isdigit((unsigned char)c)) {
4508                                 /* take all digits */
4509                                 for (i = 0; t->input[t->offset + i] && isdigit((unsigned char)t->input[t->offset + i]);  i++);
4510 -                               
4511 +
4512                                 /* was there it least a digit ? */
4513 -                               if (i && t->input[t->offset + i]) {
4514 +                               if (i) {
4515                                         tid = TK_INTEGER;
4516 -                                       
4517 +
4518                                         buffer_copy_string_len(token, t->input + t->offset, i);
4519 -                                       
4520 +
4521                                         t->offset += i;
4522                                         t->line_pos += i;
4523 -                               } else {
4524 -                                       /* ERROR */
4525 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4526 -                                                       "source:", t->source,
4527 -                                                       "line:", t->line, "pos:", t->line_pos, 
4528 -                                                       "unexpected EOF");
4529 -                                       
4530 -                                       return -1;
4531                                 }
4532                         } else {
4533                                 /* the key might consist of [-.0-9a-z] */
4534 -                               for (i = 0; t->input[t->offset + i] && 
4535 -                                    (isalnum((unsigned char)t->input[t->offset + i]) || 
4536 +                               for (i = 0; t->input[t->offset + i] &&
4537 +                                    (isalnum((unsigned char)t->input[t->offset + i]) ||
4538                                       t->input[t->offset + i] == '.' ||
4539                                       t->input[t->offset + i] == '_' || /* for env.* */
4540                                       t->input[t->offset + i] == '-'
4541                                       ); i++);
4542 -                               
4543 +
4544                                 if (i && t->input[t->offset + i]) {
4545                                         buffer_copy_string_len(token, t->input + t->offset, i);
4546 -                                       
4547 -                                       if (strcmp(token->ptr, "include") == 0) {
4548 +
4549 +                                       if (buffer_is_equal_string(token, CONST_STR_LEN("include"))) {
4550                                                 tid = TK_INCLUDE;
4551 -                                       } else if (strcmp(token->ptr, "include_shell") == 0) {
4552 +                                       } else if (buffer_is_equal_string(token, CONST_STR_LEN("include_shell"))) {
4553                                                 tid = TK_INCLUDE_SHELL;
4554 -                                       } else if (strcmp(token->ptr, "global") == 0) {
4555 +                                       } else if (buffer_is_equal_string(token, CONST_STR_LEN("global"))) {
4556                                                 tid = TK_GLOBAL;
4557 -                                       } else if (strcmp(token->ptr, "else") == 0) {
4558 +                                       } else if (buffer_is_equal_string(token, CONST_STR_LEN("else"))) {
4559                                                 tid = TK_ELSE;
4560                                         } else {
4561                                                 tid = TK_LKEY;
4562                                         }
4563 -                                       
4564 +
4565                                         t->offset += i;
4566                                         t->line_pos += i;
4567                                 } else {
4568                                         /* ERROR */
4569 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4570 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4571                                                         "source:", t->source,
4572 -                                                       "line:", t->line, "pos:", t->line_pos, 
4573 +                                                       "line:", t->line, "pos:", t->line_pos,
4574                                                         "invalid character in variable name");
4575                                         return -1;
4576                                 }
4577 @@ -753,16 +752,16 @@
4578                         break;
4579                 }
4580         }
4581 -       
4582 +
4583         if (tid) {
4584                 *token_id = tid;
4585  #if 0
4586 -               log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd", 
4587 +               log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd",
4588                                 "source:", t->source,
4589                                 "line:", t->line, "pos:", t->line_pos,
4590                                 token, token->used - 1, tid);
4591  #endif
4592 -               
4593 +
4594                 return 1;
4595         } else if (t->offset < t->size) {
4596                 fprintf(stderr, "%s.%d: %d, %s\n",
4597 @@ -781,10 +780,11 @@
4598         pParser = configparserAlloc( malloc );
4599         lasttoken = buffer_init();
4600         token = buffer_init();
4601 +
4602         while((1 == (ret = config_tokenizer(srv, t, &token_id, token))) && context->ok) {
4603                 buffer_copy_string_buffer(lasttoken, token);
4604                 configparser(pParser, token_id, token, context);
4605 -               
4606 +
4607                 token = buffer_init();
4608         }
4609         buffer_free(token);
4610 @@ -797,14 +797,14 @@
4611                 }
4612         }
4613         configparserFree(pParser, free);
4614 -       
4615 +
4616         if (ret == -1) {
4617 -               log_error_write(srv, __FILE__, __LINE__, "sb", 
4618 +               log_error_write(srv, __FILE__, __LINE__, "sb",
4619                                 "configfile parser failed:", lasttoken);
4620         } else if (context->ok == 0) {
4621 -               log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb", 
4622 +               log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb",
4623                                 "source:", t->source,
4624 -                               "line:", t->line, "pos:", t->line_pos, 
4625 +                               "line:", t->line, "pos:", t->line_pos,
4626                                 "parser failed somehow near here:", lasttoken);
4627                 ret = -1;
4628         }
4629 @@ -821,7 +821,7 @@
4630         t->offset = 0;
4631         t->line = 1;
4632         t->line_pos = 1;
4633 -       
4634 +
4635         t->in_key = 1;
4636         t->in_brace = 0;
4637         t->in_cond = 0;
4638 @@ -844,7 +844,7 @@
4639         }
4640  
4641         if (0 != stream_open(&s, filename)) {
4642 -               log_error_write(srv, __FILE__, __LINE__, "sbss", 
4643 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
4644                                 "opening configfile ", filename, "failed:", strerror(errno));
4645                 ret = -1;
4646         } else {
4647 @@ -866,7 +866,7 @@
4648         char oldpwd[PATH_MAX];
4649  
4650         if (NULL == getcwd(oldpwd, sizeof(oldpwd))) {
4651 -               log_error_write(srv, __FILE__, __LINE__, "s", 
4652 +               log_error_write(srv, __FILE__, __LINE__, "s",
4653                                 "cannot get cwd", strerror(errno));
4654                 return -1;
4655         }
4656 @@ -879,7 +879,7 @@
4657         }
4658  
4659         if (0 != proc_open_buffer(&proc, cmd, NULL, out, NULL)) {
4660 -               log_error_write(srv, __FILE__, __LINE__, "sbss", 
4661 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
4662                                 "opening", source, "failed:", strerror(errno));
4663                 ret = -1;
4664         } else {
4665 @@ -896,13 +896,12 @@
4666  static void context_init(server *srv, config_t *context) {
4667         context->srv = srv;
4668         context->ok = 1;
4669 -       context->configs_stack = array_init();
4670 -       context->configs_stack->is_weakref = 1;
4671 +       context->configs_stack = buffer_ptr_init(NULL);
4672         context->basedir = buffer_init();
4673  }
4674  
4675  static void context_free(config_t *context) {
4676 -       array_free(context->configs_stack);
4677 +       buffer_ptr_free(context->configs_stack);
4678         buffer_free(context->basedir);
4679  }
4680  
4681 @@ -918,18 +917,15 @@
4682         context_init(srv, &context);
4683         context.all_configs = srv->config_context;
4684  
4685 -       pos = strrchr(fn,
4686 -#ifdef __WIN32
4687 -                       '\\'
4688 -#else
4689 -                       '/'
4690 -#endif
4691 -                       );
4692 +    /* use the current dir as basedir for all other includes
4693 +    */
4694 +       pos = strrchr(fn, DIR_SEPERATOR);
4695 +
4696         if (pos) {
4697                 buffer_copy_string_len(context.basedir, fn, pos - fn + 1);
4698                 fn = pos + 1;
4699         }
4700 -       
4701 +
4702         dc = data_config_init();
4703         buffer_copy_string(dc->key, "global");
4704  
4705 @@ -944,7 +940,7 @@
4706         dpid->value = getpid();
4707         buffer_copy_string(dpid->key, "var.PID");
4708         array_insert_unique(srv->config, (data_unset *)dpid);
4709 -       
4710 +
4711         dcwd = data_string_init();
4712         buffer_prepare_copy(dcwd->value, 1024);
4713         if (NULL != getcwd(dcwd->value->ptr, dcwd->value->size - 1)) {
4714 @@ -968,7 +964,7 @@
4715         } else {
4716                 return -1;
4717         }
4718 -       
4719 +
4720         if (NULL != (modules = (data_array *)array_get_element(srv->config, "server.modules"))) {
4721                 data_string *ds;
4722                 data_array *prepends;
4723 @@ -1026,22 +1022,23 @@
4724                 buffer_copy_string(modules->key, "server.modules");
4725                 array_insert_unique(srv->config, (data_unset *)modules);
4726         }
4727 -       
4728 +
4729  
4730         if (0 != config_insert(srv)) {
4731                 return -1;
4732         }
4733 -       
4734 +
4735         return 0;
4736  }
4737  
4738 +
4739  int config_set_defaults(server *srv) {
4740         size_t i;
4741         specific_config *s = srv->config_storage[0];
4742         struct stat st1, st2;
4743 -       
4744 -       struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] = 
4745 -       { 
4746 +
4747 +       struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
4748 +       {
4749                 /* - poll is most reliable
4750                  * - select works everywhere
4751                  * - linux-* are experimental
4752 @@ -1067,20 +1064,21 @@
4753  #endif
4754                 { FDEVENT_HANDLER_UNSET,          NULL }
4755         };
4756 -       
4757  
4758 -       if (buffer_is_empty(s->document_root)) {  
4759 -               log_error_write(srv, __FILE__, __LINE__, "s",  
4760 -                               "a default document-root has to be set");  
4761 -               
4762 -               return -1;  
4763 -       }  
4764 -       
4765 +
4766 +       if (buffer_is_empty(s->document_root)) {
4767 +               log_error_write(srv, __FILE__, __LINE__, "s",
4768 +                               "a default document-root has to be set");
4769 +
4770 +               return -1;
4771 +       }
4772 +
4773         if (buffer_is_empty(srv->srvconf.changeroot)) {
4774 -               if (-1 == stat(s->document_root->ptr, &st1)) {  
4775 -                       log_error_write(srv, __FILE__, __LINE__, "sb",  
4776 +        pathname_unix2local(s->document_root);
4777 +               if (-1 == stat(s->document_root->ptr, &st1)) {
4778 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
4779                                         "base-docroot doesn't exist:",
4780 -                                       s->document_root);  
4781 +                                       s->document_root, strerror(errno));
4782                         return -1;
4783                 }
4784  
4785 @@ -1088,18 +1086,18 @@
4786                 buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.changeroot);
4787                 buffer_append_string_buffer(srv->tmp_buf, s->document_root);
4788  
4789 -               if (-1 == stat(srv->tmp_buf->ptr, &st1)) {  
4790 -                       log_error_write(srv, __FILE__, __LINE__, "sb",  
4791 +               if (-1 == stat(srv->tmp_buf->ptr, &st1)) {
4792 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
4793                                         "base-docroot doesn't exist:",
4794 -                                       srv->tmp_buf);  
4795 +                                       srv->tmp_buf);
4796                         return -1;
4797                 }
4798 -               
4799 +
4800         }
4801 -       
4802 -       buffer_copy_string_buffer(srv->tmp_buf, s->document_root);  
4803  
4804 -       buffer_to_lower(srv->tmp_buf);  
4805 +       buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
4806 +
4807 +       buffer_to_lower(srv->tmp_buf);
4808  
4809         if (0 == stat(srv->tmp_buf->ptr, &st1)) {
4810                 int is_lower = 0;
4811 @@ -1107,68 +1105,68 @@
4812                 is_lower = buffer_is_equal(srv->tmp_buf, s->document_root);
4813  
4814                 /* lower-case existed, check upper-case */
4815 -               buffer_copy_string_buffer(srv->tmp_buf, s->document_root);  
4816 +               buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
4817  
4818 -               buffer_to_upper(srv->tmp_buf);  
4819 +               buffer_to_upper(srv->tmp_buf);
4820  
4821                 /* we have to handle the special case that upper and lower-casing results in the same filename
4822                  * as in server.document-root = "/" or "/12345/" */
4823  
4824                 if (is_lower && buffer_is_equal(srv->tmp_buf, s->document_root)) {
4825 -                       /* lower-casing and upper-casing didn't result in  
4826 -                        * an other filename, no need to stat(), 
4827 +                       /* lower-casing and upper-casing didn't result in
4828 +                        * an other filename, no need to stat(),
4829                          * just assume it is case-sensitive. */
4830  
4831                         s->force_lowercase_filenames = 0;
4832 -               } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {  
4833 +               } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {
4834 +
4835 +                       /* upper case exists too, doesn't the FS handle this ? */
4836 +
4837 +                       /* upper and lower have the same inode -> case-insensitve FS */
4838 +
4839 +                       if (st1.st_ino == st2.st_ino) {
4840 +                               /* upper and lower have the same inode -> case-insensitve FS */
4841 +
4842 +                               s->force_lowercase_filenames = 1;
4843 +                       }
4844 +               }
4845 +       }
4846  
4847 -                       /* upper case exists too, doesn't the FS handle this ? */  
4848 -                       
4849 -                       /* upper and lower have the same inode -> case-insensitve FS */  
4850 -                       
4851 -                       if (st1.st_ino == st2.st_ino) {  
4852 -                               /* upper and lower have the same inode -> case-insensitve FS */  
4853 -                               
4854 -                               s->force_lowercase_filenames = 1;  
4855 -                       }  
4856 -               }  
4857 -       }  
4858 -       
4859         if (srv->srvconf.port == 0) {
4860                 srv->srvconf.port = s->is_ssl ? 443 : 80;
4861         }
4862 -       
4863 +
4864         if (srv->srvconf.event_handler->used == 0) {
4865                 /* choose a good default
4866 -                * 
4867 -                * the event_handler list is sorted by 'goodness' 
4868 +                *
4869 +                * the event_handler list is sorted by 'goodness'
4870                  * taking the first available should be the best solution
4871                  */
4872                 srv->event_handler = event_handlers[0].et;
4873 -               
4874 +
4875                 if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
4876 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
4877 +                       log_error_write(srv, __FILE__, __LINE__, "s",
4878                                         "sorry, there is no event handler for this system");
4879 -                       
4880 +
4881                         return -1;
4882                 }
4883         } else {
4884                 /*
4885                  * User override
4886                  */
4887 -               
4888 +
4889                 for (i = 0; event_handlers[i].name; i++) {
4890                         if (0 == strcmp(event_handlers[i].name, srv->srvconf.event_handler->ptr)) {
4891                                 srv->event_handler = event_handlers[i].et;
4892                                 break;
4893                         }
4894                 }
4895 -               
4896 +
4897                 if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
4898 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
4899 -                                       "the selected event-handler in unknown or not supported:", 
4900 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
4901 +                                       "the selected event-handler in unknown or not supported:",
4902                                         srv->srvconf.event_handler );
4903 -                       
4904 +
4905                         return -1;
4906                 }
4907         }
4908 @@ -1176,19 +1174,19 @@
4909         if (s->is_ssl) {
4910                 if (buffer_is_empty(s->ssl_pemfile)) {
4911                         /* PEM file is require */
4912 -                       
4913 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
4914 +
4915 +                       log_error_write(srv, __FILE__, __LINE__, "s",
4916                                         "ssl.pemfile has to be set");
4917                         return -1;
4918                 }
4919 -               
4920 +
4921  #ifndef USE_OPENSSL
4922 -               log_error_write(srv, __FILE__, __LINE__, "s", 
4923 +               log_error_write(srv, __FILE__, __LINE__, "s",
4924                                 "ssl support is missing, recompile with --with-openssl");
4925 -               
4926 +
4927                 return -1;
4928  #endif
4929         }
4930 -       
4931 +
4932         return 0;
4933  }
4934 --- ../lighttpd-1.4.11/src/configfile.h 2005-08-23 17:36:12.000000000 +0300
4935 +++ lighttpd-1.4.12/src/configfile.h    2006-07-16 00:26:03.000000000 +0300
4936 @@ -9,7 +9,7 @@
4937         server *srv;
4938         int     ok;
4939         array  *all_configs;
4940 -       array  *configs_stack; /* to parse nested block */
4941 +       buffer_ptr  *configs_stack; /* to parse nested block */
4942         data_config *current; /* current started with { */
4943         buffer *basedir;
4944  } config_t;
4945 --- ../lighttpd-1.4.11/src/configparser.c       2006-02-01 19:51:15.000000000 +0200
4946 +++ lighttpd-1.4.12/src/configparser.c  2006-07-17 22:02:23.000000000 +0300
4947 @@ -24,52 +24,34 @@
4948      dc->parent = ctx->current;
4949      array_insert_unique(dc->parent->childs, (data_unset *)dc);
4950    }
4951 -  array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
4952 +  buffer_ptr_append(ctx->configs_stack, (void *)ctx->current);
4953    ctx->current = dc;
4954  }
4955  
4956  static data_config *configparser_pop(config_t *ctx) {
4957    data_config *old = ctx->current;
4958 -  ctx->current = (data_config *) array_pop(ctx->configs_stack);
4959 +  ctx->current = (data_config *) buffer_ptr_pop(ctx->configs_stack);
4960    return old;
4961  }
4962  
4963  /* return a copied variable */
4964  static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
4965 -  if (strncmp(key->ptr, "env.", sizeof("env.") - 1) == 0) {
4966 -    char *env;
4967 -
4968 -    if (NULL != (env = getenv(key->ptr + 4))) {
4969 -      data_string *ds;
4970 -      ds = data_string_init();
4971 -      buffer_append_string(ds->value, env);
4972 -      return (data_unset *)ds;
4973 -    }
4974 -
4975 -    fprintf(stderr, "Undefined env variable: %s\n", key->ptr + 4);
4976 -    ctx->ok = 0;
4977 -
4978 -    return NULL;
4979 -  } else {
4980 -    data_unset *du;
4981 -    data_config *dc;
4982 +  data_unset *du;
4983 +  data_config *dc;
4984  
4985  #if 0
4986 -    fprintf(stderr, "get var %s\n", key->ptr);
4987 +  fprintf(stderr, "get var %s\n", key->ptr);
4988  #endif
4989 -    for (dc = ctx->current; dc; dc = dc->parent) {
4990 +  for (dc = ctx->current; dc; dc = dc->parent) {
4991  #if 0
4992 -      fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
4993 -      array_print(dc->value, 0);
4994 +    fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
4995 +    array_print(dc->value, 0);
4996  #endif
4997 -      if (NULL != (du = array_get_element(dc->value, key->ptr))) {
4998 -        return du->copy(du);
4999 -      }
5000 +    if (NULL != (du = array_get_element(dc->value, key->ptr))) {
5001 +      return du->copy(du);
5002      }
5003 -    fprintf(stderr, "Undefined config variable: %s\n", key->ptr);
5004 -    ctx->ok = 0;
5005 -    return NULL;
5006    }
5007 +  return NULL;
5008  }
5009  
5010  /* op1 is to be eat/return by this function, op1->key is not cared
5011 @@ -124,14 +106,14 @@
5012  }
5013  
5014  
5015 -#line 128 "configparser.c"
5016 +#line 110 "configparser.c"
5017  /* Next is all token values, in a form suitable for use by makeheaders.
5018  ** This section will be null unless lemon is run with the -m switch.
5019  */
5020 -/* 
5021 +/*
5022  ** These constants (all generated automatically by the parser generator)
5023  ** specify the various kinds of tokens (terminals) that the parser
5024 -** understands. 
5025 +** understands.
5026  **
5027  ** Each symbol here is a terminal symbol in the grammar.
5028  */
5029 @@ -148,7 +130,7 @@
5030  **                       and nonterminals.  "int" is used otherwise.
5031  **    YYNOCODE           is a number of type YYCODETYPE which corresponds
5032  **                       to no legal terminal or nonterminal number.  This
5033 -**                       number is used to fill in empty slots of the hash 
5034 +**                       number is used to fill in empty slots of the hash
5035  **                       table.
5036  **    YYFALLBACK         If defined, this indicates that one or more tokens
5037  **                       have fall-back values which should be used if the
5038 @@ -157,7 +139,7 @@
5039  **                       and nonterminal numbers.  "unsigned char" is
5040  **                       used if there are fewer than 250 rules and
5041  **                       states combined.  "int" is used otherwise.
5042 -**    configparserTOKENTYPE     is the data type used for minor tokens given 
5043 +**    configparserTOKENTYPE     is the data type used for minor tokens given
5044  **                       directly to the parser from the tokenizer.
5045  **    YYMINORTYPE        is the data type used for all minor tokens.
5046  **                       This is typically a union of many types, one of
5047 @@ -192,8 +174,8 @@
5048  #define configparserARG_PDECL ,config_t *ctx
5049  #define configparserARG_FETCH config_t *ctx = yypParser->ctx
5050  #define configparserARG_STORE yypParser->ctx = ctx
5051 -#define YYNSTATE 62
5052 -#define YYNRULE 39
5053 +#define YYNSTATE 63
5054 +#define YYNRULE 40
5055  #define YYERRORSYMBOL 26
5056  #define YYERRSYMDT yy95
5057  #define YY_NO_ACTION      (YYNSTATE+YYNRULE+2)
5058 @@ -203,7 +185,7 @@
5059  /* Next are that tables used to determine what action to take based on the
5060  ** current state and lookahead token.  These tables are used to implement
5061  ** functions that take a state number and lookahead value and return an
5062 -** action integer.  
5063 +** action integer.
5064  **
5065  ** Suppose the action integer is N.  Then the action is determined as
5066  ** follows
5067 @@ -228,7 +210,7 @@
5068  ** If the index value yy_shift_ofst[S]+X is out of range or if the value
5069  ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
5070  ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
5071 -** and that yy_default[S] should be used instead.  
5072 +** and that yy_default[S] should be used instead.
5073  **
5074  ** The formula above is for computing the action when the lookahead is
5075  ** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
5076 @@ -248,67 +230,69 @@
5077  **  yy_default[]       Default action for each state.
5078  */
5079  static YYACTIONTYPE yy_action[] = {
5080 - /*     0 */     2,    3,    4,    5,   13,   14,   62,   15,    7,   44,
5081 - /*    10 */    20,   86,   16,   45,   28,   48,   40,   10,   39,   25,
5082 - /*    20 */    22,   49,   45,    8,   15,  102,    1,   20,   28,   18,
5083 - /*    30 */    57,   59,   19,   25,   22,   39,   19,   61,   98,   45,
5084 - /*    40 */    20,    6,   23,   24,   26,   28,   35,   57,   59,   12,
5085 - /*    50 */    25,   22,   28,   27,   36,   87,   29,   25,   22,   33,
5086 - /*    60 */    15,   30,   31,   20,   28,   38,    9,   17,   37,   25,
5087 - /*    70 */    22,   39,   42,   43,   10,   45,   11,   53,   54,   55,
5088 - /*    80 */    56,   28,   52,   57,   59,   34,   25,   22,   28,   27,
5089 - /*    90 */    32,   88,   41,   25,   22,   33,   28,   48,   46,   28,
5090 - /*   100 */    48,   25,   22,   58,   25,   22,   60,   21,   19,   47,
5091 - /*   110 */    51,   50,   25,   22,   88,   88,   93,
5092 + /*     0 */     2,    3,    4,    5,   13,   14,   63,   15,    7,   45,
5093 + /*    10 */    20,   88,   16,   46,   28,   49,   41,   10,   40,   25,
5094 + /*    20 */    22,   50,   46,    8,   15,  104,    1,   20,   28,   18,
5095 + /*    30 */    58,   60,    6,   25,   22,   40,   47,   62,   11,   46,
5096 + /*    40 */    20,    9,   23,   24,   26,   29,   89,   58,   60,   10,
5097 + /*    50 */    17,   38,   28,   27,   37,   19,   30,   25,   22,   34,
5098 + /*    60 */    15,  100,   20,   20,   23,   24,   26,   12,   19,   31,
5099 + /*    70 */    32,   40,   19,   44,   43,   46,   95,   35,   90,   89,
5100 + /*    80 */    28,   49,   42,   58,   60,   25,   22,   59,   28,   27,
5101 + /*    90 */    33,   48,   52,   25,   22,   34,   28,   49,   51,   28,
5102 + /*   100 */    36,   25,   22,   61,   25,   22,   89,   28,   39,   89,
5103 + /*   110 */    89,   89,   25,   22,   54,   55,   56,   57,   89,   28,
5104 + /*   120 */    53,   21,   89,   89,   25,   22,   25,   22,
5105  };
5106  static YYCODETYPE yy_lookahead[] = {
5107   /*     0 */    29,   30,   31,   32,   33,   34,    0,    1,   44,   38,
5108   /*    10 */     4,   15,   41,   16,   35,   36,   45,   46,   12,   40,
5109   /*    20 */    41,   42,   16,   15,    1,   27,   28,    4,   35,   36,
5110 - /*    30 */    24,   25,    5,   40,   41,   12,    5,   14,   11,   16,
5111 - /*    40 */     4,    1,    6,    7,    8,   35,   36,   24,   25,   28,
5112 - /*    50 */    40,   41,   35,   36,   37,   15,   39,   40,   41,   42,
5113 - /*    60 */     1,    9,   10,    4,   35,   36,   38,    2,    3,   40,
5114 - /*    70 */    41,   12,   28,   14,   46,   16,   13,   20,   21,   22,
5115 - /*    80 */    23,   35,   36,   24,   25,   11,   40,   41,   35,   36,
5116 - /*    90 */    37,   13,   13,   40,   41,   42,   35,   36,   17,   35,
5117 - /*   100 */    36,   40,   41,   42,   40,   41,   42,   35,    5,   18,
5118 - /*   110 */    43,   19,   40,   41,   47,   47,   13,
5119 + /*    30 */    24,   25,    1,   40,   41,   12,   17,   14,   13,   16,
5120 + /*    40 */     4,   38,    6,    7,    8,    9,   15,   24,   25,   46,
5121 + /*    50 */     2,    3,   35,   36,   37,    5,   39,   40,   41,   42,
5122 + /*    60 */     1,   11,    4,    4,    6,    7,    8,   28,    5,    9,
5123 + /*    70 */    10,   12,    5,   14,   28,   16,   13,   11,   13,   47,
5124 + /*    80 */    35,   36,   13,   24,   25,   40,   41,   42,   35,   36,
5125 + /*    90 */    37,   18,   43,   40,   41,   42,   35,   36,   19,   35,
5126 + /*   100 */    36,   40,   41,   42,   40,   41,   47,   35,   36,   47,
5127 + /*   110 */    47,   47,   40,   41,   20,   21,   22,   23,   47,   35,
5128 + /*   120 */    36,   35,   47,   47,   40,   41,   40,   41,
5129  };
5130  #define YY_SHIFT_USE_DFLT (-5)
5131  static signed char yy_shift_ofst[] = {
5132 - /*     0 */    -5,    6,   -5,   -5,   -5,   40,   -4,    8,   -3,   -5,
5133 - /*    10 */    63,   -5,   23,   -5,   -5,   -5,   65,   36,   31,   36,
5134 - /*    20 */    -5,   -5,   -5,   -5,   -5,   -5,   36,   27,   -5,   52,
5135 - /*    30 */    -5,   36,   -5,   74,   36,   31,   -5,   36,   31,   78,
5136 - /*    40 */    79,   -5,   59,   -5,   -5,   81,   91,   36,   31,   92,
5137 - /*    50 */    57,   36,  103,   -5,   -5,   -5,   -5,   36,   -5,   36,
5138 - /*    60 */    -5,   -5,
5139 + /*     0 */    -5,    6,   -5,   -5,   -5,   31,   -4,    8,   -3,   -5,
5140 + /*    10 */    25,   -5,   23,   -5,   -5,   -5,   48,   58,   67,   58,
5141 + /*    20 */    -5,   -5,   -5,   -5,   -5,   -5,   36,   50,   -5,   -5,
5142 + /*    30 */    60,   -5,   58,   -5,   66,   58,   67,   -5,   58,   67,
5143 + /*    40 */    65,   69,   -5,   59,   -5,   -5,   19,   73,   58,   67,
5144 + /*    50 */    79,   94,   58,   63,   -5,   -5,   -5,   -5,   58,   -5,
5145 + /*    60 */    58,   -5,   -5,
5146  };
5147  #define YY_REDUCE_USE_DFLT (-37)
5148  static signed char yy_reduce_ofst[] = {
5149 - /*     0 */    -2,  -29,  -37,  -37,  -37,  -36,  -37,  -37,   28,  -37,
5150 - /*    10 */   -37,   21,  -29,  -37,  -37,  -37,  -37,   -7,  -37,   72,
5151 + /*     0 */    -2,  -29,  -37,  -37,  -37,  -36,  -37,  -37,    3,  -37,
5152 + /*    10 */   -37,   39,  -29,  -37,  -37,  -37,  -37,   -7,  -37,   86,
5153   /*    20 */   -37,  -37,  -37,  -37,  -37,  -37,   17,  -37,  -37,  -37,
5154 - /*    30 */   -37,   53,  -37,  -37,   10,  -37,  -37,   29,  -37,  -37,
5155 - /*    40 */   -37,   44,  -29,  -37,  -37,  -37,  -37,  -21,  -37,  -37,
5156 - /*    50 */    67,   46,  -37,  -37,  -37,  -37,  -37,   61,  -37,   64,
5157 - /*    60 */   -37,  -37,
5158 + /*    30 */   -37,  -37,   53,  -37,  -37,   64,  -37,  -37,   72,  -37,
5159 + /*    40 */   -37,  -37,   46,  -29,  -37,  -37,  -37,  -37,  -21,  -37,
5160 + /*    50 */   -37,   49,   84,  -37,  -37,  -37,  -37,  -37,   45,  -37,
5161 + /*    60 */    61,  -37,  -37,
5162  };
5163  static YYACTIONTYPE yy_default[] = {
5164 - /*     0 */    64,  101,   63,   65,   66,  101,   67,  101,  101,   90,
5165 - /*    10 */   101,   64,  101,   68,   69,   70,  101,  101,   71,  101,
5166 - /*    20 */    73,   74,   76,   77,   78,   79,  101,   84,   75,  101,
5167 - /*    30 */    80,   82,   81,  101,  101,   85,   83,  101,   72,  101,
5168 - /*    40 */   101,   64,  101,   89,   91,  101,  101,  101,   98,  101,
5169 - /*    50 */   101,  101,  101,   94,   95,   96,   97,  101,   99,  101,
5170 - /*    60 */   100,   92,
5171 + /*     0 */    65,  103,   64,   66,   67,  103,   68,  103,  103,   92,
5172 + /*    10 */   103,   65,  103,   69,   70,   71,  103,  103,   72,  103,
5173 + /*    20 */    74,   75,   77,   78,   79,   80,  103,   86,   76,   81,
5174 + /*    30 */   103,   82,   84,   83,  103,  103,   87,   85,  103,   73,
5175 + /*    40 */   103,  103,   65,  103,   91,   93,  103,  103,  103,  100,
5176 + /*    50 */   103,  103,  103,  103,   96,   97,   98,   99,  103,  101,
5177 + /*    60 */   103,  102,   94,
5178  };
5179  #define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
5180  
5181  /* The next table maps tokens into fallback tokens.  If a construct
5182  ** like the following:
5183 -** 
5184 +**
5185  **      %fallback ID X Y Z.
5186  **
5187  ** appears in the grammer, then ID becomes a fallback token for X, Y,
5188 @@ -359,10 +343,10 @@
5189  #endif /* NDEBUG */
5190  
5191  #ifndef NDEBUG
5192 -/* 
5193 +/*
5194  ** Turn parser tracing on by giving a stream to which to write the trace
5195  ** and a prompt to preface each trace message.  Tracing is turned off
5196 -** by making either argument NULL 
5197 +** by making either argument NULL
5198  **
5199  ** Inputs:
5200  ** <ul>
5201 @@ -387,7 +371,7 @@
5202  #ifndef NDEBUG
5203  /* For tracing shifts, the names of all terminals and nonterminals
5204  ** are required.  The following table supplies these names */
5205 -static const char *yyTokenName[] = { 
5206 +static const char *yyTokenName[] = {
5207    "$",             "EOL",           "ASSIGN",        "APPEND",      
5208    "LKEY",          "PLUS",          "STRING",        "INTEGER",     
5209    "LPARAN",        "RPARAN",        "COMMA",         "ARRAY_ASSIGN",
5210 @@ -425,27 +409,28 @@
5211   /*  15 */ "value ::= STRING",
5212   /*  16 */ "value ::= INTEGER",
5213   /*  17 */ "value ::= array",
5214 - /*  18 */ "array ::= LPARAN aelements RPARAN",
5215 - /*  19 */ "aelements ::= aelements COMMA aelement",
5216 - /*  20 */ "aelements ::= aelements COMMA",
5217 - /*  21 */ "aelements ::= aelement",
5218 - /*  22 */ "aelement ::= expression",
5219 - /*  23 */ "aelement ::= stringop ARRAY_ASSIGN expression",
5220 - /*  24 */ "eols ::= EOL",
5221 - /*  25 */ "eols ::=",
5222 - /*  26 */ "globalstart ::= GLOBAL",
5223 - /*  27 */ "global ::= globalstart LCURLY metalines RCURLY",
5224 - /*  28 */ "condlines ::= condlines eols ELSE condline",
5225 - /*  29 */ "condlines ::= condline",
5226 - /*  30 */ "condline ::= context LCURLY metalines RCURLY",
5227 - /*  31 */ "context ::= DOLLAR SRVVARNAME LBRACKET stringop RBRACKET cond expression",
5228 - /*  32 */ "cond ::= EQ",
5229 - /*  33 */ "cond ::= MATCH",
5230 - /*  34 */ "cond ::= NE",
5231 - /*  35 */ "cond ::= NOMATCH",
5232 - /*  36 */ "stringop ::= expression",
5233 - /*  37 */ "include ::= INCLUDE stringop",
5234 - /*  38 */ "include_shell ::= INCLUDE_SHELL stringop",
5235 + /*  18 */ "array ::= LPARAN RPARAN",
5236 + /*  19 */ "array ::= LPARAN aelements RPARAN",
5237 + /*  20 */ "aelements ::= aelements COMMA aelement",
5238 + /*  21 */ "aelements ::= aelements COMMA",
5239 + /*  22 */ "aelements ::= aelement",
5240 + /*  23 */ "aelement ::= expression",
5241 + /*  24 */ "aelement ::= stringop ARRAY_ASSIGN expression",
5242 + /*  25 */ "eols ::= EOL",
5243 + /*  26 */ "eols ::=",
5244 + /*  27 */ "globalstart ::= GLOBAL",
5245 + /*  28 */ "global ::= globalstart LCURLY metalines RCURLY",
5246 + /*  29 */ "condlines ::= condlines eols ELSE condline",
5247 + /*  30 */ "condlines ::= condline",
5248 + /*  31 */ "condline ::= context LCURLY metalines RCURLY",
5249 + /*  32 */ "context ::= DOLLAR SRVVARNAME LBRACKET stringop RBRACKET cond expression",
5250 + /*  33 */ "cond ::= EQ",
5251 + /*  34 */ "cond ::= MATCH",
5252 + /*  35 */ "cond ::= NE",
5253 + /*  36 */ "cond ::= NOMATCH",
5254 + /*  37 */ "stringop ::= expression",
5255 + /*  38 */ "include ::= INCLUDE stringop",
5256 + /*  39 */ "include_shell ::= INCLUDE_SHELL stringop",
5257  };
5258  #endif /* NDEBUG */
5259  
5260 @@ -465,7 +450,7 @@
5261  #endif
5262  }
5263  
5264 -/* 
5265 +/*
5266  ** This function allocates a new parser.
5267  ** The only argument is a pointer to a function which works like
5268  ** malloc.
5269 @@ -496,7 +481,7 @@
5270      /* Here is inserted the actions which take place when a
5271      ** terminal or non-terminal is destroyed.  This can happen
5272      ** when the symbol is popped from the stack during a
5273 -    ** reduce or during error processing or when a parser is 
5274 +    ** reduce or during error processing or when a parser is
5275      ** being destroyed before it is finished parsing.
5276      **
5277      ** Note: during a reduce, the only symbols destroyed are those
5278 @@ -528,44 +513,44 @@
5279      case 23:
5280      case 24:
5281      case 25:
5282 -#line 160 "./configparser.y"
5283 +#line 143 "./configparser.y"
5284  { buffer_free((yypminor->yy0)); }
5285 -#line 533 "configparser.c"
5286 +#line 518 "configparser.c"
5287        break;
5288      case 35:
5289 -#line 151 "./configparser.y"
5290 +#line 134 "./configparser.y"
5291  { (yypminor->yy41)->free((yypminor->yy41)); }
5292 -#line 538 "configparser.c"
5293 +#line 523 "configparser.c"
5294        break;
5295      case 36:
5296 -#line 152 "./configparser.y"
5297 +#line 135 "./configparser.y"
5298  { (yypminor->yy41)->free((yypminor->yy41)); }
5299 -#line 543 "configparser.c"
5300 +#line 528 "configparser.c"
5301        break;
5302      case 37:
5303 -#line 153 "./configparser.y"
5304 +#line 136 "./configparser.y"
5305  { (yypminor->yy41)->free((yypminor->yy41)); }
5306 -#line 548 "configparser.c"
5307 +#line 533 "configparser.c"
5308        break;
5309      case 39:
5310 -#line 154 "./configparser.y"
5311 +#line 137 "./configparser.y"
5312  { array_free((yypminor->yy40)); }
5313 -#line 553 "configparser.c"
5314 +#line 538 "configparser.c"
5315        break;
5316      case 40:
5317 -#line 155 "./configparser.y"
5318 +#line 138 "./configparser.y"
5319  { array_free((yypminor->yy40)); }
5320 -#line 558 "configparser.c"
5321 +#line 543 "configparser.c"
5322        break;
5323      case 41:
5324 -#line 156 "./configparser.y"
5325 +#line 139 "./configparser.y"
5326  { buffer_free((yypminor->yy43)); }
5327 -#line 563 "configparser.c"
5328 +#line 548 "configparser.c"
5329        break;
5330      case 42:
5331 -#line 157 "./configparser.y"
5332 +#line 140 "./configparser.y"
5333  { buffer_free((yypminor->yy43)); }
5334 -#line 568 "configparser.c"
5335 +#line 553 "configparser.c"
5336        break;
5337      default:  break;   /* If no destructor action specified: do nothing */
5338    }
5339 @@ -597,7 +582,7 @@
5340    return yymajor;
5341  }
5342  
5343 -/* 
5344 +/*
5345  ** Deallocate and destroy a parser.  Destructors are all called for
5346  ** all stack elements before shutting the parser down.
5347  **
5348 @@ -633,7 +618,7 @@
5349  ){
5350    int i;
5351    int stateno = pParser->yystack[pParser->yyidx].stateno;
5352
5353 +
5354    /* if( pParser->yyidx<0 ) return YY_NO_ACTION;  */
5355    i = yy_shift_ofst[stateno];
5356    if( i==YY_SHIFT_USE_DFLT ){
5357 @@ -677,7 +662,7 @@
5358  ){
5359    int i;
5360    int stateno = pParser->yystack[pParser->yyidx].stateno;
5361
5362 +
5363    i = yy_reduce_ofst[stateno];
5364    if( i==YY_REDUCE_USE_DFLT ){
5365      return yy_default[stateno];
5366 @@ -759,6 +744,7 @@
5367    { 35, 1 },
5368    { 35, 1 },
5369    { 35, 1 },
5370 +  { 40, 2 },
5371    { 40, 3 },
5372    { 39, 3 },
5373    { 39, 2 },
5374 @@ -800,7 +786,7 @@
5375    configparserARG_FETCH;
5376    yymsp = &yypParser->yystack[yypParser->yyidx];
5377  #ifndef NDEBUG
5378 -  if( yyTraceFILE && yyruleno>=0 
5379 +  if( yyTraceFILE && yyruleno>=0
5380          && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
5381      fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
5382        yyRuleName[yyruleno]);
5383 @@ -832,9 +818,9 @@
5384          /* No destructor defined for global */
5385          break;
5386        case 5:
5387 -#line 134 "./configparser.y"
5388 +#line 116 "./configparser.y"
5389  { yymsp[-1].minor.yy78 = NULL; }
5390 -#line 837 "configparser.c"
5391 +#line 823 "configparser.c"
5392    yy_destructor(1,&yymsp[0].minor);
5393          break;
5394        case 6:
5395 @@ -847,10 +833,15 @@
5396    yy_destructor(1,&yymsp[0].minor);
5397          break;
5398        case 9:
5399 -#line 162 "./configparser.y"
5400 +#line 145 "./configparser.y"
5401  {
5402    buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5403 -  if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) {
5404 +  if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5405 +    fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
5406 +        ctx->current->context_ndx,
5407 +        ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5408 +    ctx->ok = 0;
5409 +  } else if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) {
5410      array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
5411      yymsp[0].minor.yy41 = NULL;
5412    } else {
5413 @@ -864,16 +855,21 @@
5414    buffer_free(yymsp[-2].minor.yy43);
5415    yymsp[-2].minor.yy43 = NULL;
5416  }
5417 -#line 867 "configparser.c"
5418 +#line 858 "configparser.c"
5419    yy_destructor(2,&yymsp[-1].minor);
5420          break;
5421        case 10:
5422 -#line 179 "./configparser.y"
5423 +#line 167 "./configparser.y"
5424  {
5425    array *vars = ctx->current->value;
5426    data_unset *du;
5427  
5428 -  if (NULL != (du = array_get_element(vars, yymsp[-2].minor.yy43->ptr))) {
5429 +  if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5430 +    fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
5431 +        ctx->current->context_ndx,
5432 +        ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5433 +    ctx->ok = 0;
5434 +  } else if (NULL != (du = array_get_element(vars, yymsp[-2].minor.yy43->ptr))) {
5435      /* exists in current block */
5436      du = configparser_merge_data(du, yymsp[0].minor.yy41);
5437      if (NULL == du) {
5438 @@ -883,6 +879,7 @@
5439        buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
5440        array_replace(vars, du);
5441      }
5442 +    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5443    } else if (NULL != (du = configparser_get_variable(ctx, yymsp[-2].minor.yy43))) {
5444      du = configparser_merge_data(du, yymsp[0].minor.yy41);
5445      if (NULL == du) {
5446 @@ -892,22 +889,20 @@
5447        buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
5448        array_insert_unique(ctx->current->value, du);
5449      }
5450 +    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5451    } else {
5452 -    fprintf(stderr, "Undefined config variable in conditional %d %s: %s\n", 
5453 -            ctx->current->context_ndx,
5454 -            ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5455 -    ctx->ok = 0;
5456 +    buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5457 +    array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
5458    }
5459    buffer_free(yymsp[-2].minor.yy43);
5460    yymsp[-2].minor.yy43 = NULL;
5461 -  yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5462    yymsp[0].minor.yy41 = NULL;
5463  }
5464 -#line 906 "configparser.c"
5465 +#line 901 "configparser.c"
5466    yy_destructor(3,&yymsp[-1].minor);
5467          break;
5468        case 11:
5469 -#line 214 "./configparser.y"
5470 +#line 206 "./configparser.y"
5471  {
5472    if (strchr(yymsp[0].minor.yy0->ptr, '.') == NULL) {
5473      yygotominor.yy43 = buffer_init_string("var.");
5474 @@ -919,10 +914,10 @@
5475      yymsp[0].minor.yy0 = NULL;
5476    }
5477  }
5478 -#line 922 "configparser.c"
5479 +#line 917 "configparser.c"
5480          break;
5481        case 12:
5482 -#line 226 "./configparser.y"
5483 +#line 218 "./configparser.y"
5484  {
5485    yygotominor.yy41 = configparser_merge_data(yymsp[-2].minor.yy41, yymsp[0].minor.yy41);
5486    if (NULL == yygotominor.yy41) {
5487 @@ -932,21 +927,38 @@
5488    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5489    yymsp[0].minor.yy41 = NULL;
5490  }
5491 -#line 935 "configparser.c"
5492 +#line 930 "configparser.c"
5493    yy_destructor(5,&yymsp[-1].minor);
5494          break;
5495        case 13:
5496 -#line 236 "./configparser.y"
5497 +#line 228 "./configparser.y"
5498  {
5499    yygotominor.yy41 = yymsp[0].minor.yy41;
5500    yymsp[0].minor.yy41 = NULL;
5501  }
5502 -#line 944 "configparser.c"
5503 +#line 939 "configparser.c"
5504          break;
5505        case 14:
5506 -#line 241 "./configparser.y"
5507 +#line 233 "./configparser.y"
5508  {
5509 -  yygotominor.yy41 = configparser_get_variable(ctx, yymsp[0].minor.yy43);
5510 +  if (strncmp(yymsp[0].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5511 +    char *env;
5512 +
5513 +    if (NULL != (env = getenv(yymsp[0].minor.yy43->ptr + 4))) {
5514 +      data_string *ds;
5515 +      ds = data_string_init();
5516 +      buffer_append_string(ds->value, env);
5517 +      yygotominor.yy41 = (data_unset *)ds;
5518 +    }
5519 +    else {
5520 +      yygotominor.yy41 = NULL;
5521 +      fprintf(stderr, "Undefined env variable: %s\n", yymsp[0].minor.yy43->ptr + 4);
5522 +      ctx->ok = 0;
5523 +    }
5524 +  } else if (NULL == (yygotominor.yy41 = configparser_get_variable(ctx, yymsp[0].minor.yy43))) {
5525 +    fprintf(stderr, "Undefined config variable: %s\n", yymsp[0].minor.yy43->ptr);
5526 +    ctx->ok = 0;
5527 +  }
5528    if (!yygotominor.yy41) {
5529      /* make a dummy so it won't crash */
5530      yygotominor.yy41 = (data_unset *)data_string_init();
5531 @@ -954,50 +966,59 @@
5532    buffer_free(yymsp[0].minor.yy43);
5533    yymsp[0].minor.yy43 = NULL;
5534  }
5535 -#line 957 "configparser.c"
5536 +#line 969 "configparser.c"
5537          break;
5538        case 15:
5539 -#line 251 "./configparser.y"
5540 +#line 260 "./configparser.y"
5541  {
5542    yygotominor.yy41 = (data_unset *)data_string_init();
5543    buffer_copy_string_buffer(((data_string *)(yygotominor.yy41))->value, yymsp[0].minor.yy0);
5544    buffer_free(yymsp[0].minor.yy0);
5545    yymsp[0].minor.yy0 = NULL;
5546  }
5547 -#line 967 "configparser.c"
5548 +#line 979 "configparser.c"
5549          break;
5550        case 16:
5551 -#line 258 "./configparser.y"
5552 +#line 267 "./configparser.y"
5553  {
5554    yygotominor.yy41 = (data_unset *)data_integer_init();
5555    ((data_integer *)(yygotominor.yy41))->value = strtol(yymsp[0].minor.yy0->ptr, NULL, 10);
5556    buffer_free(yymsp[0].minor.yy0);
5557    yymsp[0].minor.yy0 = NULL;
5558  }
5559 -#line 977 "configparser.c"
5560 +#line 989 "configparser.c"
5561          break;
5562        case 17:
5563 -#line 264 "./configparser.y"
5564 +#line 273 "./configparser.y"
5565  {
5566    yygotominor.yy41 = (data_unset *)data_array_init();
5567    array_free(((data_array *)(yygotominor.yy41))->value);
5568    ((data_array *)(yygotominor.yy41))->value = yymsp[0].minor.yy40;
5569    yymsp[0].minor.yy40 = NULL;
5570  }
5571 -#line 987 "configparser.c"
5572 +#line 999 "configparser.c"
5573          break;
5574        case 18:
5575 -#line 270 "./configparser.y"
5576 +#line 279 "./configparser.y"
5577 +{
5578 +  yygotominor.yy40 = array_init();
5579 +}
5580 +#line 1006 "configparser.c"
5581 +  yy_destructor(8,&yymsp[-1].minor);
5582 +  yy_destructor(9,&yymsp[0].minor);
5583 +        break;
5584 +      case 19:
5585 +#line 282 "./configparser.y"
5586  {
5587    yygotominor.yy40 = yymsp[-1].minor.yy40;
5588    yymsp[-1].minor.yy40 = NULL;
5589  }
5590 -#line 995 "configparser.c"
5591 +#line 1016 "configparser.c"
5592    yy_destructor(8,&yymsp[-2].minor);
5593    yy_destructor(9,&yymsp[0].minor);
5594          break;
5595 -      case 19:
5596 -#line 275 "./configparser.y"
5597 +      case 20:
5598 +#line 287 "./configparser.y"
5599  {
5600    if (buffer_is_empty(yymsp[0].minor.yy41->key) ||
5601        NULL == array_get_element(yymsp[-2].minor.yy40, yymsp[0].minor.yy41->key->ptr)) {
5602 @@ -1014,37 +1035,37 @@
5603    yygotominor.yy40 = yymsp[-2].minor.yy40;
5604    yymsp[-2].minor.yy40 = NULL;
5605  }
5606 -#line 1017 "configparser.c"
5607 +#line 1038 "configparser.c"
5608    yy_destructor(10,&yymsp[-1].minor);
5609          break;
5610 -      case 20:
5611 -#line 292 "./configparser.y"
5612 +      case 21:
5613 +#line 304 "./configparser.y"
5614  {
5615    yygotominor.yy40 = yymsp[-1].minor.yy40;
5616    yymsp[-1].minor.yy40 = NULL;
5617  }
5618 -#line 1026 "configparser.c"
5619 +#line 1047 "configparser.c"
5620    yy_destructor(10,&yymsp[0].minor);
5621          break;
5622 -      case 21:
5623 -#line 297 "./configparser.y"
5624 +      case 22:
5625 +#line 309 "./configparser.y"
5626  {
5627    yygotominor.yy40 = array_init();
5628    array_insert_unique(yygotominor.yy40, yymsp[0].minor.yy41);
5629    yymsp[0].minor.yy41 = NULL;
5630  }
5631 -#line 1036 "configparser.c"
5632 +#line 1057 "configparser.c"
5633          break;
5634 -      case 22:
5635 -#line 303 "./configparser.y"
5636 +      case 23:
5637 +#line 315 "./configparser.y"
5638  {
5639    yygotominor.yy41 = yymsp[0].minor.yy41;
5640    yymsp[0].minor.yy41 = NULL;
5641  }
5642 -#line 1044 "configparser.c"
5643 +#line 1065 "configparser.c"
5644          break;
5645 -      case 23:
5646 -#line 307 "./configparser.y"
5647 +      case 24:
5648 +#line 319 "./configparser.y"
5649  {
5650    buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5651    buffer_free(yymsp[-2].minor.yy43);
5652 @@ -1053,27 +1074,27 @@
5653    yygotominor.yy41 = yymsp[0].minor.yy41;
5654    yymsp[0].minor.yy41 = NULL;
5655  }
5656 -#line 1056 "configparser.c"
5657 +#line 1077 "configparser.c"
5658    yy_destructor(11,&yymsp[-1].minor);
5659          break;
5660 -      case 24:
5661 -  yy_destructor(1,&yymsp[0].minor);
5662 -        break;
5663        case 25:
5664 +  yy_destructor(1,&yymsp[0].minor);
5665          break;
5666        case 26:
5667 -#line 319 "./configparser.y"
5668 +        break;
5669 +      case 27:
5670 +#line 331 "./configparser.y"
5671  {
5672    data_config *dc;
5673    dc = (data_config *)array_get_element(ctx->srv->config_context, "global");
5674    assert(dc);
5675    configparser_push(ctx, dc, 0);
5676  }
5677 -#line 1072 "configparser.c"
5678 +#line 1093 "configparser.c"
5679    yy_destructor(12,&yymsp[0].minor);
5680          break;
5681 -      case 27:
5682 -#line 326 "./configparser.y"
5683 +      case 28:
5684 +#line 338 "./configparser.y"
5685  {
5686    data_config *cur;
5687    
5688 @@ -1082,16 +1103,16 @@
5689  
5690    assert(cur && ctx->current);
5691  
5692 -  yygotominor.yy0 = cur;
5693 +  yygotominor.yy78 = cur;
5694  }
5695 -#line 1087 "configparser.c"
5696 +#line 1108 "configparser.c"
5697          /* No destructor defined for globalstart */
5698    yy_destructor(13,&yymsp[-2].minor);
5699          /* No destructor defined for metalines */
5700    yy_destructor(14,&yymsp[0].minor);
5701          break;
5702 -      case 28:
5703 -#line 337 "./configparser.y"
5704 +      case 29:
5705 +#line 349 "./configparser.y"
5706  {
5707    assert(yymsp[-3].minor.yy78->context_ndx < yymsp[0].minor.yy78->context_ndx);
5708    yymsp[0].minor.yy78->prev = yymsp[-3].minor.yy78;
5709 @@ -1100,20 +1121,20 @@
5710    yymsp[-3].minor.yy78 = NULL;
5711    yymsp[0].minor.yy78 = NULL;
5712  }
5713 -#line 1103 "configparser.c"
5714 +#line 1124 "configparser.c"
5715          /* No destructor defined for eols */
5716    yy_destructor(15,&yymsp[-1].minor);
5717          break;
5718 -      case 29:
5719 -#line 346 "./configparser.y"
5720 +      case 30:
5721 +#line 358 "./configparser.y"
5722  {
5723    yygotominor.yy78 = yymsp[0].minor.yy78;
5724    yymsp[0].minor.yy78 = NULL;
5725  }
5726 -#line 1113 "configparser.c"
5727 +#line 1134 "configparser.c"
5728          break;
5729 -      case 30:
5730 -#line 351 "./configparser.y"
5731 +      case 31:
5732 +#line 363 "./configparser.y"
5733  {
5734    data_config *cur;
5735    
5736 @@ -1124,14 +1145,14 @@
5737  
5738    yygotominor.yy78 = cur;
5739  }
5740 -#line 1127 "configparser.c"
5741 +#line 1148 "configparser.c"
5742          /* No destructor defined for context */
5743    yy_destructor(13,&yymsp[-2].minor);
5744          /* No destructor defined for metalines */
5745    yy_destructor(14,&yymsp[0].minor);
5746          break;
5747 -      case 31:
5748 -#line 362 "./configparser.y"
5749 +      case 32:
5750 +#line 374 "./configparser.y"
5751  {
5752    data_config *dc;
5753    buffer *b, *rvalue, *op;
5754 @@ -1266,45 +1287,45 @@
5755    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5756    yymsp[0].minor.yy41 = NULL;
5757  }
5758 -#line 1269 "configparser.c"
5759 +#line 1290 "configparser.c"
5760    yy_destructor(16,&yymsp[-6].minor);
5761    yy_destructor(18,&yymsp[-4].minor);
5762    yy_destructor(19,&yymsp[-2].minor);
5763          break;
5764 -      case 32:
5765 -#line 496 "./configparser.y"
5766 +      case 33:
5767 +#line 508 "./configparser.y"
5768  {
5769    yygotominor.yy27 = CONFIG_COND_EQ;
5770  }
5771 -#line 1279 "configparser.c"
5772 +#line 1300 "configparser.c"
5773    yy_destructor(20,&yymsp[0].minor);
5774          break;
5775 -      case 33:
5776 -#line 499 "./configparser.y"
5777 +      case 34:
5778 +#line 511 "./configparser.y"
5779  {
5780    yygotominor.yy27 = CONFIG_COND_MATCH;
5781  }
5782 -#line 1287 "configparser.c"
5783 +#line 1308 "configparser.c"
5784    yy_destructor(21,&yymsp[0].minor);
5785          break;
5786 -      case 34:
5787 -#line 502 "./configparser.y"
5788 +      case 35:
5789 +#line 514 "./configparser.y"
5790  {
5791    yygotominor.yy27 = CONFIG_COND_NE;
5792  }
5793 -#line 1295 "configparser.c"
5794 +#line 1316 "configparser.c"
5795    yy_destructor(22,&yymsp[0].minor);
5796          break;
5797 -      case 35:
5798 -#line 505 "./configparser.y"
5799 +      case 36:
5800 +#line 517 "./configparser.y"
5801  {
5802    yygotominor.yy27 = CONFIG_COND_NOMATCH;
5803  }
5804 -#line 1303 "configparser.c"
5805 +#line 1324 "configparser.c"
5806    yy_destructor(23,&yymsp[0].minor);
5807          break;
5808 -      case 36:
5809 -#line 509 "./configparser.y"
5810 +      case 37:
5811 +#line 521 "./configparser.y"
5812  {
5813    yygotominor.yy43 = NULL;
5814    if (ctx->ok) {
5815 @@ -1321,10 +1342,10 @@
5816    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5817    yymsp[0].minor.yy41 = NULL;
5818  }
5819 -#line 1324 "configparser.c"
5820 +#line 1345 "configparser.c"
5821          break;
5822 -      case 37:
5823 -#line 526 "./configparser.y"
5824 +      case 38:
5825 +#line 538 "./configparser.y"
5826  {
5827    if (ctx->ok) {
5828      if (0 != config_parse_file(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
5829 @@ -1334,11 +1355,11 @@
5830      yymsp[0].minor.yy43 = NULL;
5831    }
5832  }
5833 -#line 1337 "configparser.c"
5834 +#line 1358 "configparser.c"
5835    yy_destructor(24,&yymsp[-1].minor);
5836          break;
5837 -      case 38:
5838 -#line 536 "./configparser.y"
5839 +      case 39:
5840 +#line 548 "./configparser.y"
5841  {
5842    if (ctx->ok) {
5843      if (0 != config_parse_cmd(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
5844 @@ -1348,7 +1369,7 @@
5845      yymsp[0].minor.yy43 = NULL;
5846    }
5847  }
5848 -#line 1351 "configparser.c"
5849 +#line 1372 "configparser.c"
5850    yy_destructor(25,&yymsp[-1].minor);
5851          break;
5852    };
5853 @@ -1378,11 +1399,11 @@
5854    while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
5855    /* Here code is inserted which will be executed whenever the
5856    ** parser fails */
5857 -#line 125 "./configparser.y"
5858 +#line 107 "./configparser.y"
5859  
5860    ctx->ok = 0;
5861  
5862 -#line 1385 "configparser.c"
5863 +#line 1406 "configparser.c"
5864    configparserARG_STORE; /* Suppress warning about unused %extra_argument variable */
5865  }
5866  
5867 @@ -1489,7 +1510,7 @@
5868  #ifdef YYERRORSYMBOL
5869        /* A syntax error has occurred.
5870        ** The response to an error depends upon whether or not the
5871 -      ** grammar defines an error token "ERROR".  
5872 +      ** grammar defines an error token "ERROR".
5873        **
5874        ** This is what we do if the grammar does define ERROR:
5875        **
5876 --- ../lighttpd-1.4.11/src/configparser.y       2006-01-26 18:46:25.000000000 +0200
5877 +++ lighttpd-1.4.12/src/configparser.y  2006-07-16 00:26:04.000000000 +0300
5878 @@ -21,52 +21,34 @@
5879      dc->parent = ctx->current;
5880      array_insert_unique(dc->parent->childs, (data_unset *)dc);
5881    }
5882 -  array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
5883 +  buffer_ptr_append(ctx->configs_stack, (void *)ctx->current);
5884    ctx->current = dc;
5885  }
5886  
5887  static data_config *configparser_pop(config_t *ctx) {
5888    data_config *old = ctx->current;
5889 -  ctx->current = (data_config *) array_pop(ctx->configs_stack);
5890 +  ctx->current = (data_config *) buffer_ptr_pop(ctx->configs_stack);
5891    return old;
5892  }
5893  
5894  /* return a copied variable */
5895  static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
5896 -  if (strncmp(key->ptr, "env.", sizeof("env.") - 1) == 0) {
5897 -    char *env;
5898 -
5899 -    if (NULL != (env = getenv(key->ptr + 4))) {
5900 -      data_string *ds;
5901 -      ds = data_string_init();
5902 -      buffer_append_string(ds->value, env);
5903 -      return (data_unset *)ds;
5904 -    }
5905 -
5906 -    fprintf(stderr, "Undefined env variable: %s\n", key->ptr + 4);
5907 -    ctx->ok = 0;
5908 -
5909 -    return NULL;
5910 -  } else {
5911 -    data_unset *du;
5912 -    data_config *dc;
5913 +  data_unset *du;
5914 +  data_config *dc;
5915  
5916  #if 0
5917 -    fprintf(stderr, "get var %s\n", key->ptr);
5918 +  fprintf(stderr, "get var %s\n", key->ptr);
5919  #endif
5920 -    for (dc = ctx->current; dc; dc = dc->parent) {
5921 +  for (dc = ctx->current; dc; dc = dc->parent) {
5922  #if 0
5923 -      fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
5924 -      array_print(dc->value, 0);
5925 +    fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
5926 +    array_print(dc->value, 0);
5927  #endif
5928 -      if (NULL != (du = array_get_element(dc->value, key->ptr))) {
5929 -        return du->copy(du);
5930 -      }
5931 +    if (NULL != (du = array_get_element(dc->value, key->ptr))) {
5932 +      return du->copy(du);
5933      }
5934 -    fprintf(stderr, "Undefined config variable: %s\n", key->ptr);
5935 -    ctx->ok = 0;
5936 -    return NULL;
5937    }
5938 +  return NULL;
5939  }
5940  
5941  /* op1 is to be eat/return by this function, op1->key is not cared
5942 @@ -141,6 +123,7 @@
5943  %type       aelement               {data_unset *}
5944  %type       condline               {data_config *}
5945  %type       condlines              {data_config *}
5946 +%type       global                 {data_config *}
5947  %type       aelements              {array *}
5948  %type       array                  {array *}
5949  %type       key                    {buffer *}
5950 @@ -161,7 +144,12 @@
5951  
5952  varline ::= key(A) ASSIGN expression(B). {
5953    buffer_copy_string_buffer(B->key, A);
5954 -  if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
5955 +  if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
5956 +    fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
5957 +        ctx->current->context_ndx,
5958 +        ctx->current->key->ptr, A->ptr);
5959 +    ctx->ok = 0;
5960 +  } else if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
5961      array_insert_unique(ctx->current->value, B);
5962      B = NULL;
5963    } else {
5964 @@ -180,7 +168,12 @@
5965    array *vars = ctx->current->value;
5966    data_unset *du;
5967  
5968 -  if (NULL != (du = array_get_element(vars, A->ptr))) {
5969 +  if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
5970 +    fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
5971 +        ctx->current->context_ndx,
5972 +        ctx->current->key->ptr, A->ptr);
5973 +    ctx->ok = 0;
5974 +  } else if (NULL != (du = array_get_element(vars, A->ptr))) {
5975      /* exists in current block */
5976      du = configparser_merge_data(du, B);
5977      if (NULL == du) {
5978 @@ -190,6 +183,7 @@
5979        buffer_copy_string_buffer(du->key, A);
5980        array_replace(vars, du);
5981      }
5982 +    B->free(B);
5983    } else if (NULL != (du = configparser_get_variable(ctx, A))) {
5984      du = configparser_merge_data(du, B);
5985      if (NULL == du) {
5986 @@ -199,15 +193,13 @@
5987        buffer_copy_string_buffer(du->key, A);
5988        array_insert_unique(ctx->current->value, du);
5989      }
5990 +    B->free(B);
5991    } else {
5992 -    fprintf(stderr, "Undefined config variable in conditional %d %s: %s\n", 
5993 -            ctx->current->context_ndx,
5994 -            ctx->current->key->ptr, A->ptr);
5995 -    ctx->ok = 0;
5996 +    buffer_copy_string_buffer(B->key, A);
5997 +    array_insert_unique(ctx->current->value, B);
5998    }
5999    buffer_free(A);
6000    A = NULL;
6001 -  B->free(B);
6002    B = NULL;
6003  }
6004  
6005 @@ -239,7 +231,24 @@
6006  }
6007  
6008  value(A) ::= key(B). {
6009 -  A = configparser_get_variable(ctx, B);
6010 +  if (strncmp(B->ptr, "env.", sizeof("env.") - 1) == 0) {
6011 +    char *env;
6012 +
6013 +    if (NULL != (env = getenv(B->ptr + 4))) {
6014 +      data_string *ds;
6015 +      ds = data_string_init();
6016 +      buffer_append_string(ds->value, env);
6017 +      A = (data_unset *)ds;
6018 +    }
6019 +    else {
6020 +      A = NULL;
6021 +      fprintf(stderr, "Undefined env variable: %s\n", B->ptr + 4);
6022 +      ctx->ok = 0;
6023 +    }
6024 +  } else if (NULL == (A = configparser_get_variable(ctx, B))) {
6025 +    fprintf(stderr, "Undefined config variable: %s\n", B->ptr);
6026 +    ctx->ok = 0;
6027 +  }
6028    if (!A) {
6029      /* make a dummy so it won't crash */
6030      A = (data_unset *)data_string_init();
6031 @@ -267,6 +276,9 @@
6032    ((data_array *)(A))->value = B;
6033    B = NULL;
6034  }
6035 +array(A) ::= LPARAN RPARAN. {
6036 +  A = array_init();
6037 +}
6038  array(A) ::= LPARAN aelements(B) RPARAN. {
6039    A = B;
6040    B = NULL;
6041 --- ../lighttpd-1.4.11/src/connections-glue.c   2005-09-12 10:04:23.000000000 +0300
6042 +++ lighttpd-1.4.12/src/connections-glue.c      2006-07-16 00:26:03.000000000 +0300
6043 @@ -13,7 +13,7 @@
6044         case CON_STATE_REQUEST_END: return "req-end";
6045         case CON_STATE_RESPONSE_START: return "resp-start";
6046         case CON_STATE_RESPONSE_END: return "resp-end";
6047 -       default: return "(unknown)";    
6048 +       default: return "(unknown)";
6049         }
6050  }
6051  
6052 @@ -30,15 +30,15 @@
6053         case CON_STATE_REQUEST_END: return "Q";
6054         case CON_STATE_RESPONSE_START: return "s";
6055         case CON_STATE_RESPONSE_END: return "S";
6056 -       default: return "x";    
6057 +       default: return "x";
6058         }
6059  }
6060  
6061  int connection_set_state(server *srv, connection *con, connection_state_t state) {
6062         UNUSED(srv);
6063 -       
6064 +
6065         con->state = state;
6066 -       
6067 +
6068         return 0;
6069  }
6070  
6071 --- ../lighttpd-1.4.11/src/connections.c        2006-03-05 22:14:53.000000000 +0200
6072 +++ lighttpd-1.4.12/src/connections.c   2006-07-18 13:03:40.000000000 +0300
6073 @@ -2,7 +2,6 @@
6074  
6075  #include <stdlib.h>
6076  #include <stdio.h>
6077 -#include <unistd.h>
6078  #include <errno.h>
6079  #include <string.h>
6080  #include <fcntl.h>
6081 @@ -26,8 +25,8 @@
6082  #include "inet_ntop_cache.h"
6083  
6084  #ifdef USE_OPENSSL
6085 -# include <openssl/ssl.h> 
6086 -# include <openssl/err.h> 
6087 +# include <openssl/ssl.h>
6088 +# include <openssl/err.h>
6089  #endif
6090  
6091  #ifdef HAVE_SYS_FILIO_H
6092 @@ -35,15 +34,16 @@
6093  #endif
6094  
6095  #include "sys-socket.h"
6096 +#include "sys-files.h"
6097  
6098  typedef struct {
6099 -               PLUGIN_DATA;
6100 +       PLUGIN_DATA;
6101  } plugin_data;
6102  
6103  static connection *connections_get_new_connection(server *srv) {
6104         connections *conns = srv->conns;
6105         size_t i;
6106 -       
6107 +
6108         if (conns->size == 0) {
6109                 conns->size = 128;
6110                 conns->ptr = NULL;
6111 @@ -54,21 +54,14 @@
6112         } else if (conns->size == conns->used) {
6113                 conns->size += 128;
6114                 conns->ptr = realloc(conns->ptr, sizeof(*conns->ptr) * conns->size);
6115 -               
6116 +
6117                 for (i = conns->used; i < conns->size; i++) {
6118                         conns->ptr[i] = connection_init(srv);
6119                 }
6120         }
6121  
6122         connection_reset(srv, conns->ptr[conns->used]);
6123 -#if 0  
6124 -       fprintf(stderr, "%s.%d: add: ", __FILE__, __LINE__);
6125 -       for (i = 0; i < conns->used + 1; i++) {
6126 -               fprintf(stderr, "%d ", conns->ptr[i]->fd);
6127 -       }
6128 -       fprintf(stderr, "\n");
6129 -#endif 
6130 -       
6131 +
6132         conns->ptr[conns->used]->ndx = conns->used;
6133         return conns->ptr[conns->used++];
6134  }
6135 @@ -77,263 +70,134 @@
6136         size_t i;
6137         connections *conns = srv->conns;
6138         connection *temp;
6139 -       
6140 +
6141         if (con == NULL) return -1;
6142 -       
6143 +
6144         if (-1 == con->ndx) return -1;
6145 -       
6146 +
6147         i = con->ndx;
6148 -       
6149 +
6150         /* not last element */
6151 -       
6152 +
6153         if (i != conns->used - 1) {
6154                 temp = conns->ptr[i];
6155                 conns->ptr[i] = conns->ptr[conns->used - 1];
6156                 conns->ptr[conns->used - 1] = temp;
6157 -               
6158 +
6159                 conns->ptr[i]->ndx = i;
6160                 conns->ptr[conns->used - 1]->ndx = -1;
6161         }
6162 -       
6163 +
6164         conns->used--;
6165 -       
6166 +
6167         con->ndx = -1;
6168 -#if 0
6169 -       fprintf(stderr, "%s.%d: del: (%d)", __FILE__, __LINE__, conns->used);
6170 -       for (i = 0; i < conns->used; i++) {
6171 -               fprintf(stderr, "%d ", conns->ptr[i]->fd);
6172 -       }
6173 -       fprintf(stderr, "\n");
6174 -#endif 
6175 +
6176         return 0;
6177  }
6178  
6179  int connection_close(server *srv, connection *con) {
6180  #ifdef USE_OPENSSL
6181         server_socket *srv_sock = con->srv_socket;
6182 -#endif
6183 -       
6184 -#ifdef USE_OPENSSL
6185 +
6186         if (srv_sock->is_ssl) {
6187 -               if (con->ssl) SSL_free(con->ssl);
6188 -               con->ssl = NULL;
6189 +               if (con->sock->ssl) SSL_free(con->sock->ssl);
6190 +               con->sock->ssl = NULL;
6191         }
6192  #endif
6193 -       
6194 -       fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
6195 -       fdevent_unregister(srv->ev, con->fd);
6196 -#ifdef __WIN32
6197 -       if (closesocket(con->fd)) {
6198 -               log_error_write(srv, __FILE__, __LINE__, "sds",
6199 -                               "(warning) close:", con->fd, strerror(errno));
6200 -       }
6201 -#else
6202 -       if (close(con->fd)) {
6203 +
6204 +       fdevent_event_del(srv->ev, con->sock);
6205 +       fdevent_unregister(srv->ev, con->sock);
6206 +
6207 +       if (closesocket(con->sock->fd)) {
6208                 log_error_write(srv, __FILE__, __LINE__, "sds",
6209 -                               "(warning) close:", con->fd, strerror(errno));
6210 +                               "(warning) close:", con->sock->fd, strerror(errno));
6211         }
6212 -#endif
6213 -       
6214 +
6215         srv->cur_fds--;
6216 -#if 0
6217 -       log_error_write(srv, __FILE__, __LINE__, "sd",
6218 -                       "closed()", con->fd);
6219 -#endif
6220 -       
6221 +
6222         connection_del(srv, con);
6223         connection_set_state(srv, con, CON_STATE_CONNECT);
6224 -       
6225 +
6226         return 0;
6227  }
6228  
6229  #if 0
6230  static void dump_packet(const unsigned char *data, size_t len) {
6231         size_t i, j;
6232 -       
6233 +
6234         if (len == 0) return;
6235 -       
6236 +
6237         for (i = 0; i < len; i++) {
6238                 if (i % 16 == 0) fprintf(stderr, "  ");
6239 -               
6240 +
6241                 fprintf(stderr, "%02x ", data[i]);
6242 -               
6243 +
6244                 if ((i + 1) % 16 == 0) {
6245                         fprintf(stderr, "  ");
6246                         for (j = 0; j <= i % 16; j++) {
6247                                 unsigned char c;
6248 -                               
6249 +
6250                                 if (i-15+j >= len) break;
6251 -                               
6252 +
6253                                 c = data[i-15+j];
6254 -                               
6255 +
6256                                 fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
6257                         }
6258 -                       
6259 +
6260                         fprintf(stderr, "\n");
6261                 }
6262         }
6263 -       
6264 +
6265         if (len % 16 != 0) {
6266                 for (j = i % 16; j < 16; j++) {
6267                         fprintf(stderr, "   ");
6268                 }
6269 -               
6270 +
6271                 fprintf(stderr, "  ");
6272                 for (j = i & ~0xf; j < len; j++) {
6273                         unsigned char c;
6274 -                       
6275 +
6276                         c = data[j];
6277                         fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
6278                 }
6279                 fprintf(stderr, "\n");
6280         }
6281  }
6282 -#endif 
6283 -
6284 -static int connection_handle_read(server *srv, connection *con) {
6285 -       int len;
6286 -       buffer *b;
6287 -       int toread;
6288 -#ifdef USE_OPENSSL
6289 -       server_socket *srv_sock = con->srv_socket;
6290  #endif
6291  
6292 -       b = chunkqueue_get_append_buffer(con->read_queue);
6293 -       buffer_prepare_copy(b, 4096);
6294 -
6295 -#ifdef USE_OPENSSL
6296 -       if (srv_sock->is_ssl) {
6297 -               len = SSL_read(con->ssl, b->ptr, b->size - 1);
6298 -       } else {
6299 -               if (ioctl(con->fd, FIONREAD, &toread)) {
6300 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
6301 -                                       "unexpected end-of-file:",
6302 -                                       con->fd);
6303 -                       return -1;
6304 -               }
6305 -               buffer_prepare_copy(b, toread);
6306 +static network_status_t connection_handle_read(server *srv, connection *con) {
6307 +       off_t oldlen, newlen;
6308  
6309 -               len = read(con->fd, b->ptr, b->size - 1);
6310 -       }
6311 -#elif defined(__WIN32)
6312 -       len = recv(con->fd, b->ptr, b->size - 1, 0);
6313 -#else
6314 -       if (ioctl(con->fd, FIONREAD, &toread)) {
6315 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
6316 -                               "unexpected end-of-file:",
6317 -                               con->fd);
6318 -               return -1;
6319 -       }
6320 -       buffer_prepare_copy(b, toread);
6321 +       oldlen = chunkqueue_length(con->read_queue);
6322  
6323 -       len = read(con->fd, b->ptr, b->size - 1);
6324 -#endif
6325 -       
6326 -       if (len < 0) {
6327 +       switch(network_read_chunkqueue(srv, con, con->read_queue)) {
6328 +       case NETWORK_STATUS_SUCCESS:
6329 +               break;
6330 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
6331 +               con->is_readable = 0;
6332 +               return NETWORK_STATUS_WAIT_FOR_EVENT;
6333 +       case NETWORK_STATUS_INTERRUPTED:
6334 +               con->is_readable = 1;
6335 +               return NETWORK_STATUS_WAIT_FOR_EVENT;
6336 +       case NETWORK_STATUS_CONNECTION_CLOSE:
6337 +               /* pipelining */
6338 +               con->is_readable = 0;
6339 +               return NETWORK_STATUS_CONNECTION_CLOSE;
6340 +       case NETWORK_STATUS_FATAL_ERROR:
6341                 con->is_readable = 0;
6342 -               
6343 -#ifdef USE_OPENSSL
6344 -               if (srv_sock->is_ssl) {
6345 -                       int r, ssl_err;
6346 -                       
6347 -                       switch ((r = SSL_get_error(con->ssl, len))) {
6348 -                       case SSL_ERROR_WANT_READ:
6349 -                               return 0;
6350 -                       case SSL_ERROR_SYSCALL:
6351 -                               /**
6352 -                                * man SSL_get_error()
6353 -                                * 
6354 -                                * SSL_ERROR_SYSCALL
6355 -                                *   Some I/O error occurred.  The OpenSSL error queue may contain more 
6356 -                                *   information on the error.  If the error queue is empty (i.e.
6357 -                                *   ERR_get_error() returns 0), ret can be used to find out more about 
6358 -                                *   the error: If ret == 0, an EOF was observed that violates the
6359 -                                *   protocol.  If ret == -1, the underlying BIO reported an I/O error 
6360 -                                *   (for socket I/O on Unix systems, consult errno for details).
6361 -                                *
6362 -                                */
6363 -                               while((ssl_err = ERR_get_error())) {
6364 -                                       /* get all errors from the error-queue */
6365 -                                       log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:", 
6366 -                                                       r, ERR_error_string(ssl_err, NULL));
6367 -                               }
6368  
6369 -                               switch(errno) {
6370 -                               default:
6371 -                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", 
6372 -                                                       len, r, errno,
6373 -                                                       strerror(errno));
6374 -                                       break;
6375 -                               }
6376 -                               
6377 -                               break;
6378 -                       case SSL_ERROR_ZERO_RETURN:
6379 -                               /* clean shutdown on the remote side */
6380 -                               
6381 -                               if (r == 0) {
6382 -                                       /* FIXME: later */
6383 -                               }
6384 -                               
6385 -                               /* fall thourgh */
6386 -                       default:
6387 -                               while((ssl_err = ERR_get_error())) {
6388 -                                       /* get all errors from the error-queue */
6389 -                                       log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:", 
6390 -                                                       r, ERR_error_string(ssl_err, NULL));
6391 -                               }
6392 -                               break;
6393 -                       }
6394 -               } else {
6395 -                       if (errno == EAGAIN) return 0;
6396 -                       if (errno == EINTR) {
6397 -                               /* we have been interrupted before we could read */
6398 -                               con->is_readable = 1;
6399 -                               return 0;
6400 -                       }
6401 -               
6402 -                       if (errno != ECONNRESET) {
6403 -                               /* expected for keep-alive */
6404 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
6405 -                       }
6406 -               }
6407 -#else
6408 -               if (errno == EAGAIN) return 0;
6409 -               if (errno == EINTR) {
6410 -                       /* we have been interrupted before we could read */
6411 -                       con->is_readable = 1;
6412 -                       return 0;
6413 -               }
6414 -               
6415 -               if (errno != ECONNRESET) {
6416 -                       /* expected for keep-alive */
6417 -                       log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
6418 -               }
6419 -#endif
6420                 connection_set_state(srv, con, CON_STATE_ERROR);
6421 -               
6422 -               return -1;
6423 -       } else if (len == 0) {
6424 -               con->is_readable = 0;
6425 -               /* the other end close the connection -> KEEP-ALIVE */
6426 +               return NETWORK_STATUS_FATAL_ERROR;
6427 +       default:
6428 +               SEGFAULT();
6429 +               break;
6430 +       }
6431  
6432 -               /* pipelining */
6433 +       newlen = chunkqueue_length(con->read_queue);
6434  
6435 -               return -2;
6436 -       } else if ((size_t)len < b->size - 1) {
6437 -               /* we got less then expected, wait for the next fd-event */
6438 -               
6439 -               con->is_readable = 0;
6440 -       }
6441 -       
6442 -       b->used = len;
6443 -       b->ptr[b->used++] = '\0';
6444 -       
6445 -       con->bytes_read += len;
6446 -#if 0
6447 -       dump_packet(b->ptr, len);
6448 -#endif
6449 -       
6450 -       return 0;
6451 +       con->bytes_read += (newlen - oldlen);
6452 +
6453 +       return NETWORK_STATUS_SUCCESS;
6454  }
6455  
6456  static int connection_handle_write_prepare(server *srv, connection *con) {
6457 @@ -343,6 +207,7 @@
6458                 case HTTP_METHOD_GET:
6459                 case HTTP_METHOD_POST:
6460                 case HTTP_METHOD_HEAD:
6461 +                       /* webdav */
6462                 case HTTP_METHOD_PUT:
6463                 case HTTP_METHOD_MKCOL:
6464                 case HTTP_METHOD_DELETE:
6465 @@ -350,12 +215,14 @@
6466                 case HTTP_METHOD_MOVE:
6467                 case HTTP_METHOD_PROPFIND:
6468                 case HTTP_METHOD_PROPPATCH:
6469 +               case HTTP_METHOD_LOCK:
6470 +               case HTTP_METHOD_UNLOCK:
6471                         break;
6472                 case HTTP_METHOD_OPTIONS:
6473                         /*
6474                          * 400 is coming from the request-parser BEFORE uri.path is set
6475 -                        * 403 is from the response handler when noone else catched it 
6476 -                        * 
6477 +                        * 403 is from the response handler when noone else catched it
6478 +                        *
6479                          * */
6480                         if (con->uri.path->used &&
6481                             con->uri.path->ptr[0] != '*') {
6482 @@ -381,55 +248,60 @@
6483                         break;
6484                 }
6485         }
6486 -       
6487 +
6488         if (con->http_status == 0) {
6489                 con->http_status = 403;
6490         }
6491 -       
6492 +
6493         switch(con->http_status) {
6494         case 400: /* class: header + custom body */
6495         case 401:
6496         case 403:
6497         case 404:
6498         case 408:
6499 +       case 409:
6500 +       case 410:
6501         case 411:
6502         case 416:
6503         case 423:
6504         case 500:
6505         case 501:
6506 +       case 502:
6507         case 503:
6508 -       case 505: 
6509 +       case 504:
6510 +       case 505:
6511 +       case 509:
6512                 if (con->mode != DIRECT) break;
6513 -               
6514 +
6515                 con->file_finished = 0;
6516 -               
6517 +
6518                 buffer_reset(con->physical.path);
6519 -                               
6520 +
6521                 /* try to send static errorfile */
6522                 if (!buffer_is_empty(con->conf.errorfile_prefix)) {
6523                         stat_cache_entry *sce = NULL;
6524 -                       
6525 +
6526                         buffer_copy_string_buffer(con->physical.path, con->conf.errorfile_prefix);
6527                         buffer_append_string(con->physical.path, get_http_status_body_name(con->http_status));
6528 -                       
6529 +
6530                         if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
6531                                 con->file_finished = 1;
6532 -                               
6533 +
6534                                 http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
6535                                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
6536                         }
6537                 }
6538 -               
6539 -               if (!con->file_finished) {                      
6540 +
6541 +               if (!con->file_finished) {
6542                         buffer *b;
6543 -                       
6544 +
6545                         buffer_reset(con->physical.path);
6546 -                       
6547 +
6548                         con->file_finished = 1;
6549                         b = chunkqueue_get_append_buffer(con->write_queue);
6550 -                               
6551 +
6552                         /* build default error-page */
6553 -                       buffer_copy_string(b, 
6554 +                       buffer_copy_string(b,
6555                                            "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
6556                                            "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
6557                                            "         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
6558 @@ -439,7 +311,7 @@
6559                         buffer_append_long(b, con->http_status);
6560                         buffer_append_string(b, " - ");
6561                         buffer_append_string(b, get_http_status_name(con->http_status));
6562 -                       
6563 +
6564                         buffer_append_string(b,
6565                                              "</title>\n"
6566                                              " </head>\n"
6567 @@ -448,12 +320,12 @@
6568                         buffer_append_long(b, con->http_status);
6569                         buffer_append_string(b, " - ");
6570                         buffer_append_string(b, get_http_status_name(con->http_status));
6571 -                       
6572 -                       buffer_append_string(b,"</h1>\n" 
6573 +
6574 +                       buffer_append_string(b,"</h1>\n"
6575                                              " </body>\n"
6576                                              "</html>\n"
6577                                              );
6578 -                       
6579 +
6580                         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
6581                 }
6582                 /* fall through */
6583 @@ -463,10 +335,10 @@
6584         case 301:
6585         case 302:
6586                 break;
6587 -               
6588 +
6589         case 206: /* write_queue is already prepared */
6590                 con->file_finished = 1;
6591 -               
6592 +
6593                 break;
6594         case 205: /* class: header only */
6595         case 304:
6596 @@ -474,19 +346,19 @@
6597                 /* disable chunked encoding again as we have no body */
6598                 con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
6599                 chunkqueue_reset(con->write_queue);
6600 -               
6601 +
6602                 con->file_finished = 1;
6603                 break;
6604         }
6605 -       
6606 +
6607  
6608         if (con->file_finished) {
6609 -               /* we have all the content and chunked encoding is not used, set a content-length */ 
6610 -               
6611 -               if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) && 
6612 +               /* we have all the content and chunked encoding is not used, set a content-length */
6613 +
6614 +               if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) &&
6615                     (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) {
6616                         buffer_copy_off_t(srv->tmp_buf, chunkqueue_length(con->write_queue));
6617 -               
6618 +
6619                         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf));
6620                 }
6621         } else {
6622 @@ -495,77 +367,79 @@
6623                     ((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0)) {
6624                         con->keep_alive = 0;
6625                 }
6626 -               
6627 +
6628                 if (0 == (con->parsed_response & HTTP_CONNECTION)) {
6629                         /* (f)cgi did'nt send Connection: header
6630 -                        *                          
6631 +                        *
6632                          * shall we ?
6633                          */
6634                         if (((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) &&
6635                             (con->parsed_response & HTTP_CONTENT_LENGTH) == 0) {
6636                                 /* without content_length, no keep-alive */
6637 -                               
6638 +
6639                                 con->keep_alive = 0;
6640                         }
6641                 } else {
6642                         /* a subrequest disable keep-alive although the client wanted it */
6643                         if (con->keep_alive && !con->response.keep_alive) {
6644                                 con->keep_alive = 0;
6645 -                               
6646 +
6647                                 /* FIXME: we have to drop the Connection: Header from the subrequest */
6648                         }
6649                 }
6650         }
6651 -       
6652 +
6653         if (con->request.http_method == HTTP_METHOD_HEAD) {
6654                 chunkqueue_reset(con->write_queue);
6655         }
6656  
6657         http_response_write_header(srv, con);
6658 -               
6659 +
6660         return 0;
6661  }
6662  
6663  static int connection_handle_write(server *srv, connection *con) {
6664         switch(network_write_chunkqueue(srv, con, con->write_queue)) {
6665 -       case 0:
6666 +       case NETWORK_STATUS_SUCCESS:
6667                 if (con->file_finished) {
6668                         connection_set_state(srv, con, CON_STATE_RESPONSE_END);
6669                         joblist_append(srv, con);
6670                 }
6671                 break;
6672 -       case -1: /* error on our side */
6673 +       case NETWORK_STATUS_FATAL_ERROR: /* error on our side */
6674                 log_error_write(srv, __FILE__, __LINE__, "sd",
6675 -                               "connection closed: write failed on fd", con->fd);
6676 +                               "connection closed: write failed on fd", con->sock->fd);
6677                 connection_set_state(srv, con, CON_STATE_ERROR);
6678                 joblist_append(srv, con);
6679                 break;
6680 -       case -2: /* remote close */
6681 +       case NETWORK_STATUS_CONNECTION_CLOSE: /* remote close */
6682                 connection_set_state(srv, con, CON_STATE_ERROR);
6683                 joblist_append(srv, con);
6684                 break;
6685 -       case 1:
6686 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
6687                 con->is_writable = 0;
6688 -               
6689 +
6690                 /* not finished yet -> WRITE */
6691                 break;
6692 +       case NETWORK_STATUS_INTERRUPTED:
6693 +               con->is_writable = 1;
6694 +               break;
6695 +       case NETWORK_STATUS_UNSET:
6696 +               break;
6697         }
6698 -       
6699 +
6700         return 0;
6701  }
6702  
6703 -
6704 -
6705  connection *connection_init(server *srv) {
6706         connection *con;
6707 -       
6708 +
6709         UNUSED(srv);
6710  
6711         con = calloc(1, sizeof(*con));
6712 -               
6713 -       con->fd = 0;
6714 +
6715 +       con->sock = iosocket_init();
6716         con->ndx = -1;
6717 -       con->fde_ndx = -1;
6718         con->bytes_written = 0;
6719         con->bytes_read = 0;
6720         con->bytes_header = 0;
6721 @@ -573,32 +447,32 @@
6722  
6723  #define CLEAN(x) \
6724         con->x = buffer_init();
6725 -       
6726 +
6727         CLEAN(request.uri);
6728         CLEAN(request.request_line);
6729         CLEAN(request.request);
6730         CLEAN(request.pathinfo);
6731 -       
6732 +
6733         CLEAN(request.orig_uri);
6734 -       
6735 +
6736         CLEAN(uri.scheme);
6737         CLEAN(uri.authority);
6738         CLEAN(uri.path);
6739         CLEAN(uri.path_raw);
6740         CLEAN(uri.query);
6741 -       
6742 +
6743         CLEAN(physical.doc_root);
6744         CLEAN(physical.path);
6745         CLEAN(physical.basedir);
6746         CLEAN(physical.rel_path);
6747         CLEAN(physical.etag);
6748         CLEAN(parse_request);
6749 -       
6750 +
6751         CLEAN(authed_user);
6752         CLEAN(server_name);
6753         CLEAN(error_handler);
6754         CLEAN(dst_addr_buf);
6755 -       
6756 +
6757  #undef CLEAN
6758         con->write_queue = chunkqueue_init();
6759         con->read_queue = chunkqueue_init();
6760 @@ -608,26 +482,27 @@
6761         con->request.headers      = array_init();
6762         con->response.headers     = array_init();
6763         con->environment     = array_init();
6764 -       
6765 +
6766         /* init plugin specific connection structures */
6767 -       
6768 +
6769         con->plugin_ctx = calloc(1, (srv->plugins.used + 1) * sizeof(void *));
6770 -       
6771 +
6772         con->cond_cache = calloc(srv->config_context->used, sizeof(cond_cache_t));
6773         config_setup_connection(srv, con);
6774 -       
6775 +
6776         return con;
6777  }
6778  
6779  void connections_free(server *srv) {
6780         connections *conns = srv->conns;
6781 -       size_t i;       
6782 -       
6783 +       size_t i;
6784 +
6785         for (i = 0; i < conns->size; i++) {
6786                 connection *con = conns->ptr[i];
6787 -               
6788 +
6789                 connection_reset(srv, con);
6790 -               
6791 +               iosocket_free(con->sock);
6792 +
6793                 chunkqueue_free(con->write_queue);
6794                 chunkqueue_free(con->read_queue);
6795                 chunkqueue_free(con->request_content_queue);
6796 @@ -637,27 +512,27 @@
6797  
6798  #define CLEAN(x) \
6799         buffer_free(con->x);
6800 -               
6801 +
6802                 CLEAN(request.uri);
6803                 CLEAN(request.request_line);
6804                 CLEAN(request.request);
6805                 CLEAN(request.pathinfo);
6806 -               
6807 +
6808                 CLEAN(request.orig_uri);
6809 -               
6810 +
6811                 CLEAN(uri.scheme);
6812                 CLEAN(uri.authority);
6813                 CLEAN(uri.path);
6814                 CLEAN(uri.path_raw);
6815                 CLEAN(uri.query);
6816 -               
6817 +
6818                 CLEAN(physical.doc_root);
6819                 CLEAN(physical.path);
6820                 CLEAN(physical.basedir);
6821                 CLEAN(physical.etag);
6822                 CLEAN(physical.rel_path);
6823                 CLEAN(parse_request);
6824 -               
6825 +
6826                 CLEAN(authed_user);
6827                 CLEAN(server_name);
6828                 CLEAN(error_handler);
6829 @@ -665,97 +540,97 @@
6830  #undef CLEAN
6831                 free(con->plugin_ctx);
6832                 free(con->cond_cache);
6833 -               
6834 +
6835                 free(con);
6836         }
6837 -       
6838 +
6839         free(conns->ptr);
6840  }
6841  
6842  
6843  int connection_reset(server *srv, connection *con) {
6844         size_t i;
6845 -       
6846 +
6847         plugins_call_connection_reset(srv, con);
6848 -       
6849 +
6850         con->is_readable = 1;
6851         con->is_writable = 1;
6852         con->http_status = 0;
6853         con->file_finished = 0;
6854         con->file_started = 0;
6855         con->got_response = 0;
6856 -       
6857 +
6858         con->parsed_response = 0;
6859 -       
6860 +
6861         con->bytes_written = 0;
6862         con->bytes_written_cur_second = 0;
6863         con->bytes_read = 0;
6864         con->bytes_header = 0;
6865         con->loops_per_request = 0;
6866 -       
6867 +
6868         con->request.http_method = HTTP_METHOD_UNSET;
6869         con->request.http_version = HTTP_VERSION_UNSET;
6870 -       
6871 +
6872         con->request.http_if_modified_since = NULL;
6873         con->request.http_if_none_match = NULL;
6874 -       
6875 +
6876         con->response.keep_alive = 0;
6877         con->response.content_length = -1;
6878         con->response.transfer_encoding = 0;
6879 -       
6880 +
6881         con->mode = DIRECT;
6882 -       
6883 +
6884  #define CLEAN(x) \
6885         if (con->x) buffer_reset(con->x);
6886 -       
6887 +
6888         CLEAN(request.uri);
6889         CLEAN(request.request_line);
6890         CLEAN(request.pathinfo);
6891         CLEAN(request.request);
6892 -       
6893 +
6894         CLEAN(request.orig_uri);
6895 -       
6896 +
6897         CLEAN(uri.scheme);
6898         CLEAN(uri.authority);
6899         CLEAN(uri.path);
6900         CLEAN(uri.path_raw);
6901         CLEAN(uri.query);
6902 -       
6903 +
6904         CLEAN(physical.doc_root);
6905         CLEAN(physical.path);
6906         CLEAN(physical.basedir);
6907         CLEAN(physical.rel_path);
6908         CLEAN(physical.etag);
6909 -       
6910 +
6911         CLEAN(parse_request);
6912 -       
6913 +
6914         CLEAN(authed_user);
6915         CLEAN(server_name);
6916         CLEAN(error_handler);
6917 -#undef CLEAN   
6918 -       
6919 +#undef CLEAN
6920 +
6921  #define CLEAN(x) \
6922 -       if (con->x) con->x->used = 0;   
6923 -       
6924 +       if (con->x) con->x->used = 0;
6925 +
6926  #undef CLEAN
6927 -       
6928 +
6929  #define CLEAN(x) \
6930                 con->request.x = NULL;
6931 -       
6932 +
6933         CLEAN(http_host);
6934         CLEAN(http_range);
6935         CLEAN(http_content_type);
6936  #undef CLEAN
6937         con->request.content_length = 0;
6938 -       
6939 +
6940         array_reset(con->request.headers);
6941         array_reset(con->response.headers);
6942         array_reset(con->environment);
6943 -       
6944 +
6945         chunkqueue_reset(con->write_queue);
6946         chunkqueue_reset(con->request_content_queue);
6947  
6948 -       /* the plugins should cleanup themself */       
6949 +       /* the plugins should cleanup themself */
6950         for (i = 0; i < srv->plugins.used; i++) {
6951                 plugin *p = ((plugin **)(srv->plugins.ptr))[i];
6952                 plugin_data *pd = p->data;
6953 @@ -768,7 +643,7 @@
6954  
6955                 con->plugin_ctx[pd->id] = NULL;
6956         }
6957 -       
6958 +
6959  #if COND_RESULT_UNSET
6960         for (i = srv->config_context->used - 1; i >= 0; i --) {
6961                 con->cond_cache[i].result = COND_RESULT_UNSET;
6962 @@ -777,56 +652,56 @@
6963  #else
6964         memset(con->cond_cache, 0, sizeof(cond_cache_t) * srv->config_context->used);
6965  #endif
6966 -       
6967 +
6968         con->header_len = 0;
6969         con->in_error_handler = 0;
6970 -       
6971 +
6972         config_setup_connection(srv, con);
6973 -       
6974 +
6975         return 0;
6976  }
6977  
6978  /**
6979 - * 
6980 - * search for \r\n\r\n 
6981 - * 
6982 + *
6983 + * search for \r\n\r\n
6984 + *
6985   * this is a special 32bit version which is using a sliding window for
6986 - * the comparisions 
6987 - * 
6988 + * the comparisions
6989 + *
6990   * how it works:
6991 - * 
6992 + *
6993   * b:      'abcdefg'
6994   * rnrn:   'cdef'
6995 - * 
6996 + *
6997   * cmpbuf: abcd != cdef
6998   * cmpbuf: bcde != cdef
6999   * cmpbuf: cdef == cdef -> return &c
7000 - * 
7001 - * cmpbuf and rnrn are treated as 32bit uint and bit-ops are used to 
7002 + *
7003 + * cmpbuf and rnrn are treated as 32bit uint and bit-ops are used to
7004   * maintain cmpbuf and rnrn
7005 - * 
7006 + *
7007   */
7008  
7009  char *buffer_search_rnrn(buffer *b) {
7010         uint32_t cmpbuf, rnrn;
7011         char *cp;
7012         size_t i;
7013 -       
7014 +
7015         if (b->used < 4) return NULL;
7016 -       
7017 +
7018         rnrn = ('\r' << 24) | ('\n' << 16) |
7019                 ('\r' << 8) | ('\n' << 0);
7020 -       
7021 +
7022         cmpbuf = (b->ptr[0] << 24) | (b->ptr[1] << 16) |
7023                 (b->ptr[2] << 8) | (b->ptr[3] << 0);
7024 -               
7025 +
7026         cp = b->ptr + 4;
7027         for (i = 0; i < b->used - 4; i++) {
7028                 if (cmpbuf == rnrn) return cp - 4;
7029 -                       
7030 +
7031                 cmpbuf = (cmpbuf << 8 | *(cp++)) & 0xffffffff;
7032         }
7033 -       
7034 +
7035         return NULL;
7036  }
7037  /**
7038 @@ -840,22 +715,25 @@
7039         chunk *c;
7040         chunkqueue *cq = con->read_queue;
7041         chunkqueue *dst_cq = con->request_content_queue;
7042 -       
7043 +
7044         if (con->is_readable) {
7045                 con->read_idle_ts = srv->cur_ts;
7046 -       
7047 +
7048                 switch(connection_handle_read(srv, con)) {
7049 -               case -1:
7050 +               case NETWORK_STATUS_FATAL_ERROR:
7051                         return -1;
7052 -               case -2:
7053 +               case NETWORK_STATUS_CONNECTION_CLOSE:
7054                         /* remote side closed the connection
7055                          * if we still have content, handle it, if not leave here */
7056  
7057                         if (cq->first == cq->last &&
7058 -                           cq->first->mem->used == 0) {
7059 +                           (NULL == cq->first ||
7060 +                           cq->first->mem->used == 0)) {
7061  
7062                                 /* conn-closed, leave here */
7063                                 connection_set_state(srv, con, CON_STATE_ERROR);
7064 +
7065 +                               return 0;
7066                         }
7067                 default:
7068                         break;
7069 @@ -891,14 +769,14 @@
7070                         /* the last node was empty */
7071                         if (c->next == NULL) {
7072                                 cq->last = c;
7073 -                       } 
7074 +                       }
7075  
7076                         c = c->next;
7077                 } else {
7078                         c = c->next;
7079                 }
7080         }
7081 -       
7082 +
7083         /* nothing to handle */
7084         if (cq->first == NULL) return 0;
7085  
7086 @@ -906,25 +784,26 @@
7087         case CON_STATE_READ:
7088                 /* prepare con->request.request */
7089                 c = cq->first;
7090 -               
7091 +
7092                 /* check if we need the full package */
7093                 if (con->request.request->used == 0) {
7094                         buffer b;
7095 -                       
7096 +
7097                         b.ptr = c->mem->ptr + c->offset;
7098                         b.used = c->mem->used - c->offset;
7099 -                       
7100 +
7101                         if (NULL != (h_term = buffer_search_rnrn(&b))) {
7102                                 /* \r\n\r\n found
7103                                  * - copy everything incl. the terminator to request.request
7104                                  */
7105 -                               
7106 -                               buffer_copy_string_len(con->request.request, 
7107 -                                                      b.ptr, 
7108 +
7109 +                               buffer_copy_string_len(con->request.request,
7110 +                                                      b.ptr,
7111                                                        h_term - b.ptr + 4);
7112 -                               
7113 +
7114                                 /* the buffer has been read up to the terminator */
7115                                 c->offset += h_term - b.ptr + 4;
7116 +
7117                         } else {
7118                                 /* not found, copy everything */
7119                                 buffer_copy_string_len(con->request.request, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
7120 @@ -932,14 +811,14 @@
7121                         }
7122                 } else {
7123                         /* have to take care of overlapping header terminators */
7124 -                       
7125 +
7126                         size_t l = con->request.request->used - 2;
7127                         char *s  = con->request.request->ptr;
7128                         buffer b;
7129 -                       
7130 +
7131                         b.ptr = c->mem->ptr + c->offset;
7132                         b.used = c->mem->used - c->offset;
7133 -                       
7134 +
7135                         if (con->request.request->used - 1 > 3 &&
7136                             c->mem->used > 1 &&
7137                             s[l-2] == '\r' &&
7138 @@ -948,7 +827,7 @@
7139                             c->mem->ptr[0] == '\n') {
7140                                 buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 1);
7141                                 c->offset += 1;
7142 -                               
7143 +
7144                                 h_term = con->request.request->ptr;
7145                         } else if (con->request.request->used - 1 > 2 &&
7146                                    c->mem->used > 2 &&
7147 @@ -958,7 +837,7 @@
7148                                    c->mem->ptr[1] == '\n') {
7149                                 buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 2);
7150                                 c->offset += 2;
7151 -                               
7152 +
7153                                 h_term = con->request.request->ptr;
7154                         } else if (con->request.request->used - 1 > 1 &&
7155                                    c->mem->used > 3 &&
7156 @@ -968,17 +847,17 @@
7157                                    c->mem->ptr[2] == '\n') {
7158                                 buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 3);
7159                                 c->offset += 3;
7160 -                               
7161 +
7162                                 h_term = con->request.request->ptr;
7163                         } else if (NULL != (h_term = buffer_search_string_len(&b, "\r\n\r\n", 4))) {
7164                                 /* \r\n\r\n found
7165                                  * - copy everything incl. the terminator to request.request
7166                                  */
7167 -                               
7168 -                               buffer_append_string_len(con->request.request, 
7169 -                                                      c->mem->ptr + c->offset, 
7170 +
7171 +                               buffer_append_string_len(con->request.request,
7172 +                                                      c->mem->ptr + c->offset,
7173                                                        c->offset + h_term - b.ptr + 4);
7174 -                               
7175 +
7176                                 /* the buffer has been read up to the terminator */
7177                                 c->offset += h_term - b.ptr + 4;
7178                         } else {
7179 @@ -999,16 +878,16 @@
7180                         connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7181                 }
7182                 break;
7183 -       case CON_STATE_READ_POST: 
7184 +       case CON_STATE_READ_POST:
7185                 for (c = cq->first; c && (dst_cq->bytes_in != (off_t)con->request.content_length); c = c->next) {
7186                         off_t weWant, weHave, toRead;
7187 -                       
7188 +
7189                         weWant = con->request.content_length - dst_cq->bytes_in;
7190 -                       
7191 +
7192                         assert(c->mem->used);
7193 -                       
7194 +
7195                         weHave = c->mem->used - c->offset - 1;
7196 -                               
7197 +
7198                         toRead = weHave > weWant ? weWant : weHave;
7199  
7200                         /* the new way, copy everything into a chunkqueue whcih might use tempfiles */
7201 @@ -1017,13 +896,13 @@
7202                                 /* copy everything to max 1Mb sized tempfiles */
7203  
7204                                 /*
7205 -                                * if the last chunk is 
7206 +                                * if the last chunk is
7207                                  * - smaller than 1Mb (size < 1Mb)
7208                                  * - not read yet (offset == 0)
7209                                  * -> append to it
7210                                  * otherwise
7211 -                                * -> create a new chunk 
7212 -                                * 
7213 +                                * -> create a new chunk
7214 +                                *
7215                                  * */
7216  
7217                                 if (dst_cq->last &&
7218 @@ -1056,14 +935,14 @@
7219                                 /* we have a chunk, let's write to it */
7220  
7221                                 if (dst_c->file.fd == -1) {
7222 -                                       /* we don't have file to write to, 
7223 +                                       /* we don't have file to write to,
7224                                          * EACCES might be one reason.
7225                                          *
7226                                          * Instead of sending 500 we send 413 and say the request is too large
7227                                          *  */
7228  
7229                                         log_error_write(srv, __FILE__, __LINE__, "sbs",
7230 -                                                       "denying upload as opening to temp-file for upload failed:", 
7231 +                                                       "denying upload as opening to temp-file for upload failed:",
7232                                                         dst_c->file.name, strerror(errno));
7233  
7234                                         con->http_status = 413; /* Request-Entity too large */
7235 @@ -1074,15 +953,15 @@
7236                                 }
7237  
7238                                 if (toRead != write(dst_c->file.fd, c->mem->ptr + c->offset, toRead)) {
7239 -                                       /* write failed for some reason ... disk full ? */ 
7240 +                                       /* write failed for some reason ... disk full ? */
7241                                         log_error_write(srv, __FILE__, __LINE__, "sbs",
7242 -                                                       "denying upload as writing to file failed:", 
7243 +                                                       "denying upload as writing to file failed:",
7244                                                         dst_c->file.name, strerror(errno));
7245 -                                       
7246 +
7247                                         con->http_status = 413; /* Request-Entity too large */
7248                                         con->keep_alive = 0;
7249                                         connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7250 -                               
7251 +
7252                                         close(dst_c->file.fd);
7253                                         dst_c->file.fd = -1;
7254  
7255 @@ -1090,7 +969,7 @@
7256                                 }
7257  
7258                                 dst_c->file.length += toRead;
7259 -                                       
7260 +
7261                                 if (dst_cq->bytes_in + toRead == (off_t)con->request.content_length) {
7262                                         /* we read everything, close the chunk */
7263                                         close(dst_c->file.fd);
7264 @@ -1102,7 +981,7 @@
7265                                 b = chunkqueue_get_append_buffer(dst_cq);
7266                                 buffer_copy_string_len(b, c->mem->ptr + c->offset, toRead);
7267                         }
7268 -                       
7269 +
7270                         c->offset += toRead;
7271                         dst_cq->bytes_in += toRead;
7272                 }
7273 @@ -1111,7 +990,7 @@
7274                 if (dst_cq->bytes_in == (off_t)con->request.content_length) {
7275                         connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7276                 }
7277 -                       
7278 +
7279                 break;
7280         }
7281  
7282 @@ -1123,100 +1002,104 @@
7283  handler_t connection_handle_fdevent(void *s, void *context, int revents) {
7284         server     *srv = (server *)s;
7285         connection *con = context;
7286 -       
7287 +
7288         joblist_append(srv, con);
7289 -       
7290 +
7291         if (revents & FDEVENT_IN) {
7292                 con->is_readable = 1;
7293 -#if 0
7294 -               log_error_write(srv, __FILE__, __LINE__, "sd", "read-wait - done", con->fd);
7295 -#endif
7296         }
7297         if (revents & FDEVENT_OUT) {
7298                 con->is_writable = 1;
7299                 /* we don't need the event twice */
7300         }
7301 -       
7302 -       
7303 +
7304 +
7305         if (revents & ~(FDEVENT_IN | FDEVENT_OUT)) {
7306                 /* looks like an error */
7307 -                                               
7308 +
7309                 /* FIXME: revents = 0x19 still means that we should read from the queue */
7310                 if (revents & FDEVENT_HUP) {
7311                         if (con->state == CON_STATE_CLOSE) {
7312                                 con->close_timeout_ts = 0;
7313                         } else {
7314                                 /* sigio reports the wrong event here
7315 -                                * 
7316 -                                * there was no HUP at all 
7317 +                                *
7318 +                                * there was no HUP at all
7319                                  */
7320  #ifdef USE_LINUX_SIGIO
7321                                 if (srv->ev->in_sigio == 1) {
7322                                         log_error_write(srv, __FILE__, __LINE__, "sd",
7323 -                                               "connection closed: poll() -> HUP", con->fd);
7324 +                                               "connection closed: poll() -> HUP", con->sock->fd);
7325                                 } else {
7326                                         connection_set_state(srv, con, CON_STATE_ERROR);
7327                                 }
7328  #else
7329                                 connection_set_state(srv, con, CON_STATE_ERROR);
7330  #endif
7331 -                               
7332 +
7333                         }
7334                 } else if (revents & FDEVENT_ERR) {
7335  #ifndef USE_LINUX_SIGIO
7336                         log_error_write(srv, __FILE__, __LINE__, "sd",
7337 -                                       "connection closed: poll() -> ERR", con->fd);
7338 -#endif 
7339 +                                       "connection closed: poll() -> ERR", con->sock->fd);
7340 +#endif
7341                         connection_set_state(srv, con, CON_STATE_ERROR);
7342                 } else {
7343                         log_error_write(srv, __FILE__, __LINE__, "sd",
7344                                         "connection closed: poll() -> ???", revents);
7345 -               } 
7346 +               }
7347         }
7348 -       
7349 +
7350         if (con->state == CON_STATE_READ ||
7351             con->state == CON_STATE_READ_POST) {
7352                 connection_handle_read_state(srv, con);
7353 +               /**
7354 +                * if SSL_read() is not readin in the full packet we won't get
7355 +                * a fdevent as the low-level has already fetched everything.
7356 +                *
7357 +                * we have to call the state-engine to read the rest of the packet
7358 +                */
7359 +               if (con->is_readable) joblist_append(srv, con);
7360         }
7361 -       
7362 +
7363         if (con->state == CON_STATE_WRITE &&
7364             !chunkqueue_is_empty(con->write_queue) &&
7365             con->is_writable) {
7366 -               
7367 +
7368                 if (-1 == connection_handle_write(srv, con)) {
7369                         connection_set_state(srv, con, CON_STATE_ERROR);
7370 -                       
7371 +
7372                         log_error_write(srv, __FILE__, __LINE__, "ds",
7373 -                                       con->fd,
7374 +                                       con->sock->fd,
7375                                         "handle write failed.");
7376                 } else if (con->state == CON_STATE_WRITE) {
7377                         con->write_request_ts = srv->cur_ts;
7378                 }
7379         }
7380 -       
7381 +
7382         if (con->state == CON_STATE_CLOSE) {
7383                 /* flush the read buffers */
7384                 int b;
7385 -               
7386 -               if (ioctl(con->fd, FIONREAD, &b)) {
7387 +
7388 +               if (ioctl(con->sock->fd, FIONREAD, &b)) {
7389                         log_error_write(srv, __FILE__, __LINE__, "ss",
7390                                         "ioctl() failed", strerror(errno));
7391                 }
7392 -               
7393 +
7394                 if (b > 0) {
7395                         char buf[1024];
7396                         log_error_write(srv, __FILE__, __LINE__, "sdd",
7397 -                                       "CLOSE-read()", con->fd, b);
7398 -                       
7399 +                                       "CLOSE-read()", con->sock->fd, b);
7400 +
7401                         /* */
7402 -                       read(con->fd, buf, sizeof(buf));
7403 +                       read(con->sock->fd, buf, sizeof(buf));
7404                 } else {
7405                         /* nothing to read */
7406 -                       
7407 +
7408                         con->close_timeout_ts = 0;
7409                 }
7410         }
7411 -       
7412 +
7413         return HANDLER_FINISHED;
7414  }
7415  
7416 @@ -1229,63 +1112,68 @@
7417         sock_addr cnt_addr;
7418         socklen_t cnt_len;
7419         /* accept it and register the fd */
7420 -       
7421 +
7422         cnt_len = sizeof(cnt_addr);
7423  
7424 -       if (-1 == (cnt = accept(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {
7425 +       if (-1 == (cnt = accept(srv_socket->sock->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {
7426 +#ifdef _WIN32
7427 +               errno = WSAGetLastError();
7428 +#endif
7429                 if ((errno != EAGAIN) &&
7430 +                   (errno != EWOULDBLOCK) &&
7431                     (errno != EINTR)) {
7432 -                       log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), errno);
7433 +                       log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), srv_socket->sock->fd);
7434                 }
7435                 return NULL;
7436         } else {
7437                 connection *con;
7438 -               
7439 +
7440                 srv->cur_fds++;
7441 -               
7442 +
7443                 /* ok, we have the connection, register it */
7444  #if 0
7445                 log_error_write(srv, __FILE__, __LINE__, "sd",
7446                                 "appected()", cnt);
7447  #endif
7448                 srv->con_opened++;
7449 -               
7450 +
7451                 con = connections_get_new_connection(srv);
7452 -               
7453 -               con->fd = cnt;
7454 -               con->fde_ndx = -1;
7455 -#if 0          
7456 +               con->sock->fd = cnt;
7457 +               con->sock->fde_ndx = -1;
7458 +#if 0
7459                 gettimeofday(&(con->start_tv), NULL);
7460 -#endif         
7461 -               fdevent_register(srv->ev, con->fd, connection_handle_fdevent, con);
7462 -               
7463 +#endif
7464 +               fdevent_register(srv->ev, con->sock, connection_handle_fdevent, con);
7465 +
7466                 connection_set_state(srv, con, CON_STATE_REQUEST_START);
7467 -               
7468 +
7469                 con->connection_start = srv->cur_ts;
7470                 con->dst_addr = cnt_addr;
7471                 buffer_copy_string(con->dst_addr_buf, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
7472                 con->srv_socket = srv_socket;
7473 -               
7474 -               if (-1 == (fdevent_fcntl_set(srv->ev, con->fd))) {
7475 +
7476 +               if (-1 == (fdevent_fcntl_set(srv->ev, con->sock))) {
7477                         log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
7478 +                       connection_close(srv, con);
7479                         return NULL;
7480                 }
7481  #ifdef USE_OPENSSL
7482                 /* connect FD to SSL */
7483                 if (srv_socket->is_ssl) {
7484 -                       if (NULL == (con->ssl = SSL_new(srv_socket->ssl_ctx))) {
7485 -                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
7486 +                       if (NULL == (con->sock->ssl = SSL_new(srv_socket->ssl_ctx))) {
7487 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7488                                                 ERR_error_string(ERR_get_error(), NULL));
7489 -                               
7490 +                               connection_close(srv, con);
7491                                 return NULL;
7492                         }
7493 -                       
7494 -                       SSL_set_accept_state(con->ssl);
7495 +
7496 +                       SSL_set_accept_state(con->sock->ssl);
7497                         con->conf.is_ssl=1;
7498 -                       
7499 -                       if (1 != (SSL_set_fd(con->ssl, cnt))) {
7500 -                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
7501 +
7502 +                       if (1 != (SSL_set_fd(con->sock->ssl, cnt))) {
7503 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7504                                                 ERR_error_string(ERR_get_error(), NULL));
7505 +                               connection_close(srv, con);
7506                                 return NULL;
7507                         }
7508                 }
7509 @@ -1300,102 +1188,102 @@
7510  #ifdef USE_OPENSSL
7511         server_socket *srv_sock = con->srv_socket;
7512  #endif
7513 -       
7514 +
7515         if (srv->srvconf.log_state_handling) {
7516 -               log_error_write(srv, __FILE__, __LINE__, "sds", 
7517 -                               "state at start", 
7518 -                               con->fd,
7519 +               log_error_write(srv, __FILE__, __LINE__, "sds",
7520 +                               "state at start",
7521 +                               con->sock->fd,
7522                                 connection_get_state(con->state));
7523         }
7524  
7525         while (done == 0) {
7526                 size_t ostate = con->state;
7527                 int b;
7528 -               
7529 +
7530                 switch (con->state) {
7531                 case CON_STATE_REQUEST_START: /* transient */
7532                         if (srv->srvconf.log_state_handling) {
7533 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7534 -                                               "state for fd", con->fd, connection_get_state(con->state));
7535 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7536 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7537                         }
7538 -                       
7539 +
7540                         con->request_start = srv->cur_ts;
7541                         con->read_idle_ts = srv->cur_ts;
7542 -                       
7543 +
7544                         con->request_count++;
7545                         con->loops_per_request = 0;
7546 -                       
7547 +
7548                         connection_set_state(srv, con, CON_STATE_READ);
7549 -                       
7550 +
7551                         break;
7552                 case CON_STATE_REQUEST_END: /* transient */
7553                         if (srv->srvconf.log_state_handling) {
7554 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7555 -                                               "state for fd", con->fd, connection_get_state(con->state));
7556 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7557 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7558                         }
7559 -                       
7560 +
7561                         if (http_request_parse(srv, con)) {
7562                                 /* we have to read some data from the POST request */
7563 -                               
7564 +
7565                                 connection_set_state(srv, con, CON_STATE_READ_POST);
7566  
7567                                 break;
7568                         }
7569 -                       
7570 +
7571                         connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7572 -                       
7573 +
7574                         break;
7575                 case CON_STATE_HANDLE_REQUEST:
7576 -                       /* 
7577 +                       /*
7578                          * the request is parsed
7579 -                        * 
7580 +                        *
7581                          * decided what to do with the request
7582 -                        * - 
7583 -                        * 
7584 -                        * 
7585 +                        * -
7586 +                        *
7587 +                        *
7588                          */
7589 -                       
7590 +
7591                         if (srv->srvconf.log_state_handling) {
7592 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7593 -                                               "state for fd", con->fd, connection_get_state(con->state));
7594 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7595 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7596                         }
7597 -                       
7598 +
7599                         switch (r = http_response_prepare(srv, con)) {
7600                         case HANDLER_FINISHED:
7601                                 if (con->http_status == 404 ||
7602                                     con->http_status == 403) {
7603                                         /* 404 error-handler */
7604 -                                       
7605 -                                       if (con->in_error_handler == 0 && 
7606 +
7607 +                                       if (con->in_error_handler == 0 &&
7608                                             (!buffer_is_empty(con->conf.error_handler) ||
7609                                              !buffer_is_empty(con->error_handler))) {
7610                                                 /* call error-handler */
7611 -                                               
7612 +
7613                                                 con->error_handler_saved_status = con->http_status;
7614                                                 con->http_status = 0;
7615 -                                               
7616 +
7617                                                 if (buffer_is_empty(con->error_handler)) {
7618                                                         buffer_copy_string_buffer(con->request.uri, con->conf.error_handler);
7619                                                 } else {
7620                                                         buffer_copy_string_buffer(con->request.uri, con->error_handler);
7621                                                 }
7622                                                 buffer_reset(con->physical.path);
7623 -                                               
7624 +
7625                                                 con->in_error_handler = 1;
7626 -                                               
7627 +
7628                                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7629 -                                               
7630 +
7631                                                 done = -1;
7632                                                 break;
7633                                         } else if (con->in_error_handler) {
7634                                                 /* error-handler is a 404 */
7635 -                                               
7636 +
7637                                                 /* continue as normal, status is the same */
7638 -                                               log_error_write(srv, __FILE__, __LINE__, "sb", 
7639 +                                               log_error_write(srv, __FILE__, __LINE__, "sb",
7640                                                                 "Warning: Either the error-handler returned status 404 or the error-handler itself was not found:", con->request.uri);
7641 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
7642 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
7643                                                                 "returning the original status", con->error_handler_saved_status);
7644 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
7645 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
7646                                                                 "If this is a rails app: check your production.log");
7647                                                 con->http_status = con->error_handler_saved_status;
7648                                         }
7649 @@ -1403,73 +1291,73 @@
7650                                         /* error-handler is back and has generated content */
7651                                         /* if Status: was set, take it otherwise use 200 */
7652                                 }
7653 -                               
7654 +
7655                                 if (con->http_status == 0) con->http_status = 200;
7656 -                               
7657 +
7658                                 /* we have something to send, go on */
7659                                 connection_set_state(srv, con, CON_STATE_RESPONSE_START);
7660                                 break;
7661                         case HANDLER_WAIT_FOR_FD:
7662                                 srv->want_fds++;
7663 -                               
7664 +
7665                                 fdwaitqueue_append(srv, con);
7666 -                               
7667 +
7668                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7669 -                               
7670 +
7671                                 break;
7672                         case HANDLER_COMEBACK:
7673                                 done = -1;
7674                         case HANDLER_WAIT_FOR_EVENT:
7675                                 /* come back here */
7676                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7677 -                               
7678 +
7679                                 break;
7680                         case HANDLER_ERROR:
7681                                 /* something went wrong */
7682                                 connection_set_state(srv, con, CON_STATE_ERROR);
7683                                 break;
7684                         default:
7685 -                               log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->fd, r);
7686 +                               log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->sock->fd, r);
7687                                 break;
7688                         }
7689 -                       
7690 +
7691                         break;
7692                 case CON_STATE_RESPONSE_START:
7693 -                       /* 
7694 +                       /*
7695                          * the decision is done
7696                          * - create the HTTP-Response-Header
7697 -                        * 
7698 +                        *
7699                          */
7700 -                       
7701 +
7702                         if (srv->srvconf.log_state_handling) {
7703 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7704 -                                               "state for fd", con->fd, connection_get_state(con->state));
7705 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7706 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7707                         }
7708 -                       
7709 +
7710                         if (-1 == connection_handle_write_prepare(srv, con)) {
7711                                 connection_set_state(srv, con, CON_STATE_ERROR);
7712 -                               
7713 +
7714                                 break;
7715                         }
7716 -                       
7717 +
7718                         connection_set_state(srv, con, CON_STATE_WRITE);
7719                         break;
7720                 case CON_STATE_RESPONSE_END: /* transient */
7721                         /* log the request */
7722 -                       
7723 +
7724                         if (srv->srvconf.log_state_handling) {
7725 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7726 -                                               "state for fd", con->fd, connection_get_state(con->state));
7727 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7728 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7729                         }
7730 -                       
7731 +
7732                         plugins_call_handle_request_done(srv, con);
7733 -                       
7734 +
7735                         srv->con_written++;
7736 -                       
7737 +
7738                         if (con->keep_alive) {
7739                                 connection_set_state(srv, con, CON_STATE_REQUEST_START);
7740 -                               
7741 -#if 0                                  
7742 +
7743 +#if 0
7744                                 con->request_start = srv->cur_ts;
7745                                 con->read_idle_ts = srv->cur_ts;
7746  #endif
7747 @@ -1482,103 +1370,103 @@
7748                                         log_error_write(srv, __FILE__, __LINE__, "sd", "unhandling return value", r);
7749                                         break;
7750                                 }
7751 -                               
7752 +
7753  #ifdef USE_OPENSSL
7754                                 if (srv_sock->is_ssl) {
7755 -                                       switch (SSL_shutdown(con->ssl)) {
7756 +                                       switch (SSL_shutdown(con->sock->ssl)) {
7757                                         case 1:
7758                                                 /* done */
7759                                                 break;
7760                                         case 0:
7761 -                                               /* wait for fd-event 
7762 -                                                * 
7763 +                                               /* wait for fd-event
7764 +                                                *
7765                                                  * FIXME: wait for fdevent and call SSL_shutdown again
7766 -                                                * 
7767 +                                                *
7768                                                  */
7769 -                                               
7770 +
7771                                                 break;
7772                                         default:
7773 -                                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
7774 +                                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7775                                                                 ERR_error_string(ERR_get_error(), NULL));
7776                                         }
7777                                 }
7778  #endif
7779                                 connection_close(srv, con);
7780 -                               
7781 +
7782                                 srv->con_closed++;
7783                         }
7784 -                       
7785 +
7786                         connection_reset(srv, con);
7787 -                       
7788 +
7789                         break;
7790                 case CON_STATE_CONNECT:
7791                         if (srv->srvconf.log_state_handling) {
7792 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7793 -                                               "state for fd", con->fd, connection_get_state(con->state));
7794 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7795 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7796                         }
7797 -                       
7798 +
7799                         chunkqueue_reset(con->read_queue);
7800 -                       
7801 +
7802                         con->request_count = 0;
7803 -                       
7804 +
7805                         break;
7806                 case CON_STATE_CLOSE:
7807                         if (srv->srvconf.log_state_handling) {
7808 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7809 -                                               "state for fd", con->fd, connection_get_state(con->state));
7810 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7811 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7812                         }
7813 -                       
7814 +
7815                         if (con->keep_alive) {
7816 -                               if (ioctl(con->fd, FIONREAD, &b)) {
7817 +                               if (ioctl(con->sock->fd, FIONREAD, &b)) {
7818                                         log_error_write(srv, __FILE__, __LINE__, "ss",
7819                                                         "ioctl() failed", strerror(errno));
7820                                 }
7821                                 if (b > 0) {
7822                                         char buf[1024];
7823                                         log_error_write(srv, __FILE__, __LINE__, "sdd",
7824 -                                                       "CLOSE-read()", con->fd, b);
7825 -                                       
7826 +                                                       "CLOSE-read()", con->sock->fd, b);
7827 +
7828                                         /* */
7829 -                                       read(con->fd, buf, sizeof(buf));
7830 +                                       read(con->sock->fd, buf, sizeof(buf));
7831                                 } else {
7832                                         /* nothing to read */
7833 -                                       
7834 +
7835                                         con->close_timeout_ts = 0;
7836                                 }
7837                         } else {
7838                                 con->close_timeout_ts = 0;
7839                         }
7840 -                       
7841 +
7842                         if (srv->cur_ts - con->close_timeout_ts > 1) {
7843                                 connection_close(srv, con);
7844 -                               
7845 +
7846                                 if (srv->srvconf.log_state_handling) {
7847 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
7848 -                                                       "connection closed for fd", con->fd);
7849 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
7850 +                                                       "connection closed for fd", con->sock->fd);
7851                                 }
7852                         }
7853 -                       
7854 +
7855                         break;
7856                 case CON_STATE_READ_POST:
7857                 case CON_STATE_READ:
7858                         if (srv->srvconf.log_state_handling) {
7859 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7860 -                                               "state for fd", con->fd, connection_get_state(con->state));
7861 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7862 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7863                         }
7864 -                       
7865 +
7866                         connection_handle_read_state(srv, con);
7867                         break;
7868                 case CON_STATE_WRITE:
7869                         if (srv->srvconf.log_state_handling) {
7870 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
7871 -                                               "state for fd", con->fd, connection_get_state(con->state));
7872 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
7873 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
7874                         }
7875 -                       
7876 +
7877                         /* only try to write if we have something in the queue */
7878                         if (!chunkqueue_is_empty(con->write_queue)) {
7879  #if 0
7880                                 log_error_write(srv, __FILE__, __LINE__, "dsd",
7881 -                                               con->fd,
7882 +                                               con->sock->fd,
7883                                                 "packets to write:",
7884                                                 con->write_queue->used);
7885  #endif
7886 @@ -1586,17 +1474,17 @@
7887                         if (!chunkqueue_is_empty(con->write_queue) && con->is_writable) {
7888                                 if (-1 == connection_handle_write(srv, con)) {
7889                                         log_error_write(srv, __FILE__, __LINE__, "ds",
7890 -                                                       con->fd,
7891 +                                                       con->sock->fd,
7892                                                         "handle write failed.");
7893                                         connection_set_state(srv, con, CON_STATE_ERROR);
7894                                 } else if (con->state == CON_STATE_WRITE) {
7895                                         con->write_request_ts = srv->cur_ts;
7896                                 }
7897                         }
7898 -                       
7899 +
7900                         break;
7901                 case CON_STATE_ERROR: /* transient */
7902 -                       
7903 +
7904                         /* even if the connection was drop we still have to write it to the access log */
7905                         if (con->http_status) {
7906                                 plugins_call_handle_request_done(srv, con);
7907 @@ -1604,28 +1492,28 @@
7908  #ifdef USE_OPENSSL
7909                         if (srv_sock->is_ssl) {
7910                                 int ret;
7911 -                               switch ((ret = SSL_shutdown(con->ssl))) {
7912 +                               switch ((ret = SSL_shutdown(con->sock->ssl))) {
7913                                 case 1:
7914                                         /* ok */
7915                                         break;
7916                                 case 0:
7917 -                                       SSL_shutdown(con->ssl);
7918 +                                       SSL_shutdown(con->sock->ssl);
7919                                         break;
7920                                 default:
7921 -                                       log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:", 
7922 -                                                       SSL_get_error(con->ssl, ret), 
7923 +                                       log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
7924 +                                                       SSL_get_error(con->sock->ssl, ret),
7925                                                         ERR_error_string(ERR_get_error(), NULL));
7926                                         return -1;
7927                                 }
7928                         }
7929  #endif
7930 -                       
7931 +
7932                         switch(con->mode) {
7933                         case DIRECT:
7934  #if 0
7935 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
7936 -                                               "emergency exit: direct", 
7937 -                                               con->fd);
7938 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
7939 +                                               "emergency exit: direct",
7940 +                                               con->sock->fd);
7941  #endif
7942                                 break;
7943                         default:
7944 @@ -1639,35 +1527,35 @@
7945                                 }
7946                                 break;
7947                         }
7948 -                       
7949 +
7950                         connection_reset(srv, con);
7951 -                       
7952 +
7953                         /* close the connection */
7954                         if ((con->keep_alive == 1) &&
7955 -                           (0 == shutdown(con->fd, SHUT_WR))) {
7956 +                           (0 == shutdown(con->sock->fd, SHUT_WR))) {
7957                                 con->close_timeout_ts = srv->cur_ts;
7958                                 connection_set_state(srv, con, CON_STATE_CLOSE);
7959 -                               
7960 +
7961                                 if (srv->srvconf.log_state_handling) {
7962 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
7963 -                                                       "shutdown for fd", con->fd);
7964 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
7965 +                                                       "shutdown for fd", con->sock->fd);
7966                                 }
7967                         } else {
7968                                 connection_close(srv, con);
7969                         }
7970 -                       
7971 +
7972                         con->keep_alive = 0;
7973 -                       
7974 +
7975                         srv->con_closed++;
7976 -                       
7977 +
7978                         break;
7979                 default:
7980 -                       log_error_write(srv, __FILE__, __LINE__, "sdd", 
7981 -                                       "unknown state:", con->fd, con->state);
7982 -                       
7983 +                       log_error_write(srv, __FILE__, __LINE__, "sdd",
7984 +                                       "unknown state:", con->sock->fd, con->state);
7985 +
7986                         break;
7987                 }
7988 -               
7989 +
7990                 if (done == -1) {
7991                         done = 0;
7992                 } else if (ostate == con->state) {
7993 @@ -1676,33 +1564,33 @@
7994         }
7995  
7996         if (srv->srvconf.log_state_handling) {
7997 -               log_error_write(srv, __FILE__, __LINE__, "sds", 
7998 -                               "state at exit:", 
7999 -                               con->fd,
8000 +               log_error_write(srv, __FILE__, __LINE__, "sds",
8001 +                               "state at exit:",
8002 +                               con->sock->fd,
8003                                 connection_get_state(con->state));
8004         }
8005 -       
8006 +
8007         switch(con->state) {
8008         case CON_STATE_READ_POST:
8009         case CON_STATE_READ:
8010         case CON_STATE_CLOSE:
8011 -               fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_IN);
8012 +               fdevent_event_add(srv->ev, con->sock, FDEVENT_IN);
8013                 break;
8014         case CON_STATE_WRITE:
8015 -               /* request write-fdevent only if we really need it 
8016 +               /* request write-fdevent only if we really need it
8017                  * - if we have data to write
8018 -                * - if the socket is not writable yet 
8019 +                * - if the socket is not writable yet
8020                  */
8021 -               if (!chunkqueue_is_empty(con->write_queue) && 
8022 +               if (!chunkqueue_is_empty(con->write_queue) &&
8023                     (con->is_writable == 0) &&
8024                     (con->traffic_limit_reached == 0)) {
8025 -                       fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_OUT);
8026 +                       fdevent_event_add(srv->ev, con->sock, FDEVENT_OUT);
8027                 } else {
8028 -                       fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
8029 +                       fdevent_event_del(srv->ev, con->sock);
8030                 }
8031                 break;
8032         default:
8033 -               fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
8034 +               fdevent_event_del(srv->ev, con->sock);
8035                 break;
8036         }
8037  
8038 --- ../lighttpd-1.4.11/src/crc32.h      2005-09-30 20:18:59.000000000 +0300
8039 +++ lighttpd-1.4.12/src/crc32.h 2006-07-16 00:26:04.000000000 +0300
8040 @@ -6,6 +6,7 @@
8041  #endif
8042  
8043  #include <sys/types.h>
8044 +#include <stdlib.h>
8045  
8046  #if defined HAVE_STDINT_H
8047  #include <stdint.h>
8048 @@ -13,6 +14,10 @@
8049  #include <inttypes.h>
8050  #endif
8051  
8052 +#ifdef _WIN32
8053 +#define uint32_t unsigned __int32
8054 +#endif
8055 +
8056  uint32_t generate_crc32c(char *string, size_t length);
8057  
8058  #endif
8059 --- ../lighttpd-1.4.11/src/data_array.c 2005-08-23 17:36:12.000000000 +0300
8060 +++ lighttpd-1.4.12/src/data_array.c    2006-07-16 00:26:04.000000000 +0300
8061 @@ -17,16 +17,16 @@
8062  
8063  static void data_array_free(data_unset *d) {
8064         data_array *ds = (data_array *)d;
8065 -       
8066 +
8067         buffer_free(ds->key);
8068         array_free(ds->value);
8069 -       
8070 +
8071         free(d);
8072  }
8073  
8074  static void data_array_reset(data_unset *d) {
8075         data_array *ds = (data_array *)d;
8076 -       
8077 +
8078         /* reused array elements */
8079         buffer_reset(ds->key);
8080         array_reset(ds->value);
8081 @@ -36,7 +36,7 @@
8082         UNUSED(dst);
8083  
8084         src->free(src);
8085 -       
8086 +
8087         return 0;
8088  }
8089  
8090 @@ -48,18 +48,18 @@
8091  
8092  data_array *data_array_init(void) {
8093         data_array *ds;
8094 -       
8095 +
8096         ds = calloc(1, sizeof(*ds));
8097 -       
8098 +
8099         ds->key = buffer_init();
8100         ds->value = array_init();
8101 -       
8102 +
8103         ds->copy = data_array_copy;
8104         ds->free = data_array_free;
8105         ds->reset = data_array_reset;
8106         ds->insert_dup = data_array_insert_dup;
8107         ds->print = data_array_print;
8108         ds->type = TYPE_ARRAY;
8109 -       
8110 +
8111         return ds;
8112  }
8113 --- ../lighttpd-1.4.11/src/data_config.c        2005-08-17 12:53:19.000000000 +0300
8114 +++ lighttpd-1.4.12/src/data_config.c   2006-07-16 00:26:03.000000000 +0300
8115 @@ -17,26 +17,26 @@
8116  
8117  static void data_config_free(data_unset *d) {
8118         data_config *ds = (data_config *)d;
8119 -       
8120 +
8121         buffer_free(ds->key);
8122         buffer_free(ds->op);
8123         buffer_free(ds->comp_key);
8124 -       
8125 +
8126         array_free(ds->value);
8127         array_free(ds->childs);
8128 -       
8129 +
8130         if (ds->string) buffer_free(ds->string);
8131  #ifdef HAVE_PCRE_H
8132         if (ds->regex) pcre_free(ds->regex);
8133         if (ds->regex_study) pcre_free(ds->regex_study);
8134  #endif
8135 -       
8136 +
8137         free(d);
8138  }
8139  
8140  static void data_config_reset(data_unset *d) {
8141         data_config *ds = (data_config *)d;
8142 -       
8143 +
8144         /* reused array elements */
8145         buffer_reset(ds->key);
8146         buffer_reset(ds->comp_key);
8147 @@ -45,9 +45,9 @@
8148  
8149  static int data_config_insert_dup(data_unset *dst, data_unset *src) {
8150         UNUSED(dst);
8151 -       
8152 +
8153         src->free(src);
8154 -       
8155 +
8156         return 0;
8157  }
8158  
8159 @@ -56,7 +56,7 @@
8160         array *a = (array *)ds->value;
8161         size_t i;
8162         size_t maxlen;
8163 -       
8164 +
8165         if (0 == ds->context_ndx) {
8166                 fprintf(stderr, "config {\n");
8167         }
8168 @@ -117,22 +117,22 @@
8169  
8170  data_config *data_config_init(void) {
8171         data_config *ds;
8172 -       
8173 +
8174         ds = calloc(1, sizeof(*ds));
8175 -       
8176 +
8177         ds->key = buffer_init();
8178         ds->op = buffer_init();
8179         ds->comp_key = buffer_init();
8180         ds->value = array_init();
8181         ds->childs = array_init();
8182         ds->childs->is_weakref = 1;
8183 -       
8184 +
8185         ds->copy = data_config_copy;
8186         ds->free = data_config_free;
8187         ds->reset = data_config_reset;
8188         ds->insert_dup = data_config_insert_dup;
8189         ds->print = data_config_print;
8190         ds->type = TYPE_CONFIG;
8191 -       
8192 +
8193         return ds;
8194  }
8195 --- ../lighttpd-1.4.11/src/data_count.c 2005-08-23 17:36:12.000000000 +0300
8196 +++ lighttpd-1.4.12/src/data_count.c    2006-07-16 00:26:03.000000000 +0300
8197 @@ -16,53 +16,53 @@
8198  
8199  static void data_count_free(data_unset *d) {
8200         data_count *ds = (data_count *)d;
8201 -       
8202 +
8203         buffer_free(ds->key);
8204 -       
8205 +
8206         free(d);
8207  }
8208  
8209  static void data_count_reset(data_unset *d) {
8210         data_count *ds = (data_count *)d;
8211 -       
8212 +
8213         buffer_reset(ds->key);
8214 -       
8215 +
8216         ds->count = 0;
8217  }
8218  
8219  static int data_count_insert_dup(data_unset *dst, data_unset *src) {
8220         data_count *ds_dst = (data_count *)dst;
8221         data_count *ds_src = (data_count *)src;
8222 -       
8223 +
8224         ds_dst->count += ds_src->count;
8225 -       
8226 +
8227         src->free(src);
8228 -       
8229 +
8230         return 0;
8231  }
8232  
8233  static void data_count_print(const data_unset *d, int depth) {
8234         data_count *ds = (data_count *)d;
8235         UNUSED(depth);
8236 -       
8237 +
8238         fprintf(stderr, "count(%d)", ds->count);
8239  }
8240  
8241  
8242  data_count *data_count_init(void) {
8243         data_count *ds;
8244 -       
8245 +
8246         ds = calloc(1, sizeof(*ds));
8247 -       
8248 +
8249         ds->key = buffer_init();
8250         ds->count = 1;
8251 -       
8252 +
8253         ds->copy = data_count_copy;
8254         ds->free = data_count_free;
8255         ds->reset = data_count_reset;
8256         ds->insert_dup = data_count_insert_dup;
8257         ds->print = data_count_print;
8258         ds->type = TYPE_COUNT;
8259 -       
8260 +
8261         return ds;
8262  }
8263 --- ../lighttpd-1.4.11/src/data_fastcgi.c       2005-08-23 17:36:12.000000000 +0300
8264 +++ lighttpd-1.4.12/src/data_fastcgi.c  2006-07-16 00:26:04.000000000 +0300
8265 @@ -17,53 +17,53 @@
8266  
8267  static void data_fastcgi_free(data_unset *d) {
8268         data_fastcgi *ds = (data_fastcgi *)d;
8269 -       
8270 +
8271         buffer_free(ds->key);
8272         buffer_free(ds->host);
8273 -       
8274 +
8275         free(d);
8276  }
8277  
8278  static void data_fastcgi_reset(data_unset *d) {
8279         data_fastcgi *ds = (data_fastcgi *)d;
8280 -       
8281 +
8282         buffer_reset(ds->key);
8283         buffer_reset(ds->host);
8284 -       
8285 +
8286  }
8287  
8288  static int data_fastcgi_insert_dup(data_unset *dst, data_unset *src) {
8289         UNUSED(dst);
8290  
8291         src->free(src);
8292 -       
8293 +
8294         return 0;
8295  }
8296  
8297  static void data_fastcgi_print(const data_unset *d, int depth) {
8298         data_fastcgi *ds = (data_fastcgi *)d;
8299         UNUSED(depth);
8300 -       
8301 +
8302         fprintf(stderr, "fastcgi(%s)", ds->host->ptr);
8303  }
8304  
8305  
8306  data_fastcgi *data_fastcgi_init(void) {
8307         data_fastcgi *ds;
8308 -       
8309 +
8310         ds = calloc(1, sizeof(*ds));
8311 -       
8312 +
8313         ds->key = buffer_init();
8314         ds->host = buffer_init();
8315         ds->port = 0;
8316         ds->is_disabled = 0;
8317 -       
8318 +
8319         ds->copy = data_fastcgi_copy;
8320         ds->free = data_fastcgi_free;
8321         ds->reset = data_fastcgi_reset;
8322         ds->insert_dup = data_fastcgi_insert_dup;
8323         ds->print = data_fastcgi_print;
8324         ds->type = TYPE_FASTCGI;
8325 -       
8326 +
8327         return ds;
8328  }
8329 --- ../lighttpd-1.4.11/src/data_integer.c       2005-08-23 17:36:12.000000000 +0300
8330 +++ lighttpd-1.4.12/src/data_integer.c  2006-07-16 00:26:03.000000000 +0300
8331 @@ -16,15 +16,15 @@
8332  
8333  static void data_integer_free(data_unset *d) {
8334         data_integer *ds = (data_integer *)d;
8335 -       
8336 +
8337         buffer_free(ds->key);
8338 -       
8339 +
8340         free(d);
8341  }
8342  
8343  static void data_integer_reset(data_unset *d) {
8344         data_integer *ds = (data_integer *)d;
8345 -       
8346 +
8347         /* reused integer elements */
8348         buffer_reset(ds->key);
8349         ds->value = 0;
8350 @@ -32,9 +32,9 @@
8351  
8352  static int data_integer_insert_dup(data_unset *dst, data_unset *src) {
8353         UNUSED(dst);
8354 -       
8355 +
8356         src->free(src);
8357 -       
8358 +
8359         return 0;
8360  }
8361  
8362 @@ -48,18 +48,18 @@
8363  
8364  data_integer *data_integer_init(void) {
8365         data_integer *ds;
8366 -       
8367 +
8368         ds = calloc(1, sizeof(*ds));
8369 -       
8370 +
8371         ds->key = buffer_init();
8372         ds->value = 0;
8373 -       
8374 +
8375         ds->copy = data_integer_copy;
8376         ds->free = data_integer_free;
8377         ds->reset = data_integer_reset;
8378         ds->insert_dup = data_integer_insert_dup;
8379         ds->print = data_integer_print;
8380         ds->type = TYPE_INTEGER;
8381 -       
8382 +
8383         return ds;
8384  }
8385 --- ../lighttpd-1.4.11/src/data_string.c        2005-08-23 17:36:12.000000000 +0300
8386 +++ lighttpd-1.4.12/src/data_string.c   2006-07-16 00:26:04.000000000 +0300
8387 @@ -17,16 +17,16 @@
8388  
8389  static void data_string_free(data_unset *d) {
8390         data_string *ds = (data_string *)d;
8391 -       
8392 +
8393         buffer_free(ds->key);
8394         buffer_free(ds->value);
8395 -       
8396 +
8397         free(d);
8398  }
8399  
8400  static void data_string_reset(data_unset *d) {
8401         data_string *ds = (data_string *)d;
8402 -       
8403 +
8404         /* reused array elements */
8405         buffer_reset(ds->key);
8406         buffer_reset(ds->value);
8407 @@ -35,23 +35,23 @@
8408  static int data_string_insert_dup(data_unset *dst, data_unset *src) {
8409         data_string *ds_dst = (data_string *)dst;
8410         data_string *ds_src = (data_string *)src;
8411 -       
8412 +
8413         if (ds_dst->value->used) {
8414                 buffer_append_string(ds_dst->value, ", ");
8415                 buffer_append_string_buffer(ds_dst->value, ds_src->value);
8416         } else {
8417                 buffer_copy_string_buffer(ds_dst->value, ds_src->value);
8418         }
8419 -       
8420 +
8421         src->free(src);
8422 -       
8423 +
8424         return 0;
8425  }
8426  
8427  static int data_response_insert_dup(data_unset *dst, data_unset *src) {
8428         data_string *ds_dst = (data_string *)dst;
8429         data_string *ds_src = (data_string *)src;
8430 -       
8431 +
8432         if (ds_dst->value->used) {
8433                 buffer_append_string(ds_dst->value, "\r\n");
8434                 buffer_append_string_buffer(ds_dst->value, ds_dst->key);
8435 @@ -60,9 +60,9 @@
8436         } else {
8437                 buffer_copy_string_buffer(ds_dst->value, ds_src->value);
8438         }
8439 -       
8440 +
8441         src->free(src);
8442 -       
8443 +
8444         return 0;
8445  }
8446  
8447 @@ -77,28 +77,28 @@
8448  
8449  data_string *data_string_init(void) {
8450         data_string *ds;
8451 -       
8452 +
8453         ds = calloc(1, sizeof(*ds));
8454         assert(ds);
8455 -       
8456 +
8457         ds->key = buffer_init();
8458         ds->value = buffer_init();
8459 -       
8460 +
8461         ds->copy = data_string_copy;
8462         ds->free = data_string_free;
8463         ds->reset = data_string_reset;
8464         ds->insert_dup = data_string_insert_dup;
8465         ds->print = data_string_print;
8466         ds->type = TYPE_STRING;
8467 -       
8468 +
8469         return ds;
8470  }
8471  
8472  data_string *data_response_init(void) {
8473         data_string *ds;
8474 -       
8475 +
8476         ds = data_string_init();
8477         ds->insert_dup = data_response_insert_dup;
8478 -       
8479 +
8480         return ds;
8481  }
8482 --- ../lighttpd-1.4.11/src/etag.c       2005-08-11 01:26:40.000000000 +0300
8483 +++ lighttpd-1.4.12/src/etag.c  2006-07-18 13:03:40.000000000 +0300
8484 @@ -4,7 +4,7 @@
8485  #include "etag.h"
8486  
8487  int etag_is_equal(buffer *etag, const char *matches) {
8488 -       if (0 == strcmp(etag->ptr, matches)) return 1;
8489 +       if (buffer_is_equal_string(etag, matches, strlen(matches))) return 1;
8490         return 0;
8491  }
8492  
8493 @@ -14,19 +14,19 @@
8494         buffer_append_off_t(etag, st->st_size);
8495         buffer_append_string_len(etag, CONST_STR_LEN("-"));
8496         buffer_append_long(etag, st->st_mtime);
8497 -       
8498 +
8499         return 0;
8500  }
8501  
8502  int etag_mutate(buffer *mut, buffer *etag) {
8503         size_t h, i;
8504 -       
8505 +
8506         for (h=0, i=0; i < etag->used; ++i) h = (h<<5)^(h>>27)^(etag->ptr[i]);
8507 -       
8508 +
8509         buffer_reset(mut);
8510         buffer_copy_string_len(mut, CONST_STR_LEN("\""));
8511         buffer_append_long(mut, h);
8512         buffer_append_string_len(mut, CONST_STR_LEN("\""));
8513 -       
8514 +
8515         return 0;
8516  }
8517 --- ../lighttpd-1.4.11/src/etag.h       2005-08-11 01:26:40.000000000 +0300
8518 +++ lighttpd-1.4.12/src/etag.h  2006-07-16 00:26:03.000000000 +0300
8519 @@ -3,13 +3,12 @@
8520  
8521  #include <sys/types.h>
8522  #include <sys/stat.h>
8523 -#include <unistd.h>
8524  
8525  #include "buffer.h"
8526  
8527  int etag_is_equal(buffer *etag, const char *matches);
8528  int etag_create(buffer *etag, struct stat *st);
8529  int etag_mutate(buffer *mut, buffer *etag);
8530 -       
8531 +
8532  
8533  #endif
8534 --- ../lighttpd-1.4.11/src/fastcgi.h    2005-08-11 01:26:40.000000000 +0300
8535 +++ lighttpd-1.4.12/src/fastcgi.h       2006-07-16 00:26:03.000000000 +0300
8536 @@ -1,4 +1,4 @@
8537 -/* 
8538 +/*
8539   * fastcgi.h --
8540   *
8541   *     Defines for the FastCGI protocol.
8542 @@ -123,7 +123,7 @@
8543  
8544  
8545  typedef struct {
8546 -    unsigned char type;    
8547 +    unsigned char type;
8548      unsigned char reserved[7];
8549  } FCGI_UnknownTypeBody;
8550  
8551 --- ../lighttpd-1.4.11/src/fdevent.c    2005-11-15 10:51:05.000000000 +0200
8552 +++ lighttpd-1.4.12/src/fdevent.c       2006-07-18 13:03:40.000000000 +0300
8553 @@ -2,7 +2,6 @@
8554  
8555  #include "settings.h"
8556  
8557 -#include <unistd.h>
8558  #include <stdlib.h>
8559  #include <string.h>
8560  #include <errno.h>
8561 @@ -11,60 +10,116 @@
8562  
8563  #include "fdevent.h"
8564  #include "buffer.h"
8565 +#include "log.h"
8566 +
8567 +#include "sys-socket.h"
8568 +
8569 +fdevent_revent *fdevent_revent_init(void) {
8570 +       STRUCT_INIT(fdevent_revent, revent);
8571 +
8572 +       return revent;
8573 +}
8574 +
8575 +void fdevent_revent_free(fdevent_revent *revent) {
8576 +       if (!revent) return;
8577 +
8578 +       free(revent);
8579 +}
8580 +
8581 +fdevent_revents *fdevent_revents_init(void) {
8582 +       STRUCT_INIT(fdevent_revents, revents);
8583 +
8584 +       return revents;
8585 +}
8586 +
8587 +void fdevent_revents_reset(fdevent_revents *revents) {
8588 +       if (!revents) return;
8589 +
8590 +       revents->used = 0;
8591 +}
8592 +
8593 +void fdevent_revents_add(fdevent_revents *revents, int fd, int events) {
8594 +       fdevent_revent *revent;
8595 +
8596 +       if (revents->used == revents->size) {
8597 +               /* resize the events-array */
8598 +               revents->ptr = realloc(revents->ptr, (revents->size + 1) * sizeof(*(revents->ptr)));
8599 +               revents->ptr[revents->size++] = fdevent_revent_init();
8600 +       }
8601 +
8602 +       revent = revents->ptr[revents->used++];
8603 +       revent->fd = fd;
8604 +       revent->revents = events;
8605 +}
8606 +
8607 +void fdevent_revents_free(fdevent_revents *revents) {
8608 +       size_t i;
8609 +       
8610 +       if (!revents) return;
8611 +
8612 +       if (revents->size) {
8613 +               for (i = 0; i < revents->size; i++) {
8614 +                       fdevent_revent_free(revents->ptr[i]);
8615 +               }
8616 +
8617 +               free(revents->ptr);
8618 +       }
8619 +       free(revents);
8620 +}
8621  
8622  fdevents *fdevent_init(size_t maxfds, fdevent_handler_t type) {
8623         fdevents *ev;
8624 -       
8625 +
8626         ev = calloc(1, sizeof(*ev));
8627         ev->fdarray = calloc(maxfds, sizeof(*ev->fdarray));
8628         ev->maxfds = maxfds;
8629 -       
8630 +
8631         switch(type) {
8632         case FDEVENT_HANDLER_POLL:
8633                 if (0 != fdevent_poll_init(ev)) {
8634 -                       fprintf(stderr, "%s.%d: event-handler poll failed\n", 
8635 +                       fprintf(stderr, "%s.%d: event-handler poll failed\n",
8636                                 __FILE__, __LINE__);
8637 -                       
8638 +
8639                         return NULL;
8640                 }
8641                 break;
8642         case FDEVENT_HANDLER_SELECT:
8643                 if (0 != fdevent_select_init(ev)) {
8644 -                       fprintf(stderr, "%s.%d: event-handler select failed\n", 
8645 +                       fprintf(stderr, "%s.%d: event-handler select failed\n",
8646                                 __FILE__, __LINE__);
8647                         return NULL;
8648                 }
8649                 break;
8650         case FDEVENT_HANDLER_LINUX_RTSIG:
8651                 if (0 != fdevent_linux_rtsig_init(ev)) {
8652 -                       fprintf(stderr, "%s.%d: event-handler linux-rtsig failed, try to set server.event-handler = \"poll\" or \"select\"\n", 
8653 +                       fprintf(stderr, "%s.%d: event-handler linux-rtsig failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8654                                 __FILE__, __LINE__);
8655                         return NULL;
8656                 }
8657                 break;
8658         case FDEVENT_HANDLER_LINUX_SYSEPOLL:
8659                 if (0 != fdevent_linux_sysepoll_init(ev)) {
8660 -                       fprintf(stderr, "%s.%d: event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"\n", 
8661 +                       fprintf(stderr, "%s.%d: event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8662                                 __FILE__, __LINE__);
8663                         return NULL;
8664                 }
8665                 break;
8666         case FDEVENT_HANDLER_SOLARIS_DEVPOLL:
8667                 if (0 != fdevent_solaris_devpoll_init(ev)) {
8668 -                       fprintf(stderr, "%s.%d: event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"\n", 
8669 +                       fprintf(stderr, "%s.%d: event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8670                                 __FILE__, __LINE__);
8671                         return NULL;
8672                 }
8673                 break;
8674         case FDEVENT_HANDLER_FREEBSD_KQUEUE:
8675                 if (0 != fdevent_freebsd_kqueue_init(ev)) {
8676 -                       fprintf(stderr, "%s.%d: event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"\n", 
8677 +                       fprintf(stderr, "%s.%d: event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8678                                 __FILE__, __LINE__);
8679                         return NULL;
8680                 }
8681                 break;
8682         default:
8683 -               fprintf(stderr, "%s.%d: event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"\n", 
8684 +               fprintf(stderr, "%s.%d: event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"\n",
8685                         __FILE__, __LINE__);
8686                 return NULL;
8687         }
8688 @@ -75,28 +130,29 @@
8689  void fdevent_free(fdevents *ev) {
8690         size_t i;
8691         if (!ev) return;
8692 -       
8693 +
8694         if (ev->free) ev->free(ev);
8695 -       
8696 +
8697         for (i = 0; i < ev->maxfds; i++) {
8698                 if (ev->fdarray[i]) free(ev->fdarray[i]);
8699         }
8700 -       
8701 +
8702         free(ev->fdarray);
8703         free(ev);
8704  }
8705  
8706  int fdevent_reset(fdevents *ev) {
8707         if (ev->reset) return ev->reset(ev);
8708 -       
8709 +
8710         return 0;
8711  }
8712  
8713  fdnode *fdnode_init() {
8714         fdnode *fdn;
8715 -       
8716 +
8717         fdn = calloc(1, sizeof(*fdn));
8718         fdn->fd = -1;
8719 +
8720         return fdn;
8721  }
8722  
8723 @@ -104,48 +160,40 @@
8724         free(fdn);
8725  }
8726  
8727 -int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx) {
8728 +int fdevent_register(fdevents *ev, iosocket *sock, fdevent_handler handler, void *ctx) {
8729         fdnode *fdn;
8730 -       
8731 +
8732         fdn = fdnode_init();
8733         fdn->handler = handler;
8734 -       fdn->fd      = fd;
8735 +       fdn->fd      = sock->fd;
8736         fdn->ctx     = ctx;
8737 -       
8738 -       ev->fdarray[fd] = fdn;
8739 +
8740 +       ev->fdarray[sock->fd] = fdn;
8741  
8742         return 0;
8743  }
8744  
8745 -int fdevent_unregister(fdevents *ev, int fd) {
8746 +int fdevent_unregister(fdevents *ev, iosocket *sock) {
8747         fdnode *fdn;
8748          if (!ev) return 0;
8749 -       fdn = ev->fdarray[fd];
8750 -       
8751 +       fdn = ev->fdarray[sock->fd];
8752 +
8753         fdnode_free(fdn);
8754 -       
8755 -       ev->fdarray[fd] = NULL;
8756 -       
8757 +
8758 +       ev->fdarray[sock->fd] = NULL;
8759 +
8760         return 0;
8761  }
8762  
8763 -int fdevent_event_del(fdevents *ev, int *fde_ndx, int fd) {
8764 -       int fde = fde_ndx ? *fde_ndx : -1;
8765 -       
8766 -       if (ev->event_del) fde = ev->event_del(ev, fde, fd);
8767 -       
8768 -       if (fde_ndx) *fde_ndx = fde;
8769 -       
8770 +int fdevent_event_del(fdevents *ev, iosocket *sock) {
8771 +       if (ev->event_del) ev->event_del(ev, sock);
8772 +
8773         return 0;
8774  }
8775  
8776 -int fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int events) {
8777 -       int fde = fde_ndx ? *fde_ndx : -1;
8778 -       
8779 -       if (ev->event_add) fde = ev->event_add(ev, fde, fd, events);
8780 -       
8781 -       if (fde_ndx) *fde_ndx = fde;
8782 -       
8783 +int fdevent_event_add(fdevents *ev, iosocket *sock, int events) {
8784 +       if (ev->event_add) ev->event_add(ev, sock, events);
8785 +
8786         return 0;
8787  }
8788  
8789 @@ -154,49 +202,41 @@
8790         return ev->poll(ev, timeout_ms);
8791  }
8792  
8793 -int fdevent_event_get_revent(fdevents *ev, size_t ndx) {
8794 -       if (ev->event_get_revent == NULL) SEGFAULT();
8795 -       
8796 -       return ev->event_get_revent(ev, ndx);
8797 -}
8798 +int fdevent_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
8799 +       size_t i;
8800  
8801 -int fdevent_event_get_fd(fdevents *ev, size_t ndx) {
8802 -       if (ev->event_get_fd == NULL) SEGFAULT();
8803 -       
8804 -       return ev->event_get_fd(ev, ndx);
8805 -}
8806 +       if (ev->get_revents == NULL) SEGFAULT();
8807  
8808 -fdevent_handler fdevent_get_handler(fdevents *ev, int fd) {
8809 -       if (ev->fdarray[fd] == NULL) SEGFAULT();
8810 -       if (ev->fdarray[fd]->fd != fd) SEGFAULT();
8811 -       
8812 -       return ev->fdarray[fd]->handler;
8813 -}
8814 +       fdevent_revents_reset(revents);
8815  
8816 -void * fdevent_get_context(fdevents *ev, int fd) {
8817 -       if (ev->fdarray[fd] == NULL) SEGFAULT();
8818 -       if (ev->fdarray[fd]->fd != fd) SEGFAULT();
8819 -       
8820 -       return ev->fdarray[fd]->ctx;
8821 +       ev->get_revents(ev, event_count, revents);
8822 +
8823 +       /* patch the event handlers */
8824 +       for (i = 0; i < event_count; i++) {
8825 +               fdevent_revent *r = revents->ptr[i];
8826 +
8827 +               r->handler = ev->fdarray[r->fd]->handler;
8828 +               r->context = ev->fdarray[r->fd]->ctx;
8829 +       }
8830 +
8831 +       return 0;
8832  }
8833  
8834 -int fdevent_fcntl_set(fdevents *ev, int fd) {
8835 +int fdevent_fcntl_set(fdevents *ev, iosocket *sock) {
8836 +#ifdef _WIN32
8837 +       int i = 1;
8838 +#endif
8839  #ifdef FD_CLOEXEC
8840         /* close fd on exec (cgi) */
8841 -       fcntl(fd, F_SETFD, FD_CLOEXEC);
8842 +       fcntl(sock->fd, F_SETFD, FD_CLOEXEC);
8843  #endif
8844 -       if ((ev) && (ev->fcntl_set)) return ev->fcntl_set(ev, fd);
8845 -#ifdef O_NONBLOCK      
8846 -       return fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
8847 +       if ((ev) && (ev->fcntl_set)) return ev->fcntl_set(ev, sock->fd);
8848 +#ifdef O_NONBLOCK
8849 +       return fcntl(sock->fd, F_SETFL, O_NONBLOCK | O_RDWR);
8850 +#elif defined _WIN32
8851 +       return ioctlsocket(sock->fd, FIONBIO, &i);
8852  #else
8853         return 0;
8854  #endif
8855  }
8856  
8857 -
8858 -int fdevent_event_next_fdndx(fdevents *ev, int ndx) {
8859 -       if (ev->event_next_fdndx) return ev->event_next_fdndx(ev, ndx);
8860 -       
8861 -       return -1;
8862 -}
8863 -
8864 --- ../lighttpd-1.4.11/src/fdevent.h    2005-09-27 11:26:33.000000000 +0300
8865 +++ lighttpd-1.4.12/src/fdevent.h       2006-07-18 13:03:40.000000000 +0300
8866 @@ -7,6 +7,9 @@
8867  #include "settings.h"
8868  #include "bitset.h"
8869  
8870 +#include "iosocket.h"
8871 +#include "array-static.h"
8872 +
8873  /* select event-system */
8874  
8875  #if defined(HAVE_EPOLL_CTL) && defined(HAVE_SYS_EPOLL_H)
8876 @@ -17,13 +20,13 @@
8877  # include <sys/epoll.h>
8878  #endif
8879  
8880 -/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes 
8881 +/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes
8882   * under /usr/include/sys/ */
8883  #if defined HAVE_POLL && (defined(HAVE_SYS_POLL_H) || defined(HAVE_POLL_H))
8884  # define USE_POLL
8885  # ifdef HAVE_POLL_H
8886  #  include <poll.h>
8887 -# else 
8888 +# else
8889  #  include <sys/poll.h>
8890  # endif
8891  # if defined HAVE_SIGTIMEDWAIT && defined(__linux__)
8892 @@ -31,9 +34,11 @@
8893  #  include <signal.h>
8894  # endif
8895  #endif
8896 -
8897 +#ifdef _WIN32
8898 +# define HAVE_SELECT
8899 +#endif
8900  #if defined HAVE_SELECT
8901 -# ifdef __WIN32
8902 +# ifdef _WIN32
8903  #  include <winsock2.h>
8904  # endif
8905  # define USE_SELECT
8906 @@ -67,14 +72,14 @@
8907  #define FDEVENT_HUP    BV(4)
8908  #define FDEVENT_NVAL   BV(5)
8909  
8910 -typedef enum { FD_EVENT_TYPE_UNSET = -1, 
8911 -               FD_EVENT_TYPE_CONNECTION, 
8912 -               FD_EVENT_TYPE_FCGI_CONNECTION, 
8913 -               FD_EVENT_TYPE_DIRWATCH, 
8914 -               FD_EVENT_TYPE_CGI_CONNECTION 
8915 +typedef enum { FD_EVENT_TYPE_UNSET = -1,
8916 +               FD_EVENT_TYPE_CONNECTION,
8917 +               FD_EVENT_TYPE_FCGI_CONNECTION,
8918 +               FD_EVENT_TYPE_DIRWATCH,
8919 +               FD_EVENT_TYPE_CGI_CONNECTION
8920  } fd_event_t;
8921  
8922 -typedef enum { FDEVENT_HANDLER_UNSET, 
8923 +typedef enum { FDEVENT_HANDLER_UNSET,
8924                 FDEVENT_HANDLER_SELECT,
8925                 FDEVENT_HANDLER_POLL,
8926                 FDEVENT_HANDLER_LINUX_RTSIG,
8927 @@ -86,7 +91,7 @@
8928  
8929  /**
8930   * a mapping from fd to connection structure
8931 - * 
8932 + *
8933   */
8934  typedef struct {
8935         int fd;                  /**< the fd */
8936 @@ -96,43 +101,51 @@
8937         int revents;
8938  } fd_conn;
8939  
8940 +ARRAY_STATIC_DEF(fd_conn_buffer, fd_conn, );
8941 +
8942 +/**
8943 + * revents
8944 + */
8945  typedef struct {
8946 -       fd_conn *ptr;
8947 -       
8948 -       size_t size;
8949 -       size_t used;
8950 -} fd_conn_buffer;
8951 +       int fd;
8952 +       int revents;
8953 +
8954 +       fdevent_handler handler;
8955 +       void *context;
8956 +} fdevent_revent;
8957 +
8958 +ARRAY_STATIC_DEF(fdevent_revents, fdevent_revent, );
8959  
8960  /**
8961   * array of unused fd's
8962 - * 
8963 + *
8964   */
8965  
8966  typedef struct _fdnode {
8967 -       fdevent_handler handler;
8968 -       void *ctx;
8969 -       int fd;
8970 -       
8971 +       fdevent_handler handler; /* who handles the events for this fd */
8972 +       void *ctx;               /* opaque pointer which is passed as 3rd parameter to the handler */
8973 +       int fd;                  /* fd */
8974 +
8975         struct _fdnode *prev, *next;
8976  } fdnode;
8977  
8978  typedef struct {
8979         int *ptr;
8980 -       
8981 +
8982         size_t used;
8983         size_t size;
8984  } buffer_int;
8985  
8986  /**
8987   * fd-event handler for select(), poll() and rt-signals on Linux 2.4
8988 - * 
8989 + *
8990   */
8991  typedef struct fdevents {
8992         fdevent_handler_t type;
8993 -       
8994 -       fdnode **fdarray;
8995 +
8996 +       fdnode **fdarray; /* a list of fdnodes */
8997         size_t maxfds;
8998 -       
8999 +
9000  #ifdef USE_LINUX_SIGIO
9001         int in_sigio;
9002         int signum;
9003 @@ -146,21 +159,21 @@
9004  #endif
9005  #ifdef USE_POLL
9006         struct pollfd *pollfds;
9007 -       
9008 +
9009         size_t size;
9010         size_t used;
9011 -       
9012 +
9013         buffer_int unused;
9014  #endif
9015  #ifdef USE_SELECT
9016         fd_set select_read;
9017         fd_set select_write;
9018         fd_set select_error;
9019 -       
9020 +
9021         fd_set select_set_read;
9022         fd_set select_set_write;
9023         fd_set select_set_error;
9024 -       
9025 +
9026         int select_max_fd;
9027  #endif
9028  #ifdef USE_SOLARIS_DEVPOLL
9029 @@ -177,16 +190,13 @@
9030  #endif
9031         int (*reset)(struct fdevents *ev);
9032         void (*free)(struct fdevents *ev);
9033 -       
9034 -       int (*event_add)(struct fdevents *ev, int fde_ndx, int fd, int events);
9035 -       int (*event_del)(struct fdevents *ev, int fde_ndx, int fd);
9036 -       int (*event_get_revent)(struct fdevents *ev, size_t ndx);
9037 -       int (*event_get_fd)(struct fdevents *ev, size_t ndx);
9038 -       
9039 -       int (*event_next_fdndx)(struct fdevents *ev, int ndx);
9040 -       
9041 +
9042 +       int (*event_add)(struct fdevents *ev, iosocket *sock, int events);
9043 +       int (*event_del)(struct fdevents *ev, iosocket *sock);
9044 +       int (*get_revents)(struct fdevents *ev, size_t event_count, fdevent_revents *revents);
9045 +
9046         int (*poll)(struct fdevents *ev, int timeout_ms);
9047 -       
9048 +
9049         int (*fcntl_set)(struct fdevents *ev, int fd);
9050  } fdevents;
9051  
9052 @@ -194,22 +204,44 @@
9053  int fdevent_reset(fdevents *ev);
9054  void fdevent_free(fdevents *ev);
9055  
9056 -int fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int events);
9057 -int fdevent_event_del(fdevents *ev, int *fde_ndx, int fd);
9058 -int fdevent_event_get_revent(fdevents *ev, size_t ndx);
9059 -int fdevent_event_get_fd(fdevents *ev, size_t ndx);
9060 -fdevent_handler fdevent_get_handler(fdevents *ev, int fd);
9061 -void * fdevent_get_context(fdevents *ev, int fd);
9062 +/**
9063 + * call the plugin for the number of available events
9064 + */
9065 +int fdevent_poll(fdevents *ev, int timeout_ms);
9066 +/**
9067 + * get all available events
9068 + */
9069 +int fdevent_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents);
9070  
9071 -int fdevent_event_next_fdndx(fdevents *ev, int ndx);
9072 +/**
9073 + * add or remove a fd to the handled-pool
9074 + */
9075 +int fdevent_register(fdevents *ev, iosocket *sock, fdevent_handler handler, void *ctx);
9076 +int fdevent_unregister(fdevents *ev, iosocket *sock);
9077  
9078 -int fdevent_poll(fdevents *ev, int timeout_ms);
9079 +/**
9080 + * add a event to a registered fd
9081 + */
9082 +int fdevent_event_add(fdevents *ev, iosocket *sock, int events);
9083 +int fdevent_event_del(fdevents *ev, iosocket *sock);
9084 +
9085 +/**
9086 + * set non-blocking
9087 + */
9088 +int fdevent_fcntl_set(fdevents *ev, iosocket *sock);
9089 +
9090 +fdevent_revents *fdevent_revents_init(void);
9091 +void fdevent_revents_reset(fdevent_revents *revents);
9092 +void fdevent_revents_add(fdevent_revents *revents, int fd, int events);
9093 +void fdevent_revents_free(fdevent_revents *revents);
9094  
9095 -int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx);
9096 -int fdevent_unregister(fdevents *ev, int fd);
9097 +fdevent_revent *fdevent_revent_init(void);
9098 +void fdevent_revent_free(fdevent_revent *revent);
9099  
9100 -int fdevent_fcntl_set(fdevents *ev, int fd);
9101  
9102 +/**
9103 + * plugin init
9104 + */
9105  int fdevent_select_init(fdevents *ev);
9106  int fdevent_poll_init(fdevents *ev);
9107  int fdevent_linux_rtsig_init(fdevents *ev);
9108 --- ../lighttpd-1.4.11/src/fdevent_freebsd_kqueue.c     2005-09-01 10:46:24.000000000 +0300
9109 +++ lighttpd-1.4.12/src/fdevent_freebsd_kqueue.c        2006-07-16 00:26:03.000000000 +0300
9110 @@ -1,6 +1,5 @@
9111  #include <sys/types.h>
9112  
9113 -#include <unistd.h>
9114  #include <stdlib.h>
9115  #include <stdio.h>
9116  #include <string.h>
9117 @@ -48,7 +47,7 @@
9118  
9119                 return -1;
9120         }
9121 -       
9122 +
9123         return -1;
9124  }
9125  
9126 @@ -65,7 +64,7 @@
9127  
9128         ts.tv_sec  = 0;
9129         ts.tv_nsec = 0;
9130 -       
9131 +
9132         ret = kevent(ev->kq_fd,
9133                      &kev, 1,
9134                      NULL, 0,
9135 @@ -77,7 +76,7 @@
9136  
9137                 return -1;
9138         }
9139 -       
9140 +
9141         if (filter == EVFILT_READ) {
9142                 bitset_set_bit(ev->kq_bevents, fd);
9143         } else {
9144 @@ -124,7 +123,7 @@
9145         } else if (e == EVFILT_WRITE) {
9146                 events |= FDEVENT_OUT;
9147         }
9148 -       
9149 +
9150         e = ev->kq_results[ndx].flags;
9151  
9152         if (e & EV_EOF) {
9153 @@ -152,10 +151,10 @@
9154         if (-1 == (ev->kq_fd = kqueue())) {
9155                 fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9156                         __FILE__, __LINE__, strerror(errno));
9157 -               
9158 +
9159                 return -1;
9160         }
9161 -       
9162 +
9163         return 0;
9164  }
9165  
9166 @@ -186,7 +185,7 @@
9167         if (-1 == (ev->kq_fd = kqueue())) {
9168                 fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9169                         __FILE__, __LINE__, strerror(errno));
9170 -               
9171 +
9172                 return -1;
9173         }
9174  
9175 --- ../lighttpd-1.4.11/src/fdevent_linux_rtsig.c        2005-11-21 19:56:11.000000000 +0200
9176 +++ lighttpd-1.4.12/src/fdevent_linux_rtsig.c   2006-07-18 13:03:40.000000000 +0300
9177 @@ -1,6 +1,5 @@
9178  #include <sys/types.h>
9179  
9180 -#include <unistd.h>
9181  #include <stdlib.h>
9182  #include <stdio.h>
9183  #include <string.h>
9184 @@ -14,6 +13,8 @@
9185  #include "fdevent.h"
9186  #include "settings.h"
9187  #include "buffer.h"
9188 +#include "sys-process.h"
9189 +#include "log.h"
9190  
9191  #ifdef USE_LINUX_SIGIO
9192  static void fdevent_linux_rtsig_free(fdevents *ev) {
9193 @@ -24,21 +25,21 @@
9194  }
9195  
9196  
9197 -static int fdevent_linux_rtsig_event_del(fdevents *ev, int fde_ndx, int fd) {
9198 -       if (fde_ndx < 0) return -1;
9199 -       
9200 -       if ((size_t)fde_ndx >= ev->used) {
9201 -               fprintf(stderr, "%s.%d: del! out of range %d %zu\n", __FILE__, __LINE__, fde_ndx, ev->used);
9202 +static int fdevent_linux_rtsig_event_del(fdevents *ev, iosocket *sock) {
9203 +       if (sock->fde_ndx < 0) return -1;
9204 +
9205 +       if ((size_t)sock->fde_ndx >= ev->used) {
9206 +               TRACE("del! out of range %d %zu\n", sock->fde_ndx, ev->used);
9207                 SEGFAULT();
9208         }
9209 -       
9210 -       if (ev->pollfds[fde_ndx].fd == fd) {
9211 -               size_t k = fde_ndx;
9212 -               
9213 +
9214 +       if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9215 +               size_t k = sock->fde_ndx;
9216 +
9217                 ev->pollfds[k].fd = -1;
9218  
9219 -               bitset_clear_bit(ev->sigbset, fd);
9220 -               
9221 +               bitset_clear_bit(ev->sigbset, sock->fd);
9222 +
9223                 if (ev->unused.size == 0) {
9224                         ev->unused.size = 16;
9225                         ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size);
9226 @@ -46,53 +47,54 @@
9227                         ev->unused.size += 16;
9228                         ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
9229                 }
9230 -               
9231 +
9232                 ev->unused.ptr[ev->unused.used++] = k;
9233         } else {
9234 -               fprintf(stderr, "%s.%d: del! %d %d\n", __FILE__, __LINE__, ev->pollfds[fde_ndx].fd, fd);
9235 -               
9236 +               fprintf(stderr, "%s.%d: del! %d %d\n", __FILE__, __LINE__, ev->pollfds[sock->fde_ndx].fd, sock->fd);
9237 +
9238                 SEGFAULT();
9239         }
9240 -       
9241 -       return -1;
9242 +       sock->fde_ndx = -1;
9243 +
9244 +       return 0;
9245  }
9246  
9247  #if 0
9248  static int fdevent_linux_rtsig_event_compress(fdevents *ev) {
9249         size_t j;
9250 -       
9251 +
9252         if (ev->used == 0) return 0;
9253         if (ev->unused.used != 0) return 0;
9254 -       
9255 +
9256         for (j = ev->used - 1; j + 1 > 0; j--) {
9257                 if (ev->pollfds[j].fd == -1) ev->used--;
9258         }
9259 -       
9260 -       
9261 +
9262 +
9263         return 0;
9264  }
9265  #endif
9266  
9267 -static int fdevent_linux_rtsig_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9268 +static int fdevent_linux_rtsig_event_add(fdevents *ev, iosocket *sock, int events) {
9269         /* known index */
9270 -       if (fde_ndx != -1) {
9271 -               if (ev->pollfds[fde_ndx].fd == fd) {
9272 -                       ev->pollfds[fde_ndx].events = events;
9273 -                       
9274 -                       return fde_ndx;
9275 +       if (sock->fde_ndx != -1) {
9276 +               if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9277 +                       ev->pollfds[sock->fde_ndx].events = events;
9278 +
9279 +                       return sock->fde_ndx;
9280                 }
9281 -               fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, fde_ndx, ev->pollfds[fde_ndx].fd);
9282 +               fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, sock->fde_ndx, ev->pollfds[sock->fde_ndx].fd);
9283                 SEGFAULT();
9284         }
9285 -       
9286 +
9287         if (ev->unused.used > 0) {
9288                 int k = ev->unused.ptr[--ev->unused.used];
9289 -               
9290 -               ev->pollfds[k].fd = fd;
9291 +
9292 +               ev->pollfds[k].fd = sock->fd;
9293                 ev->pollfds[k].events = events;
9294  
9295 -               bitset_set_bit(ev->sigbset, fd);
9296 -               
9297 +               bitset_set_bit(ev->sigbset, sock->fd);
9298 +
9299                 return k;
9300         } else {
9301                 if (ev->size == 0) {
9302 @@ -102,12 +104,12 @@
9303                         ev->size += 16;
9304                         ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
9305                 }
9306 -               
9307 -               ev->pollfds[ev->used].fd = fd;
9308 +
9309 +               ev->pollfds[ev->used].fd = sock->fd;
9310                 ev->pollfds[ev->used].events = events;
9311  
9312 -               bitset_set_bit(ev->sigbset, fd);
9313 -       
9314 +               bitset_set_bit(ev->sigbset, sock->fd);
9315 +
9316                 return ev->used++;
9317         }
9318  }
9319 @@ -115,20 +117,20 @@
9320  static int fdevent_linux_rtsig_poll(fdevents *ev, int timeout_ms) {
9321         struct timespec ts;
9322         int r;
9323 -       
9324 +
9325  #if 0
9326         fdevent_linux_rtsig_event_compress(ev);
9327  #endif
9328 -       
9329 +
9330         ev->in_sigio = 1;
9331 -               
9332 +
9333         ts.tv_sec =  timeout_ms / 1000;
9334         ts.tv_nsec = (timeout_ms % 1000) * 1000000;
9335         r = sigtimedwait(&(ev->sigset), &(ev->siginfo), &(ts));
9336 -               
9337 -       if (r == -1) { 
9338 +
9339 +       if (r == -1) {
9340                 if (errno == EAGAIN) return 0;
9341 -               return r; 
9342 +               return r;
9343         } else if (r == SIGIO) {
9344                 struct sigaction act;
9345  
9346 @@ -140,7 +142,7 @@
9347                 /* re-enable the signal queue */
9348                 act.sa_handler = SIG_DFL;
9349                 sigaction(ev->signum, &act, NULL);
9350 -               
9351 +
9352                 ev->in_sigio = 0;
9353                 r = poll(ev->pollfds, ev->used, timeout_ms);
9354  
9355 @@ -156,97 +158,67 @@
9356         }
9357  }
9358  
9359 -static int fdevent_linux_rtsig_event_get_revent(fdevents *ev, size_t ndx) {
9360 +static int fdevent_linux_rtsig_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9361         if (ev->in_sigio == 1) {
9362 -#  if 0
9363 -               if (ev->siginfo.si_band == POLLERR) {
9364 -                       fprintf(stderr, "event: %d %02lx %02x %s\n", ev->siginfo.si_fd, ev->siginfo.si_band, errno, strerror(errno));
9365 -               }
9366 -#  endif               
9367 -               if (ndx != 0) {
9368 -                       fprintf(stderr, "+\n");
9369 -                       return 0;
9370 -               }
9371 -               
9372 -               return ev->siginfo.si_band & 0x3f;
9373 +               /* only one event */
9374 +
9375 +               fdevent_revents_add(revents, ev->siginfo.si_fd, ev->siginfo.si_band & 0x3f);
9376         } else {
9377 -               if (ndx >= ev->used) {
9378 -                       fprintf(stderr, "%s.%d: event: %zu %zu\n", __FILE__, __LINE__, ndx, ev->used);
9379 -                       return 0;
9380 +               size_t ndx;
9381 +
9382 +               for (ndx = 0; ndx < ev->used; ndx++) {
9383 +                       if (ev->pollfds[ndx].revents) {
9384 +                               fdevent_revents_add(revents, ev->pollfds[ndx].fd, ev->pollfds[ndx].revents);
9385 +                       }
9386                 }
9387 -               return ev->pollfds[ndx].revents;
9388         }
9389 -}
9390  
9391 -static int fdevent_linux_rtsig_event_get_fd(fdevents *ev, size_t ndx) {
9392 -       if (ev->in_sigio == 1) {
9393 -               return ev->siginfo.si_fd;
9394 -       } else {
9395 -               return ev->pollfds[ndx].fd;
9396 -       }
9397 +       return 0;
9398  }
9399  
9400  static int fdevent_linux_rtsig_fcntl_set(fdevents *ev, int fd) {
9401         static pid_t pid = 0;
9402 -       
9403 +
9404         if (pid == 0) pid = getpid();
9405 -       
9406 +
9407         if (-1 == fcntl(fd, F_SETSIG, ev->signum)) return -1;
9408 -       
9409 +
9410         if (-1 == fcntl(fd, F_SETOWN, (int) pid)) return -1;
9411 -       
9412 +
9413         return fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK | O_RDWR);
9414  }
9415  
9416  
9417 -static int fdevent_linux_rtsig_event_next_fdndx(fdevents *ev, int ndx) {
9418 -       if (ev->in_sigio == 1) {
9419 -               if (ndx < 0) return 0;
9420 -               return -1;
9421 -       } else {
9422 -               size_t i;
9423 -               
9424 -               i = (ndx < 0) ? 0 : ndx + 1;
9425 -               for (; i < ev->used; i++) {
9426 -                       if (ev->pollfds[i].revents) break;
9427 -               }
9428 -               
9429 -               return i;
9430 -       }
9431 -}
9432 -
9433  int fdevent_linux_rtsig_init(fdevents *ev) {
9434         ev->type = FDEVENT_HANDLER_LINUX_RTSIG;
9435  #define SET(x) \
9436         ev->x = fdevent_linux_rtsig_##x;
9437 -       
9438 +
9439         SET(free);
9440         SET(poll);
9441 -       
9442 +
9443         SET(event_del);
9444         SET(event_add);
9445 -       
9446 -       SET(event_next_fdndx);
9447 +
9448         SET(fcntl_set);
9449 -       SET(event_get_fd);
9450 -       SET(event_get_revent);
9451 -       
9452 +       SET(get_revents);
9453 +
9454         ev->signum = SIGRTMIN + 1;
9455 -       
9456 +
9457         sigemptyset(&(ev->sigset));
9458         sigaddset(&(ev->sigset), ev->signum);
9459         sigaddset(&(ev->sigset), SIGIO);
9460         if (-1 == sigprocmask(SIG_BLOCK, &(ev->sigset), NULL)) {
9461                 fprintf(stderr, "%s.%d: sigprocmask failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9462                         __FILE__, __LINE__, strerror(errno));
9463 -               
9464 +
9465                 return -1;
9466         }
9467 -       
9468 +
9469         ev->in_sigio = 1;
9470  
9471         ev->sigbset = bitset_init(ev->maxfds);
9472 -       
9473 +
9474         return 0;
9475  }
9476  #else
9477 --- ../lighttpd-1.4.11/src/fdevent_linux_sysepoll.c     2005-09-30 20:29:27.000000000 +0300
9478 +++ lighttpd-1.4.12/src/fdevent_linux_sysepoll.c        2006-07-18 13:03:40.000000000 +0300
9479 @@ -1,6 +1,5 @@
9480  #include <sys/types.h>
9481  
9482 -#include <unistd.h>
9483  #include <stdlib.h>
9484  #include <stdio.h>
9485  #include <string.h>
9486 @@ -11,6 +10,9 @@
9487  #include "fdevent.h"
9488  #include "settings.h"
9489  #include "buffer.h"
9490 +#include "log.h"
9491 +
9492 +#include "sys-files.h"
9493  
9494  #ifdef USE_LINUX_EPOLL
9495  static void fdevent_linux_sysepoll_free(fdevents *ev) {
9496 @@ -18,38 +20,40 @@
9497         free(ev->epoll_events);
9498  }
9499  
9500 -static int fdevent_linux_sysepoll_event_del(fdevents *ev, int fde_ndx, int fd) {
9501 +static int fdevent_linux_sysepoll_event_del(fdevents *ev, iosocket *sock) {
9502         struct epoll_event ep;
9503 -       
9504 -       if (fde_ndx < 0) return -1;
9505 -       
9506 +
9507 +       if (sock->fde_ndx < 0) return -1;
9508 +
9509         memset(&ep, 0, sizeof(ep));
9510 -       
9511 -       ep.data.fd = fd;
9512 +
9513 +       ep.data.fd = sock->fd;
9514         ep.data.ptr = NULL;
9515 -       
9516 -       if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fd, &ep)) {
9517 +
9518 +       if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, sock->fd, &ep)) {
9519                 fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n", __FILE__, __LINE__, strerror(errno));
9520 -               
9521 +
9522                 SEGFAULT();
9523 -               
9524 +
9525                 return 0;
9526         }
9527 -       
9528 -       
9529 -       return -1;
9530 +
9531 +       sock->fde_ndx = -1;
9532 +
9533 +       return 0;
9534  }
9535  
9536 -static int fdevent_linux_sysepoll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9537 +static int fdevent_linux_sysepoll_event_add(fdevents *ev, iosocket *sock, int events) {
9538         struct epoll_event ep;
9539         int add = 0;
9540 -       
9541 -       if (fde_ndx == -1) add = 1;
9542 -       
9543 +
9544 +       /* a new fd */
9545 +       if (sock->fde_ndx == -1) add = 1;
9546 +
9547         memset(&ep, 0, sizeof(ep));
9548 -       
9549 +
9550         ep.events = 0;
9551 -       
9552 +
9553         if (events & FDEVENT_IN)  ep.events |= EPOLLIN;
9554         if (events & FDEVENT_OUT) ep.events |= EPOLLOUT;
9555  
9556 @@ -60,73 +64,61 @@
9557          * sent.
9558          *
9559          */
9560 -       
9561 +
9562         ep.events |= EPOLLERR | EPOLLHUP /* | EPOLLET */;
9563 -       
9564 +
9565         ep.data.ptr = NULL;
9566 -       ep.data.fd = fd;
9567 -       
9568 -       if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, fd, &ep)) {
9569 +       ep.data.fd = sock->fd;
9570 +
9571 +       if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, sock->fd, &ep)) {
9572                 fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n", __FILE__, __LINE__, strerror(errno));
9573 -               
9574 +
9575                 SEGFAULT();
9576 -               
9577 +
9578                 return 0;
9579         }
9580 -       
9581 -       return fd;
9582 +
9583 +       sock->fde_ndx = sock->fd;
9584 +
9585 +       return 0;
9586  }
9587  
9588  static int fdevent_linux_sysepoll_poll(fdevents *ev, int timeout_ms) {
9589         return epoll_wait(ev->epoll_fd, ev->epoll_events, ev->maxfds, timeout_ms);
9590  }
9591  
9592 -static int fdevent_linux_sysepoll_event_get_revent(fdevents *ev, size_t ndx) {
9593 -       int events = 0, e;
9594 -       
9595 -       e = ev->epoll_events[ndx].events;
9596 -       if (e & EPOLLIN) events |= FDEVENT_IN;
9597 -       if (e & EPOLLOUT) events |= FDEVENT_OUT;
9598 -       if (e & EPOLLERR) events |= FDEVENT_ERR;
9599 -       if (e & EPOLLHUP) events |= FDEVENT_HUP;
9600 -       if (e & EPOLLPRI) events |= FDEVENT_PRI;
9601 -       
9602 -       return e;
9603 -}
9604 -
9605 -static int fdevent_linux_sysepoll_event_get_fd(fdevents *ev, size_t ndx) {
9606 -# if 0
9607 -       fprintf(stderr, "%s.%d: %d, %d\n", __FILE__, __LINE__, ndx, ev->epoll_events[ndx].data.fd);
9608 -# endif
9609 -       
9610 -       return ev->epoll_events[ndx].data.fd;
9611 -}
9612 -
9613 -static int fdevent_linux_sysepoll_event_next_fdndx(fdevents *ev, int ndx) {
9614 -       size_t i;
9615 -       
9616 -       UNUSED(ev);
9617 +static int fdevent_linux_sysepoll_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9618 +       size_t ndx;
9619 +
9620 +       for (ndx = 0; ndx < event_count; ndx++) {
9621 +               int events = 0, e;
9622 +
9623 +               e = ev->epoll_events[ndx].events;
9624 +               if (e & EPOLLIN) events |= FDEVENT_IN;
9625 +               if (e & EPOLLOUT) events |= FDEVENT_OUT;
9626 +               if (e & EPOLLERR) events |= FDEVENT_ERR;
9627 +               if (e & EPOLLHUP) events |= FDEVENT_HUP;
9628 +               if (e & EPOLLPRI) events |= FDEVENT_PRI;
9629  
9630 -       i = (ndx < 0) ? 0 : ndx + 1;
9631 -       
9632 -       return i;
9633 +               fdevent_revents_add(revents, ev->epoll_events[ndx].data.fd, e);
9634 +       }
9635 +
9636 +       return 0;
9637  }
9638  
9639  int fdevent_linux_sysepoll_init(fdevents *ev) {
9640         ev->type = FDEVENT_HANDLER_LINUX_SYSEPOLL;
9641  #define SET(x) \
9642         ev->x = fdevent_linux_sysepoll_##x;
9643 -       
9644 +
9645         SET(free);
9646         SET(poll);
9647 -       
9648 +
9649         SET(event_del);
9650         SET(event_add);
9651 -       
9652 -       SET(event_next_fdndx);
9653 -       SET(event_get_fd);
9654 -       SET(event_get_revent);
9655 -       
9656 +
9657 +       SET(get_revents);
9658 +
9659         if (-1 == (ev->epoll_fd = epoll_create(ev->maxfds))) {
9660                 fprintf(stderr, "%s.%d: epoll_create failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9661                         __FILE__, __LINE__, strerror(errno));
9662 @@ -154,7 +146,7 @@
9663  
9664         fprintf(stderr, "%s.%d: linux-sysepoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
9665                 __FILE__, __LINE__);
9666 -       
9667 +
9668         return -1;
9669  }
9670  #endif
9671 --- ../lighttpd-1.4.11/src/fdevent_poll.c       2005-11-18 13:59:16.000000000 +0200
9672 +++ lighttpd-1.4.12/src/fdevent_poll.c  2006-07-18 13:03:40.000000000 +0300
9673 @@ -1,6 +1,5 @@
9674  #include <sys/types.h>
9675  
9676 -#include <unistd.h>
9677  #include <stdlib.h>
9678  #include <stdio.h>
9679  #include <string.h>
9680 @@ -11,6 +10,7 @@
9681  #include "fdevent.h"
9682  #include "settings.h"
9683  #include "buffer.h"
9684 +#include "log.h"
9685  
9686  #ifdef USE_POLL
9687  static void fdevent_poll_free(fdevents *ev) {
9688 @@ -18,21 +18,21 @@
9689         if (ev->unused.ptr) free(ev->unused.ptr);
9690  }
9691  
9692 -static int fdevent_poll_event_del(fdevents *ev, int fde_ndx, int fd) {
9693 -       if (fde_ndx < 0) return -1;
9694 -       
9695 -       if ((size_t)fde_ndx >= ev->used) {
9696 -               fprintf(stderr, "%s.%d: del! out of range %d %zd\n", __FILE__, __LINE__, fde_ndx, ev->used);
9697 +static int fdevent_poll_event_del(fdevents *ev, iosocket *sock) {
9698 +       if (sock->fde_ndx < 0) return -1;
9699 +
9700 +       if ((size_t)sock->fde_ndx >= ev->used) {
9701 +               fprintf(stderr, "%s.%d: del! out of range %d %zd\n", __FILE__, __LINE__, sock->fde_ndx, ev->used);
9702                 SEGFAULT();
9703         }
9704 -       
9705 -       if (ev->pollfds[fde_ndx].fd == fd) {
9706 -               size_t k = fde_ndx;
9707 -               
9708 +
9709 +       if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9710 +               size_t k = sock->fde_ndx;
9711 +
9712                 ev->pollfds[k].fd = -1;
9713                 /* ev->pollfds[k].events = 0; */
9714                 /* ev->pollfds[k].revents = 0; */
9715 -               
9716 +
9717                 if (ev->unused.size == 0) {
9718                         ev->unused.size = 16;
9719                         ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size);
9720 @@ -40,48 +40,51 @@
9721                         ev->unused.size += 16;
9722                         ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
9723                 }
9724 -               
9725 +
9726                 ev->unused.ptr[ev->unused.used++] = k;
9727         } else {
9728                 SEGFAULT();
9729         }
9730 -       
9731 -       return -1;
9732 +
9733 +       sock->fde_ndx = -1;
9734 +
9735 +       return 0;
9736  }
9737  
9738  #if 0
9739  static int fdevent_poll_event_compress(fdevents *ev) {
9740         size_t j;
9741 -       
9742 +
9743         if (ev->used == 0) return 0;
9744         if (ev->unused.used != 0) return 0;
9745 -       
9746 +
9747         for (j = ev->used - 1; j + 1 > 0 && ev->pollfds[j].fd == -1; j--) ev->used--;
9748 -       
9749 +
9750         return 0;
9751  }
9752  #endif
9753  
9754 -static int fdevent_poll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9755 -       /* known index */
9756 -       
9757 -       if (fde_ndx != -1) {
9758 -               if (ev->pollfds[fde_ndx].fd == fd) {
9759 -                       ev->pollfds[fde_ndx].events = events;
9760 -                       
9761 -                       return fde_ndx;
9762 +static int fdevent_poll_event_add(fdevents *ev, iosocket *sock, int events) {
9763 +       if (sock->fde_ndx != -1) {
9764 +               /* this fd was already added, just change the requested events */
9765 +
9766 +               if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9767 +                       ev->pollfds[sock->fde_ndx].events = events;
9768 +
9769 +                       return sock->fde_ndx;
9770                 }
9771 -               fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, fde_ndx, ev->pollfds[fde_ndx].fd);
9772 +               fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, sock->fde_ndx, ev->pollfds[sock->fde_ndx].fd);
9773                 SEGFAULT();
9774         }
9775 -       
9776 +
9777         if (ev->unused.used > 0) {
9778                 int k = ev->unused.ptr[--ev->unused.used];
9779 -               
9780 -               ev->pollfds[k].fd = fd;
9781 +
9782 +               ev->pollfds[k].fd = sock->fd;
9783                 ev->pollfds[k].events = events;
9784 -               
9785 -               return k;
9786 +
9787 +               sock->fde_ndx = k;
9788 +
9789         } else {
9790                 if (ev->size == 0) {
9791                         ev->size = 16;
9792 @@ -90,12 +93,13 @@
9793                         ev->size += 16;
9794                         ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
9795                 }
9796 -               
9797 -               ev->pollfds[ev->used].fd = fd;
9798 +
9799 +               ev->pollfds[ev->used].fd = sock->fd;
9800                 ev->pollfds[ev->used].events = events;
9801 -               
9802 -               return ev->used++;
9803 +
9804 +               sock->fde_ndx = ev->used++;
9805         }
9806 +       return 0;
9807  }
9808  
9809  static int fdevent_poll_poll(fdevents *ev, int timeout_ms) {
9810 @@ -105,71 +109,38 @@
9811         return poll(ev->pollfds, ev->used, timeout_ms);
9812  }
9813  
9814 -static int fdevent_poll_event_get_revent(fdevents *ev, size_t ndx) {
9815 -       int r, poll_r;
9816 -       if (ndx >= ev->used) {
9817 -               fprintf(stderr, "%s.%d: dying because: event: %zd >= %zd\n", __FILE__, __LINE__, ndx, ev->used);
9818 -               
9819 -               SEGFAULT();
9820 -               
9821 -               return 0;
9822 -       }
9823 -       
9824 -       if (ev->pollfds[ndx].revents & POLLNVAL) {
9825 -               /* should never happen */
9826 -               SEGFAULT();
9827 -       }
9828 +static int fdevent_poll_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9829 +       size_t ndx;
9830  
9831 -       r = 0;
9832 -       poll_r = ev->pollfds[ndx].revents;
9833 +       for (ndx = 0; ndx < ev->used; ndx++) {
9834 +               if (ev->pollfds[ndx].revents) {
9835 +                       if (ev->pollfds[ndx].revents & POLLNVAL) {
9836 +                               /* should never happen */
9837 +                               SEGFAULT();
9838 +                       }
9839  
9840 -       /* map POLL* to FDEVEN_* */
9841 -
9842 -       if (poll_r & POLLIN) r |= FDEVENT_IN;
9843 -       if (poll_r & POLLOUT) r |= FDEVENT_OUT;
9844 -       if (poll_r & POLLERR) r |= FDEVENT_ERR;
9845 -       if (poll_r & POLLHUP) r |= FDEVENT_HUP;
9846 -       if (poll_r & POLLNVAL) r |= FDEVENT_NVAL;
9847 -       if (poll_r & POLLPRI) r |= FDEVENT_PRI;
9848 -       
9849 -       return ev->pollfds[ndx].revents;
9850 -}
9851 -
9852 -static int fdevent_poll_event_get_fd(fdevents *ev, size_t ndx) {
9853 -       return ev->pollfds[ndx].fd;
9854 -}
9855 -
9856 -static int fdevent_poll_event_next_fdndx(fdevents *ev, int ndx) {
9857 -       size_t i;
9858 -       
9859 -       i = (ndx < 0) ? 0 : ndx + 1;
9860 -       for (; i < ev->used; i++) {
9861 -               if (ev->pollfds[i].revents) break;
9862 +                       fdevent_revents_add(revents, ev->pollfds[ndx].fd, ev->pollfds[ndx].revents);
9863 +               }
9864         }
9865 -       
9866 -       return i;
9867 +
9868 +       return 0;
9869  }
9870  
9871  int fdevent_poll_init(fdevents *ev) {
9872         ev->type = FDEVENT_HANDLER_POLL;
9873  #define SET(x) \
9874         ev->x = fdevent_poll_##x;
9875 -       
9876 +
9877         SET(free);
9878         SET(poll);
9879 -       
9880 +
9881         SET(event_del);
9882         SET(event_add);
9883 -       
9884 -       SET(event_next_fdndx);
9885 -       SET(event_get_fd);
9886 -       SET(event_get_revent);
9887 -       
9888 -       return 0;
9889 -}
9890 -
9891  
9892 +       SET(get_revents);
9893  
9894 +       return 0;
9895 +}
9896  
9897  #else
9898  int fdevent_poll_init(fdevents *ev) {
9899 --- ../lighttpd-1.4.11/src/fdevent_select.c     2005-08-31 11:12:46.000000000 +0300
9900 +++ lighttpd-1.4.12/src/fdevent_select.c        2006-07-18 13:03:40.000000000 +0300
9901 @@ -1,18 +1,19 @@
9902 -#include <sys/time.h>
9903  #include <sys/types.h>
9904  
9905 -#include <unistd.h>
9906  #include <stdlib.h>
9907  #include <string.h>
9908  #include <errno.h>
9909  #include <signal.h>
9910  #include <fcntl.h>
9911  #include <assert.h>
9912 +#include <stdio.h>
9913  
9914  #include "fdevent.h"
9915  #include "settings.h"
9916  #include "buffer.h"
9917  
9918 +#include "sys-socket.h"
9919 +
9920  #ifdef USE_SELECT
9921  
9922  static int fdevent_select_reset(fdevents *ev) {
9923 @@ -24,101 +25,98 @@
9924         return 0;
9925  }
9926  
9927 -static int fdevent_select_event_del(fdevents *ev, int fde_ndx, int fd) {
9928 -       if (fde_ndx < 0) return -1;
9929 +static int fdevent_select_event_del(fdevents *ev, iosocket *sock) {
9930 +       if (sock->fde_ndx < 0) return -1;
9931  
9932 -       FD_CLR(fd, &(ev->select_set_read));
9933 -       FD_CLR(fd, &(ev->select_set_write));
9934 -       FD_CLR(fd, &(ev->select_set_error));
9935 +       FD_CLR(sock->fd, &(ev->select_set_read));
9936 +       FD_CLR(sock->fd, &(ev->select_set_write));
9937 +       FD_CLR(sock->fd, &(ev->select_set_error));
9938  
9939 -       return -1;
9940 -}
9941 +       /* mark the fdevent as deleted */
9942 +       sock->fde_ndx = -1;
9943  
9944 -static int fdevent_select_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9945 -       UNUSED(fde_ndx);
9946 +       return 0;
9947 +}
9948  
9949 +static int fdevent_select_event_add(fdevents *ev, iosocket *sock, int events) {
9950         /* we should be protected by max-fds, but you never know */
9951 -       assert(fd < FD_SETSIZE);
9952 +#ifndef _WIN32
9953 +       assert(sock->fd < FD_SETSIZE);
9954 +#endif
9955  
9956         if (events & FDEVENT_IN) {
9957 -               FD_SET(fd, &(ev->select_set_read));
9958 -               FD_CLR(fd, &(ev->select_set_write));
9959 +               FD_SET(sock->fd, &(ev->select_set_read));
9960 +               FD_CLR(sock->fd, &(ev->select_set_write));
9961         }
9962         if (events & FDEVENT_OUT) {
9963 -               FD_CLR(fd, &(ev->select_set_read));
9964 -               FD_SET(fd, &(ev->select_set_write));
9965 +               FD_CLR(sock->fd, &(ev->select_set_read));
9966 +               FD_SET(sock->fd, &(ev->select_set_write));
9967         }
9968 -       FD_SET(fd, &(ev->select_set_error));
9969 -       
9970 -       if (fd > ev->select_max_fd) ev->select_max_fd = fd;
9971 -       
9972 -       return fd;
9973 +       FD_SET(sock->fd, &(ev->select_set_error));
9974 +
9975 +       /* we need this for the poll */
9976 +       if (sock->fd > ev->select_max_fd) ev->select_max_fd = sock->fd;
9977 +
9978 +       /* mark fd as added */
9979 +       sock->fde_ndx = sock->fd;
9980 +
9981 +       return 0;
9982  }
9983  
9984  static int fdevent_select_poll(fdevents *ev, int timeout_ms) {
9985         struct timeval tv;
9986 -       
9987 +
9988         tv.tv_sec =  timeout_ms / 1000;
9989         tv.tv_usec = (timeout_ms % 1000) * 1000;
9990 -       
9991 +
9992         ev->select_read = ev->select_set_read;
9993         ev->select_write = ev->select_set_write;
9994         ev->select_error = ev->select_set_error;
9995 -       
9996 +
9997         return select(ev->select_max_fd + 1, &(ev->select_read), &(ev->select_write), &(ev->select_error), &tv);
9998  }
9999  
10000 -static int fdevent_select_event_get_revent(fdevents *ev, size_t ndx) {
10001 -       int revents = 0;
10002 -       
10003 -       if (FD_ISSET(ndx, &(ev->select_read))) {
10004 -               revents |= FDEVENT_IN;
10005 +/**
10006 + * scan the fdset for events 
10007 + */
10008 +static int fdevent_select_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
10009 +
10010 +       int ndx = 0;
10011 +
10012 +       for (ndx = 0; ndx < ev->select_max_fd; ndx++) {
10013 +               int events = 0;
10014 +
10015 +               if (FD_ISSET(ndx, &(ev->select_read))) {
10016 +                       events |= FDEVENT_IN;
10017 +               }
10018 +               if (FD_ISSET(ndx, &(ev->select_write))) {
10019 +                       events |= FDEVENT_OUT;
10020 +               }
10021 +               if (FD_ISSET(ndx, &(ev->select_error))) {
10022 +                       events |= FDEVENT_ERR;
10023 +               }
10024 +
10025 +               if (events) {
10026 +                       fdevent_revents_add(revents, ndx, events);
10027 +               }
10028         }
10029 -       if (FD_ISSET(ndx, &(ev->select_write))) {
10030 -               revents |= FDEVENT_OUT;
10031 -       }
10032 -       if (FD_ISSET(ndx, &(ev->select_error))) {
10033 -               revents |= FDEVENT_ERR;
10034 -       }
10035 -       
10036 -       return revents;
10037 -}
10038 -
10039 -static int fdevent_select_event_get_fd(fdevents *ev, size_t ndx) {
10040 -       UNUSED(ev);
10041 -
10042 -       return ndx;
10043 -}
10044  
10045 -static int fdevent_select_event_next_fdndx(fdevents *ev, int ndx) {
10046 -       int i;
10047 -       
10048 -       i = (ndx < 0) ? 0 : ndx + 1;
10049 -       
10050 -       for (; i < ev->select_max_fd + 1; i++) {
10051 -               if (FD_ISSET(i, &(ev->select_read))) break;
10052 -               if (FD_ISSET(i, &(ev->select_write))) break;
10053 -               if (FD_ISSET(i, &(ev->select_error))) break;
10054 -       }
10055 -       
10056 -       return i;
10057 +       return 0;
10058  }
10059  
10060  int fdevent_select_init(fdevents *ev) {
10061         ev->type = FDEVENT_HANDLER_SELECT;
10062  #define SET(x) \
10063         ev->x = fdevent_select_##x;
10064 -       
10065 +
10066         SET(reset);
10067         SET(poll);
10068 -       
10069 +
10070         SET(event_del);
10071         SET(event_add);
10072 -       
10073 -       SET(event_next_fdndx);
10074 -       SET(event_get_fd);
10075 -       SET(event_get_revent);
10076 -       
10077 +
10078 +       SET(get_revents);
10079 +
10080         return 0;
10081  }
10082  
10083 --- ../lighttpd-1.4.11/src/fdevent_solaris_devpoll.c    2005-09-01 10:45:26.000000000 +0300
10084 +++ lighttpd-1.4.12/src/fdevent_solaris_devpoll.c       2006-07-16 00:26:03.000000000 +0300
10085 @@ -1,6 +1,5 @@
10086  #include <sys/types.h>
10087  
10088 -#include <unistd.h>
10089  #include <stdlib.h>
10090  #include <stdio.h>
10091  #include <string.h>
10092 @@ -23,55 +22,55 @@
10093  
10094  static int fdevent_solaris_devpoll_event_del(fdevents *ev, int fde_ndx, int fd) {
10095         struct pollfd pfd;
10096 -               
10097 +
10098         if (fde_ndx < 0) return -1;
10099 -       
10100 +
10101         pfd.fd = fd;
10102         pfd.events = POLLREMOVE;
10103         pfd.revents = 0;
10104 -       
10105 +
10106         if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
10107 -               fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n", 
10108 -                       __FILE__, __LINE__, 
10109 +               fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
10110 +                       __FILE__, __LINE__,
10111                         fd, strerror(errno));
10112 -               
10113 +
10114                 return -1;
10115         }
10116 -       
10117 +
10118         return -1;
10119  }
10120  
10121  static int fdevent_solaris_devpoll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
10122         struct pollfd pfd;
10123         int add = 0;
10124 -               
10125 +
10126         if (fde_ndx == -1) add = 1;
10127 -       
10128 +
10129         pfd.fd = fd;
10130         pfd.events = events;
10131         pfd.revents = 0;
10132 -       
10133 +
10134         if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
10135 -               fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n", 
10136 -                       __FILE__, __LINE__, 
10137 +               fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
10138 +                       __FILE__, __LINE__,
10139                         fd, strerror(errno));
10140 -               
10141 +
10142                 return -1;
10143         }
10144 -       
10145 +
10146         return fd;
10147  }
10148  
10149  static int fdevent_solaris_devpoll_poll(fdevents *ev, int timeout_ms) {
10150         struct dvpoll dopoll;
10151         int ret;
10152 -       
10153 +
10154         dopoll.dp_timeout = timeout_ms;
10155         dopoll.dp_nfds = ev->maxfds;
10156         dopoll.dp_fds = ev->devpollfds;
10157 -       
10158 +
10159         ret = ioctl(ev->devpoll_fd, DP_POLL, &dopoll);
10160 -       
10161 +
10162         return ret;
10163  }
10164  
10165 @@ -85,11 +84,11 @@
10166  
10167  static int fdevent_solaris_devpoll_event_next_fdndx(fdevents *ev, int last_ndx) {
10168         size_t i;
10169 -       
10170 +
10171         UNUSED(ev);
10172  
10173         i = (last_ndx < 0) ? 0 : last_ndx + 1;
10174 -       
10175 +
10176         return i;
10177  }
10178  
10179 @@ -117,20 +116,20 @@
10180         ev->type = FDEVENT_HANDLER_SOLARIS_DEVPOLL;
10181  #define SET(x) \
10182         ev->x = fdevent_solaris_devpoll_##x;
10183 -       
10184 +
10185         SET(free);
10186         SET(poll);
10187         SET(reset);
10188 -       
10189 +
10190         SET(event_del);
10191         SET(event_add);
10192 -       
10193 +
10194         SET(event_next_fdndx);
10195         SET(event_get_fd);
10196         SET(event_get_revent);
10197 -       
10198 +
10199         ev->devpollfds = malloc(sizeof(*ev->devpollfds) * ev->maxfds);
10200 -       
10201 +
10202         if ((ev->devpoll_fd = open("/dev/poll", O_RDWR)) < 0) {
10203                 fprintf(stderr, "%s.%d: opening /dev/poll failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
10204                         __FILE__, __LINE__, strerror(errno));
10205 @@ -152,7 +151,7 @@
10206  
10207         fprintf(stderr, "%s.%d: solaris-devpoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
10208                         __FILE__, __LINE__);
10209 -       
10210 +
10211         return -1;
10212  }
10213  #endif
10214 --- ../lighttpd-1.4.11/src/http-header-glue.c   2006-02-08 15:31:36.000000000 +0200
10215 +++ lighttpd-1.4.12/src/http-header-glue.c      2006-07-18 13:03:40.000000000 +0300
10216 @@ -45,20 +45,20 @@
10217  #   ifdef HAVE_STRUCT_SOCKADDR_STORAGE
10218  static size_t get_sa_len(const struct sockaddr *addr) {
10219         switch (addr->sa_family) {
10220 -               
10221 +
10222  #    ifdef AF_INET
10223         case AF_INET:
10224                 return (sizeof (struct sockaddr_in));
10225  #    endif
10226 -               
10227 +
10228  #    ifdef AF_INET6
10229         case AF_INET6:
10230                 return (sizeof (struct sockaddr_in6));
10231  #    endif
10232 -               
10233 +
10234         default:
10235                 return (sizeof (struct sockaddr));
10236 -               
10237 +
10238         }
10239  }
10240  #    define SA_LEN(addr)   (get_sa_len(addr))
10241 @@ -74,7 +74,7 @@
10242  
10243  int response_header_insert(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
10244         data_string *ds;
10245 -       
10246 +
10247         UNUSED(srv);
10248  
10249         if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
10250 @@ -82,32 +82,32 @@
10251         }
10252         buffer_copy_string_len(ds->key, key, keylen);
10253         buffer_copy_string_len(ds->value, value, vallen);
10254 -       
10255 +
10256         array_insert_unique(con->response.headers, (data_unset *)ds);
10257 -       
10258 +
10259         return 0;
10260  }
10261  
10262  int response_header_overwrite(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
10263         data_string *ds;
10264 -       
10265 +
10266         UNUSED(srv);
10267  
10268         /* if there already is a key by this name overwrite the value */
10269         if (NULL != (ds = (data_string *)array_get_element(con->response.headers, key))) {
10270                 buffer_copy_string(ds->value, value);
10271 -               
10272 +
10273                 return 0;
10274         }
10275 -       
10276 +
10277         return response_header_insert(srv, con, key, keylen, value, vallen);
10278  }
10279  
10280  int http_response_redirect_to_directory(server *srv, connection *con) {
10281         buffer *o;
10282 -       
10283 +
10284         o = buffer_init();
10285 -       
10286 +
10287         if (con->conf.is_ssl) {
10288                 buffer_copy_string(o, "https://");
10289         } else {
10290 @@ -123,36 +123,36 @@
10291  #endif
10292                 sock_addr our_addr;
10293                 socklen_t our_addr_len;
10294 -               
10295 +
10296                 our_addr_len = sizeof(our_addr);
10297 -               
10298 -               if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
10299 +
10300 +               if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
10301                         con->http_status = 500;
10302 -                       
10303 +
10304                         log_error_write(srv, __FILE__, __LINE__, "ss",
10305                                         "can't get sockname", strerror(errno));
10306 -                       
10307 +
10308                         buffer_free(o);
10309                         return 0;
10310                 }
10311 -               
10312 -               
10313 +
10314 +
10315                 /* Lookup name: secondly try to get hostname for bind address */
10316                 switch(our_addr.plain.sa_family) {
10317  #ifdef HAVE_IPV6
10318                 case AF_INET6:
10319 -                       if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6), 
10320 -                                            SA_LEN((const struct sockaddr *)&our_addr.ipv6), 
10321 +                       if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6),
10322 +                                            SA_LEN((const struct sockaddr *)&our_addr.ipv6),
10323                                              hbuf, sizeof(hbuf), NULL, 0, 0)) {
10324 -                               
10325 +
10326                                 char dst[INET6_ADDRSTRLEN];
10327 -                               
10328 +
10329                                 log_error_write(srv, __FILE__, __LINE__,
10330                                                 "SSSS", "NOTICE: getnameinfo failed: ",
10331                                                 strerror(errno), ", using ip-address instead");
10332 -                               
10333 -                               buffer_append_string(o, 
10334 -                                                    inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr, 
10335 +
10336 +                               buffer_append_string(o,
10337 +                                                    inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr,
10338                                                                dst, sizeof(dst)));
10339                         } else {
10340                                 buffer_append_string(o, hbuf);
10341 @@ -164,7 +164,7 @@
10342                                 log_error_write(srv, __FILE__, __LINE__,
10343                                                 "SdSS", "NOTICE: gethostbyaddr failed: ",
10344                                                 h_errno, ", using ip-address instead");
10345 -                               
10346 +
10347                                 buffer_append_string(o, inet_ntoa(our_addr.ipv4.sin_addr));
10348                         } else {
10349                                 buffer_append_string(o, he->h_name);
10350 @@ -173,12 +173,12 @@
10351                 default:
10352                         log_error_write(srv, __FILE__, __LINE__,
10353                                         "S", "ERROR: unsupported address-type");
10354 -                       
10355 +
10356                         buffer_free(o);
10357                         return -1;
10358                 }
10359 -               
10360 -               if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) || 
10361 +
10362 +               if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) ||
10363                       (con->conf.is_ssl == 1 && srv->srvconf.port == 443))) {
10364                         buffer_append_string(o, ":");
10365                         buffer_append_long(o, srv->srvconf.port);
10366 @@ -190,41 +190,41 @@
10367                 buffer_append_string(o, "?");
10368                 buffer_append_string_buffer(o, con->uri.query);
10369         }
10370 -       
10371 +
10372         response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(o));
10373 -       
10374 +
10375         con->http_status = 301;
10376         con->file_finished = 1;
10377 -       
10378 +
10379         buffer_free(o);
10380 -       
10381 +
10382         return 0;
10383  }
10384  
10385  buffer * strftime_cache_get(server *srv, time_t last_mod) {
10386         struct tm *tm;
10387         size_t i;
10388 -               
10389 +
10390         for (i = 0; i < FILE_CACHE_MAX; i++) {
10391                 /* found cache-entry */
10392                 if (srv->mtime_cache[i].mtime == last_mod) return srv->mtime_cache[i].str;
10393 -                               
10394 +
10395                 /* found empty slot */
10396                 if (srv->mtime_cache[i].mtime == 0) break;
10397         }
10398 -       
10399 +
10400         if (i == FILE_CACHE_MAX) {
10401                 i = 0;
10402         }
10403 -               
10404 +
10405         srv->mtime_cache[i].mtime = last_mod;
10406         buffer_prepare_copy(srv->mtime_cache[i].str, 1024);
10407         tm = gmtime(&(srv->mtime_cache[i].mtime));
10408 -       srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr, 
10409 +       srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr,
10410                                                  srv->mtime_cache[i].str->size - 1,
10411                                                  "%a, %d %b %Y %H:%M:%S GMT", tm);
10412         srv->mtime_cache[i].str->used++;
10413 -       
10414 +
10415         return srv->mtime_cache[i].str;
10416  }
10417  
10418 @@ -239,56 +239,60 @@
10419          *    request. That is, if no entity tags match, then the server MUST NOT
10420          *    return a 304 (Not Modified) response.
10421          */
10422 -       
10423 +
10424         /* last-modified handling */
10425         if (con->request.http_if_none_match) {
10426                 if (etag_is_equal(con->physical.etag, con->request.http_if_none_match)) {
10427 -                       if (con->request.http_method == HTTP_METHOD_GET || 
10428 +                       if (con->request.http_method == HTTP_METHOD_GET ||
10429                             con->request.http_method == HTTP_METHOD_HEAD) {
10430 -                               
10431 +
10432                                 /* check if etag + last-modified */
10433                                 if (con->request.http_if_modified_since) {
10434                                         size_t used_len;
10435                                         char *semicolon;
10436 -                                       
10437 +
10438                                         if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
10439                                                 used_len = strlen(con->request.http_if_modified_since);
10440                                         } else {
10441                                                 used_len = semicolon - con->request.http_if_modified_since;
10442                                         }
10443 -                                       
10444 +
10445                                         if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
10446                                                 con->http_status = 304;
10447                                                 return HANDLER_FINISHED;
10448                                         } else {
10449 +#ifdef HAVE_STRPTIME
10450                                                 char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
10451 +                                               time_t t_header, t_file;
10452 +                                               struct tm tm;
10453  
10454 -                                               /* convert to timestamp */
10455 -                                               if (used_len < sizeof(buf)) {
10456 -                                                       time_t t_header, t_file;
10457 -                                                       struct tm tm;
10458 -                                                       
10459 -                                                       strncpy(buf, con->request.http_if_modified_since, used_len);
10460 -                                                       buf[used_len] = '\0';
10461 -                                                       
10462 -                                                       strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10463 -                                                       t_header = mktime(&tm);
10464 -                                                       
10465 -                                                       strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10466 -                                                       t_file = mktime(&tm);
10467 -
10468 -                                                       if (t_file > t_header) {
10469 -                                                               con->http_status = 304;
10470 -                                                               return HANDLER_FINISHED;
10471 -                                                       }
10472 -                                               } else {
10473 -                                                       log_error_write(srv, __FILE__, __LINE__, "ssdd", 
10474 -                                                                       "DEBUG: Last-Modified check failed as the received timestamp was too long:", 
10475 +                                               /* check if we can safely copy the string */
10476 +                                               if (used_len >= sizeof(buf)) {
10477 +                                                       log_error_write(srv, __FILE__, __LINE__, "ssdd",
10478 +                                                                       "DEBUG: Last-Modified check failed as the received timestamp was too long:",
10479                                                                         con->request.http_if_modified_since, used_len, sizeof(buf) - 1);
10480 -                                                       
10481 +
10482                                                         con->http_status = 412;
10483                                                         return HANDLER_FINISHED;
10484                                                 }
10485 +
10486 +
10487 +                                               strncpy(buf, con->request.http_if_modified_since, used_len);
10488 +                                               buf[used_len] = '\0';
10489 +
10490 +                                               strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10491 +                                               t_header = mktime(&tm);
10492 +
10493 +                                               strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10494 +                                               t_file = mktime(&tm);
10495 +
10496 +                                               if (t_file > t_header) return HANDLER_GO_ON;
10497 +
10498 +                                               con->http_status = 304;
10499 +                                               return HANDLER_FINISHED;
10500 +#else
10501 +                        return HANDLER_GO_ON;
10502 +#endif
10503                                         }
10504                                 } else {
10505                                         con->http_status = 304;
10506 @@ -302,16 +306,41 @@
10507         } else if (con->request.http_if_modified_since) {
10508                 size_t used_len;
10509                 char *semicolon;
10510 -               
10511 +
10512                 if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
10513                         used_len = strlen(con->request.http_if_modified_since);
10514                 } else {
10515                         used_len = semicolon - con->request.http_if_modified_since;
10516                 }
10517 -               
10518 +
10519                 if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
10520                         con->http_status = 304;
10521                         return HANDLER_FINISHED;
10522 +               } else {
10523 +#ifdef HAVE_STRPTIME
10524 +                       char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
10525 +                       time_t t_header, t_file;
10526 +                       struct tm tm;
10527 +
10528 +                       /* convert to timestamp */
10529 +                       if (used_len >= sizeof(buf)) return HANDLER_GO_ON;
10530 +
10531 +                       strncpy(buf, con->request.http_if_modified_since, used_len);
10532 +                       buf[used_len] = '\0';
10533 +
10534 +                       strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10535 +                       t_header = mktime(&tm);
10536 +
10537 +                       strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10538 +                       t_file = mktime(&tm);
10539 +
10540 +                       if (t_file > t_header) return HANDLER_GO_ON;
10541 +
10542 +                       con->http_status = 304;
10543 +                       return HANDLER_FINISHED;
10544 +#else
10545 +            return HANDLER_GO_ON;
10546 +#endif
10547                 }
10548         }
10549  
10550 --- ../lighttpd-1.4.11/src/http_auth.c  2006-02-01 13:02:52.000000000 +0200
10551 +++ lighttpd-1.4.12/src/http_auth.c     2006-07-18 13:03:40.000000000 +0300
10552 @@ -22,7 +22,6 @@
10553  #include <string.h>
10554  #include <time.h>
10555  #include <errno.h>
10556 -#include <unistd.h>
10557  #include <ctype.h>
10558  
10559  #include "server.h"
10560 @@ -31,23 +30,14 @@
10561  #include "http_auth_digest.h"
10562  #include "stream.h"
10563  
10564 +#include "sys-strings.h"
10565 +
10566  #ifdef USE_OPENSSL
10567  # include <openssl/md5.h>
10568  #else
10569  # include "md5.h"
10570  #endif
10571  
10572 -
10573 -#ifdef USE_PAM
10574 -#include <security/pam_appl.h>
10575 -#include <security/pam_misc.h>
10576 -
10577 -static struct pam_conv conv = {
10578 -       misc_conv,
10579 -               NULL
10580 -};
10581 -#endif
10582 -
10583  handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s);
10584  
10585  static const char base64_pad = '=';
10586 @@ -75,25 +65,25 @@
10587         unsigned char *result;
10588         int ch, j = 0, k;
10589         size_t i;
10590 -       
10591 +
10592         size_t in_len = strlen(in);
10593 -       
10594 +
10595         buffer_prepare_copy(out, in_len);
10596 -       
10597 +
10598         result = (unsigned char *)out->ptr;
10599 -       
10600 +
10601         ch = in[0];
10602         /* run through the whole string, converting as we go */
10603         for (i = 0; i < in_len; i++) {
10604                 ch = in[i];
10605 -               
10606 +
10607                 if (ch == '\0') break;
10608 -               
10609 +
10610                 if (ch == base64_pad) break;
10611 -               
10612 +
10613                 ch = base64_reverse_table[ch];
10614                 if (ch < 0) continue;
10615 -               
10616 +
10617                 switch(i % 4) {
10618                 case 0:
10619                         result[j] = ch << 2;
10620 @@ -125,168 +115,168 @@
10621                 }
10622         }
10623         result[k] = '\0';
10624 -       
10625 +
10626         out->used = k;
10627 -       
10628 +
10629         return result;
10630  }
10631  
10632  static int http_auth_get_password(server *srv, mod_auth_plugin_data *p, buffer *username, buffer *realm, buffer *password) {
10633         int ret = -1;
10634 -       
10635 +
10636         if (!username->used|| !realm->used) return -1;
10637 -       
10638 +
10639         if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
10640                 stream f;
10641                 char * f_line;
10642 -               
10643 +
10644                 if (buffer_is_empty(p->conf.auth_htdigest_userfile)) return -1;
10645 -               
10646 +
10647                 if (0 != stream_open(&f, p->conf.auth_htdigest_userfile)) {
10648                         log_error_write(srv, __FILE__, __LINE__, "sbss", "opening digest-userfile", p->conf.auth_htdigest_userfile, "failed:", strerror(errno));
10649 -                       
10650 +
10651                         return -1;
10652                 }
10653 -               
10654 +
10655                 f_line = f.start;
10656 -               
10657 +
10658                 while (f_line - f.start != f.size) {
10659                         char *f_user, *f_pwd, *e, *f_realm;
10660                         size_t u_len, pwd_len, r_len;
10661 -                       
10662 +
10663                         f_user = f_line;
10664 -                       
10665 -                       /* 
10666 +
10667 +                       /*
10668                          * htdigest format
10669 -                        * 
10670 -                        * user:realm:md5(user:realm:password) 
10671 +                        *
10672 +                        * user:realm:md5(user:realm:password)
10673                          */
10674 -                       
10675 +
10676                         if (NULL == (f_realm = memchr(f_user, ':', f.size - (f_user - f.start) ))) {
10677 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
10678 -                                               "parsed error in", p->conf.auth_htdigest_userfile, 
10679 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
10680 +                                               "parsed error in", p->conf.auth_htdigest_userfile,
10681                                                 "expected 'username:realm:hashed password'");
10682 -                               
10683 +
10684                                 stream_close(&f);
10685 -                               
10686 +
10687                                 return -1;
10688                         }
10689 -                       
10690 +
10691                         if (NULL == (f_pwd = memchr(f_realm + 1, ':', f.size - (f_realm + 1 - f.start)))) {
10692 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
10693 -                                               "parsed error in", p->conf.auth_plain_userfile, 
10694 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
10695 +                                               "parsed error in", p->conf.auth_plain_userfile,
10696                                                 "expected 'username:realm:hashed password'");
10697 -                               
10698 +
10699                                 stream_close(&f);
10700 -                               
10701 +
10702                                 return -1;
10703                         }
10704 -                       
10705 +
10706                         /* get pointers to the fields */
10707 -                       u_len = f_realm - f_user; 
10708 +                       u_len = f_realm - f_user;
10709                         f_realm++;
10710                         r_len = f_pwd - f_realm;
10711                         f_pwd++;
10712 -                       
10713 +
10714                         if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
10715                                 pwd_len = e - f_pwd;
10716                         } else {
10717                                 pwd_len = f.size - (f_pwd - f.start);
10718                         }
10719 -                       
10720 +
10721                         if (username->used - 1 == u_len &&
10722                             (realm->used - 1 == r_len) &&
10723                             (0 == strncmp(username->ptr, f_user, u_len)) &&
10724                             (0 == strncmp(realm->ptr, f_realm, r_len))) {
10725                                 /* found */
10726 -                               
10727 +
10728                                 buffer_copy_string_len(password, f_pwd, pwd_len);
10729 -                               
10730 +
10731                                 ret = 0;
10732                                 break;
10733                         }
10734 -                       
10735 +
10736                         /* EOL */
10737                         if (!e) break;
10738 -                       
10739 +
10740                         f_line = e + 1;
10741                 }
10742 -               
10743 +
10744                 stream_close(&f);
10745         } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD ||
10746                    p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
10747                 stream f;
10748                 char * f_line;
10749                 buffer *auth_fn;
10750 -               
10751 +
10752                 auth_fn = (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) ? p->conf.auth_htpasswd_userfile : p->conf.auth_plain_userfile;
10753 -               
10754 +
10755                 if (buffer_is_empty(auth_fn)) return -1;
10756 -               
10757 +
10758                 if (0 != stream_open(&f, auth_fn)) {
10759 -                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
10760 +                       log_error_write(srv, __FILE__, __LINE__, "sbss",
10761                                         "opening plain-userfile", auth_fn, "failed:", strerror(errno));
10762 -                       
10763 +
10764                         return -1;
10765                 }
10766 -               
10767 +
10768                 f_line = f.start;
10769 -               
10770 +
10771                 while (f_line - f.start != f.size) {
10772                         char *f_user, *f_pwd, *e;
10773                         size_t u_len, pwd_len;
10774 -                       
10775 +
10776                         f_user = f_line;
10777 -                       
10778 -                       /* 
10779 +
10780 +                       /*
10781                          * htpasswd format
10782 -                        * 
10783 +                        *
10784                          * user:crypted passwd
10785                          */
10786 -                       
10787 +
10788                         if (NULL == (f_pwd = memchr(f_user, ':', f.size - (f_user - f.start) ))) {
10789 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
10790 -                                               "parsed error in", auth_fn, 
10791 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
10792 +                                               "parsed error in", auth_fn,
10793                                                 "expected 'username:hashed password'");
10794 -                               
10795 +
10796                                 stream_close(&f);
10797 -                               
10798 +
10799                                 return -1;
10800                         }
10801 -                       
10802 +
10803                         /* get pointers to the fields */
10804 -                       u_len = f_pwd - f_user; 
10805 +                       u_len = f_pwd - f_user;
10806                         f_pwd++;
10807 -                       
10808 +
10809                         if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
10810                                 pwd_len = e - f_pwd;
10811                         } else {
10812                                 pwd_len = f.size - (f_pwd - f.start);
10813                         }
10814 -                       
10815 +
10816                         if (username->used - 1 == u_len &&
10817                             (0 == strncmp(username->ptr, f_user, u_len))) {
10818                                 /* found */
10819 -                               
10820 +
10821                                 buffer_copy_string_len(password, f_pwd, pwd_len);
10822 -                               
10823 +
10824                                 ret = 0;
10825                                 break;
10826                         }
10827 -                       
10828 +
10829                         /* EOL */
10830                         if (!e) break;
10831 -                       
10832 +
10833                         f_line = e + 1;
10834                 }
10835 -               
10836 +
10837                 stream_close(&f);
10838         } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
10839                 ret = 0;
10840         } else {
10841                 return -1;
10842         }
10843 -       
10844 +
10845         return ret;
10846  }
10847  
10848 @@ -296,7 +286,7 @@
10849         int username_len;
10850         data_string *require;
10851         array *req;
10852 -       
10853 +
10854         UNUSED(group);
10855         UNUSED(host);
10856  
10857 @@ -304,12 +294,12 @@
10858         /* search auth-directives for path */
10859         for (i = 0; i < p->conf.auth_require->used; i++) {
10860                 if (p->conf.auth_require->data[i]->key->used == 0) continue;
10861 -               
10862 +
10863                 if (0 == strncmp(url, p->conf.auth_require->data[i]->key->ptr, p->conf.auth_require->data[i]->key->used - 1)) {
10864                         break;
10865                 }
10866         }
10867 -       
10868 +
10869         if (i == p->conf.auth_require->used) {
10870                 return -1;
10871         }
10872 @@ -317,72 +307,72 @@
10873         req = ((data_array *)(p->conf.auth_require->data[i]))->value;
10874  
10875         require = (data_string *)array_get_element(req, "require");
10876 -       
10877 +
10878         /* if we get here, the user we got a authed user */
10879 -       if (0 == strcmp(require->value->ptr, "valid-user")) {
10880 +       if (buffer_is_equal_string(require->value, CONST_STR_LEN("valid-user"))) {
10881                 return 0;
10882         }
10883 -       
10884 +
10885         /* user=name1|group=name3|host=name4 */
10886 -       
10887 +
10888         /* seperate the string by | */
10889  #if 0
10890         log_error_write(srv, __FILE__, __LINE__, "sb", "rules", require->value);
10891 -#endif 
10892 -       
10893 +#endif
10894 +
10895         username_len = username ? strlen(username) : 0;
10896 -       
10897 +
10898         r = rules = require->value->ptr;
10899 -       
10900 +
10901         while (1) {
10902                 const char *eq;
10903                 const char *k, *v, *e;
10904                 int k_len, v_len, r_len;
10905 -               
10906 +
10907                 e = strchr(r, '|');
10908 -               
10909 +
10910                 if (e) {
10911                         r_len = e - r;
10912                 } else {
10913                         r_len = strlen(rules) - (r - rules);
10914                 }
10915 -               
10916 +
10917                 /* from r to r + r_len is a rule */
10918 -               
10919 +
10920                 if (0 == strncmp(r, "valid-user", r_len)) {
10921 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
10922 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
10923                                         "parsing the 'require' section in 'auth.require' failed: valid-user cannot be combined with other require rules",
10924                                         require->value);
10925                         return -1;
10926                 }
10927 -               
10928 +
10929                 /* search for = in the rules */
10930                 if (NULL == (eq = strchr(r, '='))) {
10931 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
10932 -                                       "parsing the 'require' section in 'auth.require' failed: a = is missing", 
10933 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
10934 +                                       "parsing the 'require' section in 'auth.require' failed: a = is missing",
10935                                         require->value);
10936                         return -1;
10937                 }
10938 -               
10939 +
10940                 /* = out of range */
10941                 if (eq > r + r_len) {
10942 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
10943 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
10944                                         "parsing the 'require' section in 'auth.require' failed: = out of range",
10945                                         require->value);
10946 -                       
10947 +
10948                         return -1;
10949                 }
10950 -               
10951 +
10952                 /* the part before the = is user|group|host */
10953 -               
10954 +
10955                 k = r;
10956                 k_len = eq - r;
10957                 v = eq + 1;
10958                 v_len = r_len - k_len - 1;
10959 -               
10960 +
10961                 if (k_len == 4) {
10962                         if (0 == strncmp(k, "user", k_len)) {
10963 -                               if (username && 
10964 +                               if (username &&
10965                                     username_len == v_len &&
10966                                     0 == strncmp(username, v, v_len)) {
10967                                         return 0;
10968 @@ -404,19 +394,19 @@
10969                         log_error_write(srv, __FILE__, __LINE__, "s", "unknown  key");
10970                         return -1;
10971                 }
10972 -               
10973 +
10974                 if (!e) break;
10975                 r = e + 1;
10976         }
10977 -       
10978 +
10979         log_error_write(srv, __FILE__, __LINE__, "s", "nothing matched");
10980 -       
10981 +
10982         return -1;
10983  }
10984  
10985  /**
10986 - * 
10987 - * 
10988 + *
10989 + *
10990   * @param password password-string from the auth-backend
10991   * @param pw       password-string from the client
10992   */
10993 @@ -426,16 +416,16 @@
10994         UNUSED(req);
10995  
10996         if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
10997 -               /* 
10998 +               /*
10999                  * htdigest format
11000 -                * 
11001 -                * user:realm:md5(user:realm:password) 
11002 +                *
11003 +                * user:realm:md5(user:realm:password)
11004                  */
11005 -               
11006 +
11007                 MD5_CTX Md5Ctx;
11008                 HASH HA1;
11009                 char a1[256];
11010 -               
11011 +
11012                 MD5_Init(&Md5Ctx);
11013                 MD5_Update(&Md5Ctx, (unsigned char *)username->ptr, username->used - 1);
11014                 MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
11015 @@ -443,24 +433,24 @@
11016                 MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
11017                 MD5_Update(&Md5Ctx, (unsigned char *)pw, strlen(pw));
11018                 MD5_Final(HA1, &Md5Ctx);
11019 -               
11020 +
11021                 CvtHex(HA1, a1);
11022 -               
11023 -               if (0 == strcmp(password->ptr, a1)) {
11024 +
11025 +               if (buffer_is_equal_string(password, a1, strlen(a1))) {
11026                         return 0;
11027                 }
11028 -       } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) { 
11029 -#ifdef HAVE_CRYPT      
11030 +       } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) {
11031 +#ifdef HAVE_CRYPT
11032                 char salt[32];
11033                 char *crypted;
11034                 size_t salt_len = 0;
11035 -               /* 
11036 +               /*
11037                  * htpasswd format
11038 -                * 
11039 +                *
11040                  * user:crypted password
11041                  */
11042  
11043 -               /* 
11044 +               /*
11045                  *  Algorithm      Salt
11046                  *  CRYPT_STD_DES   2-character (Default)
11047                  *  CRYPT_EXT_DES   9-character
11048 @@ -478,7 +468,7 @@
11049                         salt_len = 2;
11050                 } else if (password->ptr[0] == '$' && password->ptr[2] == '$') {
11051                         char *dollar = NULL;
11052 -               
11053 +
11054                         if (NULL == (dollar = strchr(password->ptr + 3, '$'))) {
11055                                 fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
11056                                 return -1;
11057 @@ -495,48 +485,21 @@
11058                 strncpy(salt, password->ptr, salt_len);
11059  
11060                 salt[salt_len] = '\0';
11061 -               
11062 +
11063                 crypted = crypt(pw, salt);
11064  
11065 -               if (0 == strcmp(password->ptr, crypted)) {
11066 +               if (buffer_is_equal_string(password, crypted, strlen(crypted))) {
11067                         return 0;
11068                 } else {
11069                         fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
11070                 }
11071 -       
11072 -#endif 
11073 -       } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) { 
11074 -               if (0 == strcmp(password->ptr, pw)) {
11075 -                       return 0;
11076 -               }
11077 -       } else if (p->conf.auth_backend == AUTH_BACKEND_PAM) { 
11078 -#ifdef USE_PAM
11079 -               pam_handle_t *pamh=NULL;
11080 -               int retval;
11081 -               
11082 -               retval = pam_start("lighttpd", username->ptr, &conv, &pamh);
11083 -               
11084 -               if (retval == PAM_SUCCESS)
11085 -                       retval = pam_authenticate(pamh, 0);    /* is user really user? */
11086 -               
11087 -               if (retval == PAM_SUCCESS)
11088 -                       retval = pam_acct_mgmt(pamh, 0);       /* permitted access? */
11089 -               
11090 -               /* This is where we have been authorized or not. */
11091 -               
11092 -               if (pam_end(pamh,retval) != PAM_SUCCESS) {     /* close Linux-PAM */
11093 -                       pamh = NULL;
11094 -                       log_error_write(srv, __FILE__, __LINE__, "s", "failed to release authenticator");
11095 -               }
11096 -               
11097 -               if (retval == PAM_SUCCESS) {
11098 -                       log_error_write(srv, __FILE__, __LINE__, "s", "Authenticated");
11099 +
11100 +#endif
11101 +       } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
11102 +               if (buffer_is_equal_string(password, pw, strlen(pw))) {
11103                         return 0;
11104 -               } else {
11105 -                       log_error_write(srv, __FILE__, __LINE__, "s", "Not Authenticated");
11106                 }
11107 -#endif
11108 -       } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) { 
11109 +       } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
11110  #ifdef USE_LDAP
11111                 LDAP *ldap;
11112                 LDAPMessage *lm, *first;
11113 @@ -544,45 +507,45 @@
11114                 int ret;
11115                 char *attrs[] = { LDAP_NO_ATTRS, NULL };
11116                 size_t i;
11117 -               
11118 +
11119                 /* for now we stay synchronous */
11120 -               
11121 -               /* 
11122 +
11123 +               /*
11124                  * 1. connect anonymously (done in plugin init)
11125                  * 2. get DN for uid = username
11126                  * 3. auth against ldap server
11127                  * 4. (optional) check a field
11128                  * 5. disconnect
11129 -                * 
11130 +                *
11131                  */
11132 -               
11133 +
11134                 /* check username
11135 -                * 
11136 +                *
11137                  * we have to protect us againt username which modifies out filter in
11138                  * a unpleasant way
11139                  */
11140 -               
11141 +
11142                 for (i = 0; i < username->used - 1; i++) {
11143                         char c = username->ptr[i];
11144 -                       
11145 +
11146                         if (!isalpha(c) &&
11147                             !isdigit(c)) {
11148 -                               
11149 -                               log_error_write(srv, __FILE__, __LINE__, "sbd", 
11150 +
11151 +                               log_error_write(srv, __FILE__, __LINE__, "sbd",
11152                                         "ldap: invalid character (a-zA-Z0-9 allowed) in username:", username, i);
11153 -                               
11154 +
11155                                 return -1;
11156                         }
11157                 }
11158 -               
11159 -               
11160 -               
11161 +
11162 +
11163 +
11164                 /* build filter */
11165                 buffer_copy_string_buffer(p->ldap_filter, p->conf.ldap_filter_pre);
11166                 buffer_append_string_buffer(p->ldap_filter, username);
11167                 buffer_append_string_buffer(p->ldap_filter, p->conf.ldap_filter_post);
11168 -               
11169 -               
11170 +
11171 +
11172                 /* 2. */
11173                 if (p->conf.ldap == NULL ||
11174                     LDAP_SUCCESS != (ret = ldap_search_s(p->conf.ldap, p->conf.auth_ldap_basedn->ptr, LDAP_SCOPE_SUBTREE, p->ldap_filter->ptr, attrs, 0, &lm))) {
11175 @@ -590,71 +553,71 @@
11176                                 return -1;
11177                         if (LDAP_SUCCESS != (ret = ldap_search_s(p->conf.ldap, p->conf.auth_ldap_basedn->ptr, LDAP_SCOPE_SUBTREE, p->ldap_filter->ptr, attrs, 0, &lm))) {
11178  
11179 -                       log_error_write(srv, __FILE__, __LINE__, "sssb", 
11180 +                       log_error_write(srv, __FILE__, __LINE__, "sssb",
11181                                         "ldap:", ldap_err2string(ret), "filter:", p->ldap_filter);
11182 -                       
11183 +
11184                         return -1;
11185                         }
11186                 }
11187 -               
11188 +
11189                 if (NULL == (first = ldap_first_entry(p->conf.ldap, lm))) {
11190                         log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
11191 -                       
11192 +
11193                         ldap_msgfree(lm);
11194 -                       
11195 +
11196                         return -1;
11197                 }
11198 -               
11199 +
11200                 if (NULL == (dn = ldap_get_dn(p->conf.ldap, first))) {
11201                         log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
11202 -                       
11203 +
11204                         ldap_msgfree(lm);
11205 -                       
11206 +
11207                         return -1;
11208                 }
11209 -               
11210 +
11211                 ldap_msgfree(lm);
11212 -               
11213 -               
11214 +
11215 +
11216                 /* 3. */
11217                 if (NULL == (ldap = ldap_init(p->conf.auth_ldap_hostname->ptr, LDAP_PORT))) {
11218                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno));
11219                         return -1;
11220                 }
11221 -               
11222 +
11223                 ret = LDAP_VERSION3;
11224                 if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) {
11225                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
11226 -                       
11227 +
11228                         ldap_unbind_s(ldap);
11229 -                       
11230 +
11231                         return -1;
11232                 }
11233 -               
11234 +
11235                 if (p->conf.auth_ldap_starttls == 1) {
11236                         if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(ldap, NULL,  NULL))) {
11237                                 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
11238 -               
11239 +
11240                                 ldap_unbind_s(ldap);
11241 -                               
11242 +
11243                                 return -1;
11244                         }
11245                 }
11246  
11247 -               
11248 +
11249                 if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(ldap, dn, pw))) {
11250                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
11251 -                       
11252 +
11253                         ldap_unbind_s(ldap);
11254 -                       
11255 +
11256                         return -1;
11257                 }
11258 -               
11259 +
11260                 /* 5. */
11261                 ldap_unbind_s(ldap);
11262 -               
11263 +
11264                 /* everything worked, good, access granted */
11265 -               
11266 +
11267                 return 0;
11268  #endif
11269         }
11270 @@ -664,65 +627,65 @@
11271  int http_auth_basic_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) {
11272         buffer *username, *password;
11273         char *pw;
11274 -       
11275 +
11276         data_string *realm;
11277 -       
11278 +
11279         realm = (data_string *)array_get_element(req, "realm");
11280 -       
11281 +
11282         username = buffer_init();
11283         password = buffer_init();
11284 -       
11285 +
11286         base64_decode(username, realm_str);
11287 -       
11288 +
11289         /* r2 == user:password */
11290         if (NULL == (pw = strchr(username->ptr, ':'))) {
11291                 buffer_free(username);
11292 -               
11293 +
11294                 log_error_write(srv, __FILE__, __LINE__, "sb", ": is missing in", username);
11295 -               
11296 +
11297                 return 0;
11298         }
11299 -       
11300 +
11301         *pw++ = '\0';
11302 -       
11303 +
11304         username->used = pw - username->ptr;
11305 -       
11306 +
11307         /* copy password to r1 */
11308         if (http_auth_get_password(srv, p, username, realm->value, password)) {
11309                 buffer_free(username);
11310                 buffer_free(password);
11311 -               
11312 +
11313                 log_error_write(srv, __FILE__, __LINE__, "s", "get_password failed");
11314 -               
11315 +
11316                 return 0;
11317         }
11318 -       
11319 +
11320         /* password doesn't match */
11321         if (http_auth_basic_password_compare(srv, p, req, username, realm->value, password, pw)) {
11322                 log_error_write(srv, __FILE__, __LINE__, "sbb", "password doesn't match for", con->uri.path, username);
11323 -               
11324 +
11325                 buffer_free(username);
11326                 buffer_free(password);
11327 -               
11328 +
11329                 return 0;
11330         }
11331 -       
11332 +
11333         /* value is our allow-rules */
11334         if (http_auth_match_rules(srv, p, url->ptr, username->ptr, NULL, NULL)) {
11335                 buffer_free(username);
11336                 buffer_free(password);
11337 -               
11338 +
11339                 log_error_write(srv, __FILE__, __LINE__, "s", "rules didn't match");
11340 -               
11341 +
11342                 return 0;
11343         }
11344 -       
11345 +
11346         /* remember the username */
11347         buffer_copy_string_buffer(p->auth_user, username);
11348 -       
11349 +
11350         buffer_free(username);
11351         buffer_free(password);
11352 -       
11353 +
11354         return 1;
11355  }
11356  
11357 @@ -735,7 +698,7 @@
11358  int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) {
11359         char a1[256];
11360         char a2[256];
11361 -       
11362 +
11363         char *username;
11364         char *realm;
11365         char *nonce;
11366 @@ -745,18 +708,18 @@
11367         char *cnonce;
11368         char *nc;
11369         char *respons;
11370 -       
11371 +
11372         char *e, *c;
11373         const char *m = NULL;
11374         int i;
11375         buffer *password, *b, *username_buf, *realm_buf;
11376 -       
11377 +
11378         MD5_CTX Md5Ctx;
11379         HASH HA1;
11380         HASH HA2;
11381         HASH RespHash;
11382         HASHHEX HA2Hex;
11383 -       
11384 +
11385  
11386         /* init pointers */
11387  #define S(x) \
11388 @@ -771,11 +734,11 @@
11389                 { S("cnonce=") },
11390                 { S("nc=") },
11391                 { S("response=") },
11392 -               
11393 +
11394                 { NULL, 0, NULL }
11395         };
11396  #undef S
11397 -       
11398 +
11399         dkv[0].ptr = &username;
11400         dkv[1].ptr = &realm;
11401         dkv[2].ptr = &nonce;
11402 @@ -786,24 +749,24 @@
11403         dkv[7].ptr = &nc;
11404         dkv[8].ptr = &respons;
11405         dkv[9].ptr = NULL;
11406 -       
11407 +
11408         UNUSED(req);
11409 -       
11410 +
11411         for (i = 0; dkv[i].key; i++) {
11412                 *(dkv[i].ptr) = NULL;
11413         }
11414 -       
11415 -       
11416 +
11417 +
11418         if (p->conf.auth_backend != AUTH_BACKEND_HTDIGEST &&
11419             p->conf.auth_backend != AUTH_BACKEND_PLAIN) {
11420 -               log_error_write(srv, __FILE__, __LINE__, "s", 
11421 +               log_error_write(srv, __FILE__, __LINE__, "s",
11422                                 "digest: unsupported backend (only htdigest or plain)");
11423 -               
11424 +
11425                 return -1;
11426         }
11427 -       
11428 +
11429         b = buffer_init_string(realm_str);
11430 -       
11431 +
11432         /* parse credentials from client */
11433         for (c = b->ptr; *c; c++) {
11434                 /* skip whitespaces */
11435 @@ -812,18 +775,18 @@
11436  
11437                 for (i = 0; dkv[i].key; i++) {
11438                         if ((0 == strncmp(c, dkv[i].key, dkv[i].key_len))) {
11439 -                               if ((c[dkv[i].key_len] == '"') && 
11440 +                               if ((c[dkv[i].key_len] == '"') &&
11441                                     (NULL != (e = strchr(c + dkv[i].key_len + 1, '"')))) {
11442                                         /* value with "..." */
11443                                         *(dkv[i].ptr) = c + dkv[i].key_len + 1;
11444                                         c = e;
11445 -       
11446 +
11447                                         *e = '\0';
11448                                 } else if (NULL != (e = strchr(c + dkv[i].key_len, ','))) {
11449                                         /* value without "...", terminated by ',' */
11450                                         *(dkv[i].ptr) = c + dkv[i].key_len;
11451                                         c = e;
11452 -                                       
11453 +
11454                                         *e = '\0';
11455                                 } else {
11456                                         /* value without "...", terminated by EOL */
11457 @@ -833,7 +796,7 @@
11458                         }
11459                 }
11460         }
11461 -       
11462 +
11463         if (p->conf.auth_debug > 1) {
11464                 log_error_write(srv, __FILE__, __LINE__, "ss", "username", username);
11465                 log_error_write(srv, __FILE__, __LINE__, "ss", "realm", realm);
11466 @@ -845,22 +808,22 @@
11467                 log_error_write(srv, __FILE__, __LINE__, "ss", "nc", nc);
11468                 log_error_write(srv, __FILE__, __LINE__, "ss", "response", respons);
11469         }
11470 -       
11471 +
11472         /* check if everything is transmitted */
11473 -       if (!username || 
11474 +       if (!username ||
11475             !realm ||
11476             !nonce ||
11477             !uri ||
11478             (qop && (!nc || !cnonce)) ||
11479             !respons ) {
11480                 /* missing field */
11481 -               
11482 -               log_error_write(srv, __FILE__, __LINE__, "s", 
11483 +
11484 +               log_error_write(srv, __FILE__, __LINE__, "s",
11485                                 "digest: missing field");
11486                 return -1;
11487         }
11488  
11489 -       m = get_http_method_name(con->request.http_method);     
11490 +       m = get_http_method_name(con->request.http_method);
11491  
11492         /* password-string == HA1 */
11493         password = buffer_init();
11494 @@ -873,10 +836,10 @@
11495                 buffer_free(realm_buf);
11496                 return 0;
11497         }
11498 -       
11499 +
11500         buffer_free(username_buf);
11501         buffer_free(realm_buf);
11502 -       
11503 +
11504         if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
11505                 /* generate password from plain-text */
11506                 MD5_Init(&Md5Ctx);
11507 @@ -890,16 +853,16 @@
11508                 /* HA1 */
11509                 /* transform the 32-byte-hex-md5 to a 16-byte-md5 */
11510                 for (i = 0; i < HASHLEN; i++) {
11511 -                       HA1[i] = hex2int(password->ptr[i*2]) << 4; 
11512 -                       HA1[i] |= hex2int(password->ptr[i*2+1]); 
11513 +                       HA1[i] = hex2int(password->ptr[i*2]) << 4;
11514 +                       HA1[i] |= hex2int(password->ptr[i*2+1]);
11515                 }
11516         } else {
11517                 /* we already check that above */
11518                 SEGFAULT();
11519         }
11520 -       
11521 +
11522         buffer_free(password);
11523 -       
11524 +
11525         if (algorithm &&
11526             strcasecmp(algorithm, "md5-sess") == 0) {
11527                 MD5_Init(&Md5Ctx);
11528 @@ -910,9 +873,9 @@
11529                 MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce));
11530                 MD5_Final(HA1, &Md5Ctx);
11531         }
11532 -       
11533 +
11534         CvtHex(HA1, a1);
11535 -       
11536 +
11537         /* calculate H(A2) */
11538         MD5_Init(&Md5Ctx);
11539         MD5_Update(&Md5Ctx, (unsigned char *)m, strlen(m));
11540 @@ -924,7 +887,7 @@
11541         }
11542         MD5_Final(HA2, &Md5Ctx);
11543         CvtHex(HA2, HA2Hex);
11544 -       
11545 +
11546         /* calculate response */
11547         MD5_Init(&Md5Ctx);
11548         MD5_Update(&Md5Ctx, (unsigned char *)a1, HASHHEXLEN);
11549 @@ -942,39 +905,39 @@
11550         MD5_Update(&Md5Ctx, (unsigned char *)HA2Hex, HASHHEXLEN);
11551         MD5_Final(RespHash, &Md5Ctx);
11552         CvtHex(RespHash, a2);
11553 -       
11554 +
11555         if (0 != strcmp(a2, respons)) {
11556                 /* digest not ok */
11557 -               
11558 +
11559                 if (p->conf.auth_debug) {
11560 -                       log_error_write(srv, __FILE__, __LINE__, "sss", 
11561 +                       log_error_write(srv, __FILE__, __LINE__, "sss",
11562                                 "digest: digest mismatch", a2, respons);
11563                 }
11564 -               
11565 -               log_error_write(srv, __FILE__, __LINE__, "sss", 
11566 +
11567 +               log_error_write(srv, __FILE__, __LINE__, "sss",
11568                                 "digest: auth failed for", username, "wrong password");
11569 -               
11570 +
11571                 buffer_free(b);
11572                 return 0;
11573         }
11574 -       
11575 +
11576         /* value is our allow-rules */
11577         if (http_auth_match_rules(srv, p, url->ptr, username, NULL, NULL)) {
11578                 buffer_free(b);
11579 -               
11580 -               log_error_write(srv, __FILE__, __LINE__, "s", 
11581 +
11582 +               log_error_write(srv, __FILE__, __LINE__, "s",
11583                                 "digest: rules did match");
11584 -               
11585 +
11586                 return 0;
11587         }
11588 -       
11589 +
11590         /* remember the username */
11591         buffer_copy_string(p->auth_user, username);
11592 -       
11593 +
11594         buffer_free(b);
11595 -       
11596 +
11597         if (p->conf.auth_debug) {
11598 -               log_error_write(srv, __FILE__, __LINE__, "s", 
11599 +               log_error_write(srv, __FILE__, __LINE__, "s",
11600                                 "digest: auth ok");
11601         }
11602         return 1;
11603 @@ -985,23 +948,23 @@
11604         HASH h;
11605         MD5_CTX Md5Ctx;
11606         char hh[32];
11607 -       
11608 +
11609         UNUSED(p);
11610  
11611         /* generate shared-secret */
11612         MD5_Init(&Md5Ctx);
11613         MD5_Update(&Md5Ctx, (unsigned char *)fn->ptr, fn->used - 1);
11614         MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
11615 -       
11616 +
11617         /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
11618         ltostr(hh, srv->cur_ts);
11619         MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
11620         ltostr(hh, rand());
11621         MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
11622 -       
11623 +
11624         MD5_Final(h, &Md5Ctx);
11625 -       
11626 +
11627         CvtHex(h, out);
11628 -       
11629 +
11630         return 0;
11631  }
11632 --- ../lighttpd-1.4.11/src/http_auth.h  2005-08-14 17:12:31.000000000 +0300
11633 +++ lighttpd-1.4.12/src/http_auth.h     2006-07-16 00:26:04.000000000 +0300
11634 @@ -9,22 +9,26 @@
11635  # include <ldap.h>
11636  #endif
11637  
11638 -typedef enum { AUTH_BACKEND_UNSET, AUTH_BACKEND_PLAIN, 
11639 -               AUTH_BACKEND_LDAP, AUTH_BACKEND_HTPASSWD, 
11640 -               AUTH_BACKEND_HTDIGEST, AUTH_BACKEND_PAM } auth_backend_t;
11641 +typedef enum {
11642 +       AUTH_BACKEND_UNSET,
11643 +       AUTH_BACKEND_PLAIN,
11644 +       AUTH_BACKEND_LDAP,
11645 +       AUTH_BACKEND_HTPASSWD,
11646 +       AUTH_BACKEND_HTDIGEST
11647 +} auth_backend_t;
11648  
11649  typedef struct {
11650         /* auth */
11651         array  *auth_require;
11652 -       
11653 +
11654         buffer *auth_plain_groupfile;
11655         buffer *auth_plain_userfile;
11656 -       
11657 +
11658         buffer *auth_htdigest_userfile;
11659         buffer *auth_htpasswd_userfile;
11660 -       
11661 +
11662         buffer *auth_backend_conf;
11663 -       
11664 +
11665         buffer *auth_ldap_hostname;
11666         buffer *auth_ldap_basedn;
11667         buffer *auth_ldap_binddn;
11668 @@ -32,15 +36,15 @@
11669         buffer *auth_ldap_filter;
11670         buffer *auth_ldap_cafile;
11671         unsigned short auth_ldap_starttls;
11672 -       
11673 +
11674         unsigned short auth_debug;
11675 -       
11676 +
11677         /* generated */
11678         auth_backend_t auth_backend;
11679 -       
11680 +
11681  #ifdef USE_LDAP
11682         LDAP *ldap;
11683 -       
11684 +
11685         buffer *ldap_filter_pre;
11686         buffer *ldap_filter_post;
11687  #endif
11688 @@ -49,15 +53,15 @@
11689  typedef struct {
11690         PLUGIN_DATA;
11691         buffer *tmp_buf;
11692 -       
11693 +
11694         buffer *auth_user;
11695  
11696  #ifdef USE_LDAP
11697         buffer *ldap_filter;
11698  #endif
11699 -       
11700 +
11701         mod_auth_plugin_config **config_storage;
11702 -       
11703 +
11704         mod_auth_plugin_config conf; /* this is only used as long as no handler_ctx is setup */
11705  } mod_auth_plugin_data;
11706  
11707 --- ../lighttpd-1.4.11/src/http_auth_digest.h   2006-01-05 00:54:01.000000000 +0200
11708 +++ lighttpd-1.4.12/src/http_auth_digest.h      2006-07-16 00:26:04.000000000 +0300
11709 @@ -12,7 +12,7 @@
11710  #ifdef USE_OPENSSL
11711  #define IN const
11712  #else
11713 -#define IN 
11714 +#define IN
11715  #endif
11716  #define OUT
11717  
11718 --- ../lighttpd-1.4.11/src/http_chunk.c 2005-08-11 01:26:50.000000000 +0300
11719 +++ lighttpd-1.4.12/src/http_chunk.c    2006-07-16 00:26:04.000000000 +0300
11720 @@ -1,7 +1,7 @@
11721  /**
11722   * the HTTP chunk-API
11723 - * 
11724 - * 
11725 + *
11726 + *
11727   */
11728  
11729  #include <sys/types.h>
11730 @@ -9,7 +9,6 @@
11731  
11732  #include <stdlib.h>
11733  #include <fcntl.h>
11734 -#include <unistd.h>
11735  
11736  #include <stdio.h>
11737  #include <errno.h>
11738 @@ -23,19 +22,19 @@
11739  static int http_chunk_append_len(server *srv, connection *con, size_t len) {
11740         size_t i, olen = len, j;
11741         buffer *b;
11742 -       
11743 +
11744         b = srv->tmp_chunk_len;
11745 -       
11746 +
11747         if (len == 0) {
11748                 buffer_copy_string(b, "0");
11749         } else {
11750                 for (i = 0; i < 8 && len; i++) {
11751                         len >>= 4;
11752                 }
11753 -               
11754 +
11755                 /* i is the number of hex digits we have */
11756                 buffer_prepare_copy(b, i + 1);
11757 -               
11758 +
11759                 for (j = i-1, len = olen; j+1 > 0; j--) {
11760                         b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10);
11761                         len >>= 4;
11762 @@ -43,61 +42,61 @@
11763                 b->used = i;
11764                 b->ptr[b->used++] = '\0';
11765         }
11766 -               
11767 +
11768         buffer_append_string(b, "\r\n");
11769         chunkqueue_append_buffer(con->write_queue, b);
11770 -       
11771 +
11772         return 0;
11773  }
11774  
11775  
11776  int http_chunk_append_file(server *srv, connection *con, buffer *fn, off_t offset, off_t len) {
11777         chunkqueue *cq;
11778 -       
11779 +
11780         if (!con) return -1;
11781 -       
11782 +
11783         cq = con->write_queue;
11784 -       
11785 +
11786         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11787                 http_chunk_append_len(srv, con, len);
11788         }
11789 -       
11790 +
11791         chunkqueue_append_file(cq, fn, offset, len);
11792 -       
11793 +
11794         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && len > 0) {
11795                 chunkqueue_append_mem(cq, "\r\n", 2 + 1);
11796         }
11797 -       
11798 +
11799         return 0;
11800  }
11801  
11802  int http_chunk_append_buffer(server *srv, connection *con, buffer *mem) {
11803         chunkqueue *cq;
11804 -       
11805 +
11806         if (!con) return -1;
11807 -       
11808 +
11809         cq = con->write_queue;
11810 -       
11811 +
11812         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11813                 http_chunk_append_len(srv, con, mem->used - 1);
11814         }
11815 -       
11816 +
11817         chunkqueue_append_buffer(cq, mem);
11818 -       
11819 +
11820         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && mem->used > 0) {
11821                 chunkqueue_append_mem(cq, "\r\n", 2 + 1);
11822         }
11823 -       
11824 +
11825         return 0;
11826  }
11827  
11828  int http_chunk_append_mem(server *srv, connection *con, const char * mem, size_t len) {
11829         chunkqueue *cq;
11830 -       
11831 +
11832         if (!con) return -1;
11833 -       
11834 +
11835         cq = con->write_queue;
11836 -       
11837 +
11838         if (len == 0) {
11839                 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11840                         http_chunk_append_len(srv, con, 0);
11841 @@ -107,17 +106,17 @@
11842                 }
11843                 return 0;
11844         }
11845 -       
11846 +
11847         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11848                 http_chunk_append_len(srv, con, len - 1);
11849         }
11850 -       
11851 +
11852         chunkqueue_append_mem(cq, mem, len);
11853 -       
11854 +
11855         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11856                 chunkqueue_append_mem(cq, "\r\n", 2 + 1);
11857         }
11858 -       
11859 +
11860         return 0;
11861  }
11862  
11863 @@ -125,9 +124,9 @@
11864  off_t http_chunkqueue_length(server *srv, connection *con) {
11865         if (!con) {
11866                 log_error_write(srv, __FILE__, __LINE__, "s", "connection is NULL!!");
11867 -               
11868 +
11869                 return 0;
11870         }
11871 -       
11872 +
11873         return chunkqueue_length(con->write_queue);
11874  }
11875 --- ../lighttpd-1.4.11/src/http_resp.c  1970-01-01 03:00:00.000000000 +0300
11876 +++ lighttpd-1.4.12/src/http_resp.c     2006-07-18 13:03:40.000000000 +0300
11877 @@ -0,0 +1,277 @@
11878 +#include <string.h>
11879 +#include <stdlib.h>
11880 +#include <stdio.h>
11881 +#include <assert.h>
11882 +
11883 +#include "log.h"
11884 +#include "http_resp.h"
11885 +#include "http_resp_parser.h"
11886 +
11887 +/* declare prototypes for the parser */
11888 +void *http_resp_parserAlloc(void *(*mallocProc)(size_t));
11889 +void http_resp_parserFree(void *p,  void (*freeProc)(void*));
11890 +void http_resp_parserTrace(FILE *TraceFILE, char *zTracePrompt);
11891 +void http_resp_parser(void *, int, buffer *, http_resp_ctx_t *);
11892 +
11893 +typedef struct {
11894 +       chunkqueue *cq;
11895 +
11896 +       chunk *c; /* current chunk in the chunkqueue */
11897 +       size_t offset; /* current offset in current chunk */
11898 +
11899 +       chunk *lookup_c;
11900 +       size_t lookup_offset;
11901 +
11902 +       int is_key;
11903 +       int is_statusline;
11904 +} http_resp_tokenizer_t;
11905 +
11906 +http_resp *http_response_init(void) {
11907 +       http_resp *resp = calloc(1, sizeof(*resp));
11908 +
11909 +       resp->reason = buffer_init();
11910 +       resp->headers = array_init();
11911 +
11912 +       return resp;
11913 +}
11914 +
11915 +void http_response_reset(http_resp *resp) {
11916 +       if (!resp) return;
11917 +
11918 +       buffer_reset(resp->reason);
11919 +       array_reset(resp->headers);
11920 +
11921 +}
11922 +
11923 +void http_response_free(http_resp *resp) {
11924 +       if (!resp) return;
11925 +
11926 +       buffer_free(resp->reason);
11927 +       array_free(resp->headers);
11928 +
11929 +       free(resp);
11930 +}
11931 +
11932 +static int http_resp_get_next_char(http_resp_tokenizer_t *t, unsigned char *c) {
11933 +       if (t->offset == t->c->mem->used - 1) {
11934 +               /* end of chunk, open next chunk */
11935 +
11936 +               if (!t->c->next) return -1;
11937 +
11938 +               t->c = t->c->next;
11939 +               t->offset = 0;
11940 +       }
11941 +
11942 +       *c = t->c->mem->ptr[t->offset++];
11943 +
11944 +       t->lookup_offset = t->offset;
11945 +       t->lookup_c = t->c;
11946 +
11947 +#if 0
11948 +       fprintf(stderr, "%s.%d: get: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->offset - 1);
11949 +#endif
11950 +
11951 +       return 0;
11952 +}
11953 +
11954 +static int http_resp_lookup_next_char(http_resp_tokenizer_t *t, unsigned char *c) {
11955 +       if (t->lookup_offset == t->lookup_c->mem->used - 1) {
11956 +               /* end of chunk, open next chunk */
11957 +
11958 +               if (!t->lookup_c->next) return -1;
11959 +
11960 +               t->lookup_c = t->lookup_c->next;
11961 +               t->lookup_offset = 0;
11962 +       }
11963 +
11964 +       *c = t->lookup_c->mem->ptr[t->lookup_offset++];
11965 +#if 0
11966 +       fprintf(stderr, "%s.%d: lookup: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->lookup_offset - 1);
11967 +#endif
11968 +
11969 +       return 0;
11970 +}
11971 +
11972 +
11973 +static int http_resp_tokenizer(
11974 +       http_resp_tokenizer_t *t,
11975 +       int *token_id,
11976 +       buffer *token
11977 +) {
11978 +       unsigned char c;
11979 +       int tid = 0;
11980 +
11981 +       /* push the token to the parser */
11982 +
11983 +       while (tid == 0 && 0 == http_resp_get_next_char(t, &c)) {
11984 +               switch (c) {
11985 +               case ':':
11986 +                       tid = TK_COLON;
11987 +
11988 +                       t->is_key = 0;
11989 +
11990 +                       break;
11991 +               case ' ':
11992 +               case '\t':
11993 +                       /* ignore WS */
11994 +
11995 +                       break;
11996 +               case '\r':
11997 +                       if (0 != http_resp_lookup_next_char(t, &c)) return -1;
11998 +
11999 +                       if (c == '\n') {
12000 +                               tid = TK_CRLF;
12001 +
12002 +                               t->c = t->lookup_c;
12003 +                               t->offset = t->lookup_offset;
12004 +
12005 +                               t->is_statusline = 0;
12006 +                               t->is_key = 1;
12007 +                       } else {
12008 +                               fprintf(stderr, "%s.%d: CR with out LF\r\n", __FILE__, __LINE__);
12009 +                               return -1;
12010 +                       }
12011 +                       break;
12012 +               case '\n':
12013 +                       tid = TK_CRLF;
12014 +
12015 +                       t->is_statusline = 0;
12016 +                       t->is_key = 1;
12017 +
12018 +                       break;
12019 +               default:
12020 +                       while (c >= 32 && c != 127 && c != 255) {
12021 +                               if (t->is_statusline) {
12022 +                                       if (c == ':') { t->is_statusline = 0; break; } /* this is not a status line by a real header */
12023 +                                       if (c == 32) break; /* the space is a splitter in the statusline */
12024 +                               } else {
12025 +                                       if (t->is_key) {
12026 +                                               if (c == ':') break; /* the : is the splitter between key and value */
12027 +                                       }
12028 +                               }
12029 +                               if (0 != http_resp_lookup_next_char(t, &c)) return -1;
12030 +                       }
12031 +
12032 +                       if (t->c == t->lookup_c &&
12033 +                               t->offset == t->lookup_offset + 1) {
12034 +
12035 +                               fprintf(stderr, "%s.%d: invalid char in string\n", __FILE__, __LINE__);
12036 +                               return -1;
12037 +                       }
12038 +
12039 +                       tid = TK_STRING;
12040 +
12041 +                       /* the lookup points to the first invalid char */
12042 +                       t->lookup_offset--;
12043 +
12044 +                       /* no overlapping string */
12045 +                       if (t->c == t->lookup_c) {
12046 +                               buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->lookup_offset - t->offset + 1);
12047 +                       } else {
12048 +                               /* first chunk */
12049 +                               buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->c->mem->used - t->offset);
12050 +
12051 +                               /* chunks in the middle */
12052 +                               for (t->c = t->c->next; t->c != t->lookup_c; t->c = t->c->next) {
12053 +                                       buffer_append_string_buffer(token, t->c->mem);
12054 +                                       t->offset = t->c->mem->used - 1;
12055 +                               }
12056 +
12057 +                               /* last chunk */
12058 +                               buffer_append_string_len(token, t->c->mem->ptr, t->lookup_offset);
12059 +                       }
12060 +
12061 +                       t->offset = t->lookup_offset;
12062 +
12063 +                       break;
12064 +               }
12065 +       }
12066 +
12067 +       if (tid) {
12068 +               *token_id = tid;
12069 +
12070 +               return 1;
12071 +       }
12072 +
12073 +       return -1;
12074 +}
12075 +
12076 +parse_status_t http_response_parse_cq(chunkqueue *cq, http_resp *resp) {
12077 +       http_resp_tokenizer_t t;
12078 +       void *pParser = NULL;
12079 +       int token_id = 0;
12080 +       buffer *token = NULL;
12081 +       http_resp_ctx_t context;
12082 +       parse_status_t ret = PARSE_UNSET;
12083 +       int last_token_id = 0;
12084 +
12085 +       t.cq = cq;
12086 +       t.c = cq->first;
12087 +       t.offset = t.c->offset;
12088 +       t.is_key = 0;
12089 +       t.is_statusline = 1;
12090 +
12091 +       context.ok = 1;
12092 +       context.errmsg = buffer_init();
12093 +       context.resp = resp;
12094 +
12095 +       pParser = http_resp_parserAlloc( malloc );
12096 +       token = buffer_init();
12097 +#if 0
12098 +       http_resp_parserTrace(stderr, "http-response: "); 
12099 +#endif
12100 +
12101 +       while((1 == http_resp_tokenizer(&t, &token_id, token)) && context.ok) {
12102 +               http_resp_parser(pParser, token_id, token, &context);
12103 +
12104 +               token = buffer_init();
12105 +
12106 +               /* CRLF CRLF ... the header end sequence */
12107 +               if (last_token_id == TK_CRLF &&
12108 +                   token_id == TK_CRLF) break;
12109 +
12110 +               last_token_id = token_id;
12111 +       }
12112 +
12113 +       /* oops, the parser failed */
12114 +       if (context.ok == 0) {
12115 +               ret = PARSE_ERROR;
12116 +
12117 +               if (!buffer_is_empty(context.errmsg)) {
12118 +                       TRACE("parsing failed: %s", BUF_STR(context.errmsg));
12119 +               } else {
12120 +                       TRACE("%s", "parsing failed ...");
12121 +               }
12122 +       }
12123 +
12124 +       http_resp_parser(pParser, 0, token, &context);
12125 +       http_resp_parserFree(pParser, free);
12126 +
12127 +       if (context.ok == 0) {
12128 +               /* we are missing the some tokens */
12129 +
12130 +               if (!buffer_is_empty(context.errmsg)) {
12131 +                       TRACE("parsing failed: %s", BUF_STR(context.errmsg));
12132 +               }
12133 +
12134 +               if (ret == PARSE_UNSET) {
12135 +                       ret = buffer_is_empty(context.errmsg) ? PARSE_NEED_MORE : PARSE_ERROR;
12136 +               }
12137 +       } else {
12138 +               chunk *c;
12139 +
12140 +               for (c = cq->first; c != t.c; c = c->next) {
12141 +                       c->offset = c->mem->used - 1;
12142 +               }
12143 +
12144 +               c->offset = t.offset;
12145 +
12146 +               ret = PARSE_SUCCESS;
12147 +       }
12148 +
12149 +       buffer_free(token);
12150 +       buffer_free(context.errmsg);
12151 +
12152 +       return ret;
12153 +}
12154 +
12155 --- ../lighttpd-1.4.11/src/http_resp.h  1970-01-01 03:00:00.000000000 +0300
12156 +++ lighttpd-1.4.12/src/http_resp.h     2006-07-16 00:26:04.000000000 +0300
12157 @@ -0,0 +1,34 @@
12158 +#ifndef _HTTP_RESP_H_
12159 +#define _HTTP_RESP_H_
12160 +
12161 +#include "array.h"
12162 +#include "chunk.h"
12163 +
12164 +typedef enum {
12165 +    PARSE_UNSET,
12166 +    PARSE_SUCCESS,
12167 +    PARSE_ERROR,
12168 +    PARSE_NEED_MORE
12169 +} parse_status_t;
12170 +
12171 +typedef struct {
12172 +    int protocol;   /* http/1.0, http/1.1 */
12173 +    int status;     /* e.g. 200 */
12174 +    buffer *reason; /* e.g. Ok */
12175 +    array *headers;
12176 +} http_resp;
12177 +
12178 +typedef struct {
12179 +       int     ok;
12180 +    buffer *errmsg;
12181 +
12182 +    http_resp *resp;
12183 +} http_resp_ctx_t;
12184 +
12185 +http_resp *http_response_init(void);
12186 +void http_response_free(http_resp *resp);
12187 +void http_response_reset(http_resp *resp);
12188 +
12189 +parse_status_t http_response_parse_cq(chunkqueue *cq, http_resp *http_response);
12190 +
12191 +#endif
12192 --- ../lighttpd-1.4.11/src/http_resp_parser.c   1970-01-01 03:00:00.000000000 +0300
12193 +++ lighttpd-1.4.12/src/http_resp_parser.c      2006-07-18 13:03:52.000000000 +0300
12194 @@ -0,0 +1,901 @@
12195 +/* Driver template for the LEMON parser generator.
12196 +** The author disclaims copyright to this source code.
12197 +*/
12198 +/* First off, code is include which follows the "include" declaration
12199 +** in the input file. */
12200 +#include <stdio.h>
12201 +#line 6 "./http_resp_parser.y"
12202 +
12203 +#include <assert.h>
12204 +#include <string.h>
12205 +#include "http_resp.h"
12206 +#include "keyvalue.h"
12207 +#include "array.h"
12208 +#include "log.h"
12209 +
12210 +#line 17 "http_resp_parser.c"
12211 +/* Next is all token values, in a form suitable for use by makeheaders.
12212 +** This section will be null unless lemon is run with the -m switch.
12213 +*/
12214 +/*
12215 +** These constants (all generated automatically by the parser generator)
12216 +** specify the various kinds of tokens (terminals) that the parser
12217 +** understands.
12218 +**
12219 +** Each symbol here is a terminal symbol in the grammar.
12220 +*/
12221 +/* Make sure the INTERFACE macro is defined.
12222 +*/
12223 +#ifndef INTERFACE
12224 +# define INTERFACE 1
12225 +#endif
12226 +/* The next thing included is series of defines which control
12227 +** various aspects of the generated parser.
12228 +**    YYCODETYPE         is the data type used for storing terminal
12229 +**                       and nonterminal numbers.  "unsigned char" is
12230 +**                       used if there are fewer than 250 terminals
12231 +**                       and nonterminals.  "int" is used otherwise.
12232 +**    YYNOCODE           is a number of type YYCODETYPE which corresponds
12233 +**                       to no legal terminal or nonterminal number.  This
12234 +**                       number is used to fill in empty slots of the hash
12235 +**                       table.
12236 +**    YYFALLBACK         If defined, this indicates that one or more tokens
12237 +**                       have fall-back values which should be used if the
12238 +**                       original value of the token will not parse.
12239 +**    YYACTIONTYPE       is the data type used for storing terminal
12240 +**                       and nonterminal numbers.  "unsigned char" is
12241 +**                       used if there are fewer than 250 rules and
12242 +**                       states combined.  "int" is used otherwise.
12243 +**    http_resp_parserTOKENTYPE     is the data type used for minor tokens given
12244 +**                       directly to the parser from the tokenizer.
12245 +**    YYMINORTYPE        is the data type used for all minor tokens.
12246 +**                       This is typically a union of many types, one of
12247 +**                       which is http_resp_parserTOKENTYPE.  The entry in the union
12248 +**                       for base tokens is called "yy0".
12249 +**    YYSTACKDEPTH       is the maximum depth of the parser's stack.
12250 +**    http_resp_parserARG_SDECL     A static variable declaration for the %extra_argument
12251 +**    http_resp_parserARG_PDECL     A parameter declaration for the %extra_argument
12252 +**    http_resp_parserARG_STORE     Code to store %extra_argument into yypParser
12253 +**    http_resp_parserARG_FETCH     Code to extract %extra_argument from yypParser
12254 +**    YYNSTATE           the combined number of states.
12255 +**    YYNRULE            the number of rules in the grammar
12256 +**    YYERRORSYMBOL      is the code number of the error symbol.  If not
12257 +**                       defined, then do no error processing.
12258 +*/
12259 +/* \ 1 */
12260 +#define YYCODETYPE unsigned char
12261 +#define YYNOCODE 12
12262 +#define YYACTIONTYPE unsigned char
12263 +#define http_resp_parserTOKENTYPE buffer *
12264 +typedef union {
12265 +  http_resp_parserTOKENTYPE yy0;
12266 +  http_resp * yy2;
12267 +  data_string * yy9;
12268 +  array * yy12;
12269 +  int yy20;
12270 +  int yy23;
12271 +} YYMINORTYPE;
12272 +#define YYSTACKDEPTH 100
12273 +#define http_resp_parserARG_SDECL http_resp_ctx_t *ctx;
12274 +#define http_resp_parserARG_PDECL ,http_resp_ctx_t *ctx
12275 +#define http_resp_parserARG_FETCH http_resp_ctx_t *ctx = yypParser->ctx
12276 +#define http_resp_parserARG_STORE yypParser->ctx = ctx
12277 +#define YYNSTATE 19
12278 +#define YYNRULE 9
12279 +#define YYERRORSYMBOL 4
12280 +#define YYERRSYMDT yy23
12281 +#define YY_NO_ACTION      (YYNSTATE+YYNRULE+2)
12282 +#define YY_ACCEPT_ACTION  (YYNSTATE+YYNRULE+1)
12283 +#define YY_ERROR_ACTION   (YYNSTATE+YYNRULE)
12284 +
12285 +/* Next are that tables used to determine what action to take based on the
12286 +** current state and lookahead token.  These tables are used to implement
12287 +** functions that take a state number and lookahead value and return an
12288 +** action integer.
12289 +**
12290 +** Suppose the action integer is N.  Then the action is determined as
12291 +** follows
12292 +**
12293 +**   0 <= N < YYNSTATE                  Shift N.  That is, push the lookahead
12294 +**                                      token onto the stack and goto state N.
12295 +**
12296 +**   YYNSTATE <= N < YYNSTATE+YYNRULE   Reduce by rule N-YYNSTATE.
12297 +**
12298 +**   N == YYNSTATE+YYNRULE              A syntax error has occurred.
12299 +**
12300 +**   N == YYNSTATE+YYNRULE+1            The parser accepts its input.
12301 +**
12302 +**   N == YYNSTATE+YYNRULE+2            No such action.  Denotes unused
12303 +**                                      slots in the yy_action[] table.
12304 +**
12305 +** The action table is constructed as a single large table named yy_action[].
12306 +** Given state S and lookahead X, the action is computed as
12307 +**
12308 +**      yy_action[ yy_shift_ofst[S] + X ]
12309 +**
12310 +** If the index value yy_shift_ofst[S]+X is out of range or if the value
12311 +** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
12312 +** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
12313 +** and that yy_default[S] should be used instead.
12314 +**
12315 +** The formula above is for computing the action when the lookahead is
12316 +** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
12317 +** a reduce action) then the yy_reduce_ofst[] array is used in place of
12318 +** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
12319 +** YY_SHIFT_USE_DFLT.
12320 +**
12321 +** The following are the tables generated in this section:
12322 +**
12323 +**  yy_action[]        A single table containing all actions.
12324 +**  yy_lookahead[]     A table containing the lookahead for each entry in
12325 +**                     yy_action.  Used to detect hash collisions.
12326 +**  yy_shift_ofst[]    For each state, the offset into yy_action for
12327 +**                     shifting terminals.
12328 +**  yy_reduce_ofst[]   For each state, the offset into yy_action for
12329 +**                     shifting non-terminals after a reduce.
12330 +**  yy_default[]       Default action for each state.
12331 +*/
12332 +static YYACTIONTYPE yy_action[] = {
12333 + /*     0 */     8,   29,   18,    1,   14,    2,    4,   11,   15,   12,
12334 + /*    10 */    14,   13,    4,   21,    5,   19,    3,    5,    6,    7,
12335 + /*    20 */     9,   17,   16,    4,   20,   22,   22,   10,
12336 +};
12337 +static YYCODETYPE yy_lookahead[] = {
12338 + /*     0 */     5,    6,    2,    8,    9,    1,    2,    1,    2,    8,
12339 + /*    10 */     9,    1,    2,    2,    3,    0,    9,    3,    2,    1,
12340 + /*    20 */     7,    2,    2,    2,    0,    2,   11,   10,
12341 +};
12342 +#define YY_SHIFT_USE_DFLT (-1)
12343 +static signed char yy_shift_ofst[] = {
12344 + /*     0 */     0,    4,   15,   -1,   14,   16,   18,   -1,   19,   20,
12345 + /*    10 */     6,   21,   10,   24,   -1,   -1,   -1,   23,   11,
12346 +};
12347 +#define YY_REDUCE_USE_DFLT (-6)
12348 +static signed char yy_reduce_ofst[] = {
12349 + /*     0 */    -5,    7,   -6,   -6,   -6,   -6,   -6,   -6,   13,   17,
12350 + /*    10 */    -6,    1,    7,   -6,   -6,   -6,   -6,   -6,   -6,
12351 +};
12352 +static YYACTIONTYPE yy_default[] = {
12353 + /*     0 */    28,   28,   28,   25,   28,   28,   28,   27,   28,   28,
12354 + /*    10 */    28,   28,   28,   28,   26,   24,   23,   28,   28,
12355 +};
12356 +#define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
12357 +
12358 +/* The next table maps tokens into fallback tokens.  If a construct
12359 +** like the following:
12360 +**
12361 +**      %fallback ID X Y Z.
12362 +**
12363 +** appears in the grammer, then ID becomes a fallback token for X, Y,
12364 +** and Z.  Whenever one of the tokens X, Y, or Z is input to the parser
12365 +** but it does not parse, the type of the token is changed to ID and
12366 +** the parse is retried before an error is thrown.
12367 +*/
12368 +#ifdef YYFALLBACK
12369 +static const YYCODETYPE yyFallback[] = {
12370 +};
12371 +#endif /* YYFALLBACK */
12372 +
12373 +/* The following structure represents a single element of the
12374 +** parser's stack.  Information stored includes:
12375 +**
12376 +**   +  The state number for the parser at this level of the stack.
12377 +**
12378 +**   +  The value of the token stored at this level of the stack.
12379 +**      (In other words, the "major" token.)
12380 +**
12381 +**   +  The semantic value stored at this level of the stack.  This is
12382 +**      the information used by the action routines in the grammar.
12383 +**      It is sometimes called the "minor" token.
12384 +*/
12385 +struct yyStackEntry {
12386 +  int stateno;       /* The state-number */
12387 +  int major;         /* The major token value.  This is the code
12388 +                     ** number for the token at this stack level */
12389 +  YYMINORTYPE minor; /* The user-supplied minor token value.  This
12390 +                     ** is the value of the token  */
12391 +};
12392 +typedef struct yyStackEntry yyStackEntry;
12393 +
12394 +/* The state of the parser is completely contained in an instance of
12395 +** the following structure */
12396 +struct yyParser {
12397 +  int yyidx;                    /* Index of top element in stack */
12398 +  int yyerrcnt;                 /* Shifts left before out of the error */
12399 +  http_resp_parserARG_SDECL                /* A place to hold %extra_argument */
12400 +  yyStackEntry yystack[YYSTACKDEPTH];  /* The parser's stack */
12401 +};
12402 +typedef struct yyParser yyParser;
12403 +
12404 +#ifndef NDEBUG
12405 +#include <stdio.h>
12406 +static FILE *yyTraceFILE = 0;
12407 +static char *yyTracePrompt = 0;
12408 +#endif /* NDEBUG */
12409 +
12410 +#ifndef NDEBUG
12411 +/*
12412 +** Turn parser tracing on by giving a stream to which to write the trace
12413 +** and a prompt to preface each trace message.  Tracing is turned off
12414 +** by making either argument NULL
12415 +**
12416 +** Inputs:
12417 +** <ul>
12418 +** <li> A FILE* to which trace output should be written.
12419 +**      If NULL, then tracing is turned off.
12420 +** <li> A prefix string written at the beginning of every
12421 +**      line of trace output.  If NULL, then tracing is
12422 +**      turned off.
12423 +** </ul>
12424 +**
12425 +** Outputs:
12426 +** None.
12427 +*/
12428 +void http_resp_parserTrace(FILE *TraceFILE, char *zTracePrompt){
12429 +  yyTraceFILE = TraceFILE;
12430 +  yyTracePrompt = zTracePrompt;
12431 +  if( yyTraceFILE==0 ) yyTracePrompt = 0;
12432 +  else if( yyTracePrompt==0 ) yyTraceFILE = 0;
12433 +}
12434 +#endif /* NDEBUG */
12435 +
12436 +#ifndef NDEBUG
12437 +/* For tracing shifts, the names of all terminals and nonterminals
12438 +** are required.  The following table supplies these names */
12439 +static const char *yyTokenName[] = {
12440 +  "$",             "CRLF",          "STRING",        "COLON",       
12441 +  "error",         "protocol",      "response_hdr",  "number",      
12442 +  "headers",       "header",        "reason",      
12443 +};
12444 +#endif /* NDEBUG */
12445 +
12446 +#ifndef NDEBUG
12447 +/* For tracing reduce actions, the names of all rules are required.
12448 +*/
12449 +static const char *yyRuleName[] = {
12450 + /*   0 */ "response_hdr ::= headers CRLF",
12451 + /*   1 */ "response_hdr ::= protocol number reason CRLF headers CRLF",
12452 + /*   2 */ "protocol ::= STRING",
12453 + /*   3 */ "number ::= STRING",
12454 + /*   4 */ "reason ::= STRING",
12455 + /*   5 */ "reason ::= reason STRING",
12456 + /*   6 */ "headers ::= headers header",
12457 + /*   7 */ "headers ::= header",
12458 + /*   8 */ "header ::= STRING COLON STRING CRLF",
12459 +};
12460 +#endif /* NDEBUG */
12461 +
12462 +/*
12463 +** This function returns the symbolic name associated with a token
12464 +** value.
12465 +*/
12466 +const char *http_resp_parserTokenName(int tokenType){
12467 +#ifndef NDEBUG
12468 +  if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
12469 +    return yyTokenName[tokenType];
12470 +  }else{
12471 +    return "Unknown";
12472 +  }
12473 +#else
12474 +  return "";
12475 +#endif
12476 +}
12477 +
12478 +/*
12479 +** This function allocates a new parser.
12480 +** The only argument is a pointer to a function which works like
12481 +** malloc.
12482 +**
12483 +** Inputs:
12484 +** A pointer to the function used to allocate memory.
12485 +**
12486 +** Outputs:
12487 +** A pointer to a parser.  This pointer is used in subsequent calls
12488 +** to http_resp_parser and http_resp_parserFree.
12489 +*/
12490 +void *http_resp_parserAlloc(void *(*mallocProc)(size_t)){
12491 +  yyParser *pParser;
12492 +  pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
12493 +  if( pParser ){
12494 +    pParser->yyidx = -1;
12495 +  }
12496 +  return pParser;
12497 +}
12498 +
12499 +/* The following function deletes the value associated with a
12500 +** symbol.  The symbol can be either a terminal or nonterminal.
12501 +** "yymajor" is the symbol code, and "yypminor" is a pointer to
12502 +** the value.
12503 +*/
12504 +static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
12505 +  switch( yymajor ){
12506 +    /* Here is inserted the actions which take place when a
12507 +    ** terminal or non-terminal is destroyed.  This can happen
12508 +    ** when the symbol is popped from the stack during a
12509 +    ** reduce or during error processing or when a parser is
12510 +    ** being destroyed before it is finished parsing.
12511 +    **
12512 +    ** Note: during a reduce, the only symbols destroyed are those
12513 +    ** which appear on the RHS of the rule, but which are not used
12514 +    ** inside the C code.
12515 +    */
12516 +    case 1:
12517 +    case 2:
12518 +    case 3:
12519 +#line 25 "./http_resp_parser.y"
12520 +{ buffer_free((yypminor->yy0)); }
12521 +#line 327 "http_resp_parser.c"
12522 +      break;
12523 +    case 10:
12524 +#line 24 "./http_resp_parser.y"
12525 +{ buffer_free((yypminor->yy0)); }
12526 +#line 332 "http_resp_parser.c"
12527 +      break;
12528 +    default:  break;   /* If no destructor action specified: do nothing */
12529 +  }
12530 +}
12531 +
12532 +/*
12533 +** Pop the parser's stack once.
12534 +**
12535 +** If there is a destructor routine associated with the token which
12536 +** is popped from the stack, then call it.
12537 +**
12538 +** Return the major token number for the symbol popped.
12539 +*/
12540 +static int yy_pop_parser_stack(yyParser *pParser){
12541 +  YYCODETYPE yymajor;
12542 +  yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
12543 +
12544 +  if( pParser->yyidx<0 ) return 0;
12545 +#ifndef NDEBUG
12546 +  if( yyTraceFILE && pParser->yyidx>=0 ){
12547 +    fprintf(yyTraceFILE,"%sPopping %s\n",
12548 +      yyTracePrompt,
12549 +      yyTokenName[yytos->major]);
12550 +  }
12551 +#endif
12552 +  yymajor = yytos->major;
12553 +  yy_destructor( yymajor, &yytos->minor);
12554 +  pParser->yyidx--;
12555 +  return yymajor;
12556 +}
12557 +
12558 +/*
12559 +** Deallocate and destroy a parser.  Destructors are all called for
12560 +** all stack elements before shutting the parser down.
12561 +**
12562 +** Inputs:
12563 +** <ul>
12564 +** <li>  A pointer to the parser.  This should be a pointer
12565 +**       obtained from http_resp_parserAlloc.
12566 +** <li>  A pointer to a function used to reclaim memory obtained
12567 +**       from malloc.
12568 +** </ul>
12569 +*/
12570 +void http_resp_parserFree(
12571 +  void *p,                    /* The parser to be deleted */
12572 +  void (*freeProc)(void*)     /* Function used to reclaim memory */
12573 +){
12574 +  yyParser *pParser = (yyParser*)p;
12575 +  if( pParser==0 ) return;
12576 +  while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
12577 +  (*freeProc)((void*)pParser);
12578 +}
12579 +
12580 +/*
12581 +** Find the appropriate action for a parser given the terminal
12582 +** look-ahead token iLookAhead.
12583 +**
12584 +** If the look-ahead token is YYNOCODE, then check to see if the action is
12585 +** independent of the look-ahead.  If it is, return the action, otherwise
12586 +** return YY_NO_ACTION.
12587 +*/
12588 +static int yy_find_shift_action(
12589 +  yyParser *pParser,        /* The parser */
12590 +  int iLookAhead            /* The look-ahead token */
12591 +){
12592 +  int i;
12593 +  int stateno = pParser->yystack[pParser->yyidx].stateno;
12594 +
12595 +  /* if( pParser->yyidx<0 ) return YY_NO_ACTION;  */
12596 +  i = yy_shift_ofst[stateno];
12597 +  if( i==YY_SHIFT_USE_DFLT ){
12598 +    return yy_default[stateno];
12599 +  }
12600 +  if( iLookAhead==YYNOCODE ){
12601 +    return YY_NO_ACTION;
12602 +  }
12603 +  i += iLookAhead;
12604 +  if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
12605 +#ifdef YYFALLBACK
12606 +    int iFallback;            /* Fallback token */
12607 +    if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
12608 +           && (iFallback = yyFallback[iLookAhead])!=0 ){
12609 +#ifndef NDEBUG
12610 +      if( yyTraceFILE ){
12611 +        fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
12612 +           yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
12613 +      }
12614 +#endif
12615 +      return yy_find_shift_action(pParser, iFallback);
12616 +    }
12617 +#endif
12618 +    return yy_default[stateno];
12619 +  }else{
12620 +    return yy_action[i];
12621 +  }
12622 +}
12623 +
12624 +/*
12625 +** Find the appropriate action for a parser given the non-terminal
12626 +** look-ahead token iLookAhead.
12627 +**
12628 +** If the look-ahead token is YYNOCODE, then check to see if the action is
12629 +** independent of the look-ahead.  If it is, return the action, otherwise
12630 +** return YY_NO_ACTION.
12631 +*/
12632 +static int yy_find_reduce_action(
12633 +  yyParser *pParser,        /* The parser */
12634 +  int iLookAhead            /* The look-ahead token */
12635 +){
12636 +  int i;
12637 +  int stateno = pParser->yystack[pParser->yyidx].stateno;
12638 +
12639 +  i = yy_reduce_ofst[stateno];
12640 +  if( i==YY_REDUCE_USE_DFLT ){
12641 +    return yy_default[stateno];
12642 +  }
12643 +  if( iLookAhead==YYNOCODE ){
12644 +    return YY_NO_ACTION;
12645 +  }
12646 +  i += iLookAhead;
12647 +  if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
12648 +    return yy_default[stateno];
12649 +  }else{
12650 +    return yy_action[i];
12651 +  }
12652 +}
12653 +
12654 +/*
12655 +** Perform a shift action.
12656 +*/
12657 +static void yy_shift(
12658 +  yyParser *yypParser,          /* The parser to be shifted */
12659 +  int yyNewState,               /* The new state to shift in */
12660 +  int yyMajor,                  /* The major token to shift in */
12661 +  YYMINORTYPE *yypMinor         /* Pointer ot the minor token to shift in */
12662 +){
12663 +  yyStackEntry *yytos;
12664 +  yypParser->yyidx++;
12665 +  if( yypParser->yyidx>=YYSTACKDEPTH ){
12666 +     http_resp_parserARG_FETCH;
12667 +     yypParser->yyidx--;
12668 +#ifndef NDEBUG
12669 +     if( yyTraceFILE ){
12670 +       fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
12671 +     }
12672 +#endif
12673 +     while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
12674 +     /* Here code is inserted which will execute if the parser
12675 +     ** stack every overflows */
12676 +     http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument var */
12677 +     return;
12678 +  }
12679 +  yytos = &yypParser->yystack[yypParser->yyidx];
12680 +  yytos->stateno = yyNewState;
12681 +  yytos->major = yyMajor;
12682 +  yytos->minor = *yypMinor;
12683 +#ifndef NDEBUG
12684 +  if( yyTraceFILE && yypParser->yyidx>0 ){
12685 +    int i;
12686 +    fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
12687 +    fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
12688 +    for(i=1; i<=yypParser->yyidx; i++)
12689 +      fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
12690 +    fprintf(yyTraceFILE,"\n");
12691 +  }
12692 +#endif
12693 +}
12694 +
12695 +/* The following table contains information about every rule that
12696 +** is used during the reduce.
12697 +*/
12698 +static struct {
12699 +  YYCODETYPE lhs;         /* Symbol on the left-hand side of the rule */
12700 +  unsigned char nrhs;     /* Number of right-hand side symbols in the rule */
12701 +} yyRuleInfo[] = {
12702 +  { 6, 2 },
12703 +  { 6, 6 },
12704 +  { 5, 1 },
12705 +  { 7, 1 },
12706 +  { 10, 1 },
12707 +  { 10, 2 },
12708 +  { 8, 2 },
12709 +  { 8, 1 },
12710 +  { 9, 4 },
12711 +};
12712 +
12713 +static void yy_accept(yyParser*);  /* Forward Declaration */
12714 +
12715 +/*
12716 +** Perform a reduce action and the shift that must immediately
12717 +** follow the reduce.
12718 +*/
12719 +static void yy_reduce(
12720 +  yyParser *yypParser,         /* The parser */
12721 +  int yyruleno                 /* Number of the rule by which to reduce */
12722 +){
12723 +  int yygoto;                     /* The next state */
12724 +  int yyact;                      /* The next action */
12725 +  YYMINORTYPE yygotominor;        /* The LHS of the rule reduced */
12726 +  yyStackEntry *yymsp;            /* The top of the parser's stack */
12727 +  int yysize;                     /* Amount to pop the stack */
12728 +  http_resp_parserARG_FETCH;
12729 +  yymsp = &yypParser->yystack[yypParser->yyidx];
12730 +#ifndef NDEBUG
12731 +  if( yyTraceFILE && yyruleno>=0
12732 +        && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
12733 +    fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
12734 +      yyRuleName[yyruleno]);
12735 +  }
12736 +#endif /* NDEBUG */
12737 +
12738 +  switch( yyruleno ){
12739 +  /* Beginning here are the reduction cases.  A typical example
12740 +  ** follows:
12741 +  **   case 0:
12742 +  **  #line <lineno> <grammarfile>
12743 +  **     { ... }           // User supplied code
12744 +  **  #line <lineno> <thisfile>
12745 +  **     break;
12746 +  */
12747 +      case 0:
12748 +#line 28 "./http_resp_parser.y"
12749 +{
12750 +    http_resp *resp = ctx->resp;
12751 +    data_string *ds;
12752
12753 +    resp->protocol = HTTP_VERSION_UNSET;
12754 +
12755 +    buffer_copy_string(resp->reason, ""); /* no reason */
12756 +    array_free(resp->headers);
12757 +    resp->headers = yymsp[-1].minor.yy12;
12758 +
12759 +    if (NULL == (ds = (data_string *)array_get_element(yymsp[-1].minor.yy12, "Status"))) { 
12760 +        resp->status = 0;
12761 +    } else {
12762 +        char *err;
12763 +        resp->status = strtol(ds->value->ptr, &err, 10);
12764 +   
12765 +        if (*err != '\0' && *err != ' ') {
12766 +            buffer_copy_string(ctx->errmsg, "expected a number: ");
12767 +            buffer_append_string_buffer(ctx->errmsg, ds->value);
12768 +            buffer_append_string(ctx->errmsg, err);
12769 +        
12770 +            ctx->ok = 0;
12771 +        }
12772 +    }
12773 +
12774 +    yymsp[-1].minor.yy12 = NULL;
12775 +}
12776 +#line 582 "http_resp_parser.c"
12777 +  yy_destructor(1,&yymsp[0].minor);
12778 +        break;
12779 +      case 1:
12780 +#line 56 "./http_resp_parser.y"
12781 +{
12782 +    http_resp *resp = ctx->resp;
12783 +    
12784 +    resp->status = yymsp[-4].minor.yy20;
12785 +    resp->protocol = yymsp[-5].minor.yy20;
12786 +    buffer_copy_string_buffer(resp->reason, yymsp[-3].minor.yy0);
12787 +    buffer_free(yymsp[-3].minor.yy0); 
12788 +
12789 +    array_free(resp->headers);
12790 +    
12791 +    resp->headers = yymsp[-1].minor.yy12;
12792 +}
12793 +#line 599 "http_resp_parser.c"
12794 +  yy_destructor(1,&yymsp[-2].minor);
12795 +  yy_destructor(1,&yymsp[0].minor);
12796 +        break;
12797 +      case 2:
12798 +#line 69 "./http_resp_parser.y"
12799 +{
12800 +    if (buffer_is_equal_string(yymsp[0].minor.yy0, CONST_STR_LEN("HTTP/1.0"))) {
12801 +        yygotominor.yy20 = HTTP_VERSION_1_0;
12802 +    } else if (buffer_is_equal_string(yymsp[0].minor.yy0, CONST_STR_LEN("HTTP/1.1"))) {
12803 +        yygotominor.yy20 = HTTP_VERSION_1_1;
12804 +    } else {
12805 +        buffer_copy_string(ctx->errmsg, "unknown protocol: ");
12806 +        buffer_append_string_buffer(ctx->errmsg, yymsp[0].minor.yy0);
12807 +        
12808 +        ctx->ok = 0;
12809 +    }
12810 +    buffer_free(yymsp[0].minor.yy0);
12811 +}
12812 +#line 618 "http_resp_parser.c"
12813 +        break;
12814 +      case 3:
12815 +#line 83 "./http_resp_parser.y"
12816 +{
12817 +    char *err;
12818 +    yygotominor.yy20 = strtol(yymsp[0].minor.yy0->ptr, &err, 10);
12819 +    
12820 +    if (*err != '\0') {
12821 +        buffer_copy_string(ctx->errmsg, "expected a number, got: ");
12822 +        buffer_append_string_buffer(ctx->errmsg, yymsp[0].minor.yy0);
12823 +        
12824 +        ctx->ok = 0;
12825 +    }
12826 +    buffer_free(yymsp[0].minor.yy0);
12827 +}
12828 +#line 634 "http_resp_parser.c"
12829 +        break;
12830 +      case 4:
12831 +#line 96 "./http_resp_parser.y"
12832 +{
12833 +    yygotominor.yy0 = yymsp[0].minor.yy0;
12834 +}
12835 +#line 641 "http_resp_parser.c"
12836 +        break;
12837 +      case 5:
12838 +#line 100 "./http_resp_parser.y"
12839 +{
12840 +    yygotominor.yy0 = yymsp[-1].minor.yy0;
12841 +    
12842 +    buffer_append_string(yygotominor.yy0, " ");
12843 +    buffer_append_string_buffer(yygotominor.yy0, yymsp[0].minor.yy0);
12844 +
12845 +    buffer_free(yymsp[0].minor.yy0); 
12846 +}
12847 +#line 653 "http_resp_parser.c"
12848 +        break;
12849 +      case 6:
12850 +#line 109 "./http_resp_parser.y"
12851 +{
12852 +    yygotominor.yy12 = yymsp[-1].minor.yy12;
12853 +    
12854 +    array_insert_unique(yygotominor.yy12, (data_unset *)yymsp[0].minor.yy9);
12855 +}
12856 +#line 662 "http_resp_parser.c"
12857 +        break;
12858 +      case 7:
12859 +#line 115 "./http_resp_parser.y"
12860 +{
12861 +    yygotominor.yy12 = array_init();
12862 +
12863 +    array_insert_unique(yygotominor.yy12, (data_unset *)yymsp[0].minor.yy9);
12864 +}
12865 +#line 671 "http_resp_parser.c"
12866 +        break;
12867 +      case 8:
12868 +#line 120 "./http_resp_parser.y"
12869 +{
12870 +    yygotominor.yy9 = data_string_init();
12871 +    
12872 +    buffer_copy_string_buffer(yygotominor.yy9->key, yymsp[-3].minor.yy0);
12873 +    buffer_copy_string_buffer(yygotominor.yy9->value, yymsp[-1].minor.yy0);    
12874 +    buffer_free(yymsp[-3].minor.yy0);
12875 +    buffer_free(yymsp[-1].minor.yy0);
12876 +}
12877 +#line 683 "http_resp_parser.c"
12878 +  yy_destructor(3,&yymsp[-2].minor);
12879 +  yy_destructor(1,&yymsp[0].minor);
12880 +        break;
12881 +  };
12882 +  yygoto = yyRuleInfo[yyruleno].lhs;
12883 +  yysize = yyRuleInfo[yyruleno].nrhs;
12884 +  yypParser->yyidx -= yysize;
12885 +  yyact = yy_find_reduce_action(yypParser,yygoto);
12886 +  if( yyact < YYNSTATE ){
12887 +    yy_shift(yypParser,yyact,yygoto,&yygotominor);
12888 +  }else if( yyact == YYNSTATE + YYNRULE + 1 ){
12889 +    yy_accept(yypParser);
12890 +  }
12891 +}
12892 +
12893 +/*
12894 +** The following code executes when the parse fails
12895 +*/
12896 +static void yy_parse_failed(
12897 +  yyParser *yypParser           /* The parser */
12898 +){
12899 +  http_resp_parserARG_FETCH;
12900 +#ifndef NDEBUG
12901 +  if( yyTraceFILE ){
12902 +    fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
12903 +  }
12904 +#endif
12905 +  while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
12906 +  /* Here code is inserted which will be executed whenever the
12907 +  ** parser fails */
12908 +#line 15 "./http_resp_parser.y"
12909 +
12910 +  ctx->ok = 0;
12911 +
12912 +#line 718 "http_resp_parser.c"
12913 +  http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
12914 +}
12915 +
12916 +/*
12917 +** The following code executes when a syntax error first occurs.
12918 +*/
12919 +static void yy_syntax_error(
12920 +  yyParser *yypParser,           /* The parser */
12921 +  int yymajor,                   /* The major type of the error token */
12922 +  YYMINORTYPE yyminor            /* The minor type of the error token */
12923 +){
12924 +  http_resp_parserARG_FETCH;
12925 +#define TOKEN (yyminor.yy0)
12926 +  http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
12927 +}
12928 +
12929 +/*
12930 +** The following is executed when the parser accepts
12931 +*/
12932 +static void yy_accept(
12933 +  yyParser *yypParser           /* The parser */
12934 +){
12935 +  http_resp_parserARG_FETCH;
12936 +#ifndef NDEBUG
12937 +  if( yyTraceFILE ){
12938 +    fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
12939 +  }
12940 +#endif
12941 +  while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
12942 +  /* Here code is inserted which will be executed whenever the
12943 +  ** parser accepts */
12944 +  http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
12945 +}
12946 +
12947 +/* The main parser program.
12948 +** The first argument is a pointer to a structure obtained from
12949 +** "http_resp_parserAlloc" which describes the current state of the parser.
12950 +** The second argument is the major token number.  The third is
12951 +** the minor token.  The fourth optional argument is whatever the
12952 +** user wants (and specified in the grammar) and is available for
12953 +** use by the action routines.
12954 +**
12955 +** Inputs:
12956 +** <ul>
12957 +** <li> A pointer to the parser (an opaque structure.)
12958 +** <li> The major token number.
12959 +** <li> The minor token number.
12960 +** <li> An option argument of a grammar-specified type.
12961 +** </ul>
12962 +**
12963 +** Outputs:
12964 +** None.
12965 +*/
12966 +void http_resp_parser(
12967 +  void *yyp,                   /* The parser */
12968 +  int yymajor,                 /* The major token code number */
12969 +  http_resp_parserTOKENTYPE yyminor       /* The value for the token */
12970 +  http_resp_parserARG_PDECL               /* Optional %extra_argument parameter */
12971 +){
12972 +  YYMINORTYPE yyminorunion;
12973 +  int yyact;            /* The parser action. */
12974 +  int yyendofinput;     /* True if we are at the end of input */
12975 +  int yyerrorhit = 0;   /* True if yymajor has invoked an error */
12976 +  yyParser *yypParser;  /* The parser */
12977 +
12978 +  /* (re)initialize the parser, if necessary */
12979 +  yypParser = (yyParser*)yyp;
12980 +  if( yypParser->yyidx<0 ){
12981 +    if( yymajor==0 ) return;
12982 +    yypParser->yyidx = 0;
12983 +    yypParser->yyerrcnt = -1;
12984 +    yypParser->yystack[0].stateno = 0;
12985 +    yypParser->yystack[0].major = 0;
12986 +  }
12987 +  yyminorunion.yy0 = yyminor;
12988 +  yyendofinput = (yymajor==0);
12989 +  http_resp_parserARG_STORE;
12990 +
12991 +#ifndef NDEBUG
12992 +  if( yyTraceFILE ){
12993 +    fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
12994 +  }
12995 +#endif
12996 +
12997 +  do{
12998 +    yyact = yy_find_shift_action(yypParser,yymajor);
12999 +    if( yyact<YYNSTATE ){
13000 +      yy_shift(yypParser,yyact,yymajor,&yyminorunion);
13001 +      yypParser->yyerrcnt--;
13002 +      if( yyendofinput && yypParser->yyidx>=0 ){
13003 +        yymajor = 0;
13004 +      }else{
13005 +        yymajor = YYNOCODE;
13006 +      }
13007 +    }else if( yyact < YYNSTATE + YYNRULE ){
13008 +      yy_reduce(yypParser,yyact-YYNSTATE);
13009 +    }else if( yyact == YY_ERROR_ACTION ){
13010 +      int yymx;
13011 +#ifndef NDEBUG
13012 +      if( yyTraceFILE ){
13013 +        fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
13014 +      }
13015 +#endif
13016 +#ifdef YYERRORSYMBOL
13017 +      /* A syntax error has occurred.
13018 +      ** The response to an error depends upon whether or not the
13019 +      ** grammar defines an error token "ERROR".
13020 +      **
13021 +      ** This is what we do if the grammar does define ERROR:
13022 +      **
13023 +      **  * Call the %syntax_error function.
13024 +      **
13025 +      **  * Begin popping the stack until we enter a state where
13026 +      **    it is legal to shift the error symbol, then shift
13027 +      **    the error symbol.
13028 +      **
13029 +      **  * Set the error count to three.
13030 +      **
13031 +      **  * Begin accepting and shifting new tokens.  No new error
13032 +      **    processing will occur until three tokens have been
13033 +      **    shifted successfully.
13034 +      **
13035 +      */
13036 +      if( yypParser->yyerrcnt<0 ){
13037 +        yy_syntax_error(yypParser,yymajor,yyminorunion);
13038 +      }
13039 +      yymx = yypParser->yystack[yypParser->yyidx].major;
13040 +      if( yymx==YYERRORSYMBOL || yyerrorhit ){
13041 +#ifndef NDEBUG
13042 +        if( yyTraceFILE ){
13043 +          fprintf(yyTraceFILE,"%sDiscard input token %s\n",
13044 +             yyTracePrompt,yyTokenName[yymajor]);
13045 +        }
13046 +#endif
13047 +        yy_destructor(yymajor,&yyminorunion);
13048 +        yymajor = YYNOCODE;
13049 +      }else{
13050 +         while(
13051 +          yypParser->yyidx >= 0 &&
13052 +          yymx != YYERRORSYMBOL &&
13053 +          (yyact = yy_find_shift_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
13054 +        ){
13055 +          yy_pop_parser_stack(yypParser);
13056 +        }
13057 +        if( yypParser->yyidx < 0 || yymajor==0 ){
13058 +          yy_destructor(yymajor,&yyminorunion);
13059 +          yy_parse_failed(yypParser);
13060 +          yymajor = YYNOCODE;
13061 +        }else if( yymx!=YYERRORSYMBOL ){
13062 +          YYMINORTYPE u2;
13063 +          u2.YYERRSYMDT = 0;
13064 +          yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
13065 +        }
13066 +      }
13067 +      yypParser->yyerrcnt = 3;
13068 +      yyerrorhit = 1;
13069 +#else  /* YYERRORSYMBOL is not defined */
13070 +      /* This is what we do if the grammar does not define ERROR:
13071 +      **
13072 +      **  * Report an error message, and throw away the input token.
13073 +      **
13074 +      **  * If the input token is $, then fail the parse.
13075 +      **
13076 +      ** As before, subsequent error messages are suppressed until
13077 +      ** three input tokens have been successfully shifted.
13078 +      */
13079 +      if( yypParser->yyerrcnt<=0 ){
13080 +        yy_syntax_error(yypParser,yymajor,yyminorunion);
13081 +      }
13082 +      yypParser->yyerrcnt = 3;
13083 +      yy_destructor(yymajor,&yyminorunion);
13084 +      if( yyendofinput ){
13085 +        yy_parse_failed(yypParser);
13086 +      }
13087 +      yymajor = YYNOCODE;
13088 +#endif
13089 +    }else{
13090 +      yy_accept(yypParser);
13091 +      yymajor = YYNOCODE;
13092 +    }
13093 +  }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
13094 +  return;
13095 +}
13096 --- ../lighttpd-1.4.11/src/http_resp_parser.h   1970-01-01 03:00:00.000000000 +0300
13097 +++ lighttpd-1.4.12/src/http_resp_parser.h      2006-07-18 13:03:52.000000000 +0300
13098 @@ -0,0 +1,3 @@
13099 +#define TK_CRLF                            1
13100 +#define TK_STRING                          2
13101 +#define TK_COLON                           3
13102 --- ../lighttpd-1.4.11/src/http_resp_parser.y   1970-01-01 03:00:00.000000000 +0300
13103 +++ lighttpd-1.4.12/src/http_resp_parser.y      2006-07-18 13:03:40.000000000 +0300
13104 @@ -0,0 +1,127 @@
13105 +%token_prefix TK_
13106 +%token_type {buffer *}
13107 +%extra_argument {http_resp_ctx_t *ctx}
13108 +%name http_resp_parser
13109 +
13110 +%include {
13111 +#include <assert.h>
13112 +#include <string.h>
13113 +#include "http_resp.h"
13114 +#include "keyvalue.h"
13115 +#include "array.h"
13116 +#include "log.h"
13117 +}
13118 +
13119 +%parse_failure {
13120 +  ctx->ok = 0;
13121 +}
13122 +
13123 +%type protocol { int }
13124 +%type response_hdr { http_resp * }
13125 +%type number { int }
13126 +%type headers { array * }
13127 +%type header { data_string * }
13128 +%destructor reason { buffer_free($$); }
13129 +%token_destructor { buffer_free($$); }
13130 +
13131 +/* just headers + Status: ... */
13132 +response_hdr ::= headers(HDR) CRLF . {
13133 +    http_resp *resp = ctx->resp;
13134 +    data_string *ds;
13135
13136 +    resp->protocol = HTTP_VERSION_UNSET;
13137 +
13138 +    buffer_copy_string(resp->reason, ""); /* no reason */
13139 +    array_free(resp->headers);
13140 +    resp->headers = HDR;
13141 +
13142 +    if (NULL == (ds = (data_string *)array_get_element(HDR, "Status"))) { 
13143 +        resp->status = 0;
13144 +    } else {
13145 +        char *err;
13146 +        resp->status = strtol(ds->value->ptr, &err, 10);
13147 +   
13148 +        if (*err != '\0' && *err != ' ') {
13149 +            buffer_copy_string(ctx->errmsg, "expected a number: ");
13150 +            buffer_append_string_buffer(ctx->errmsg, ds->value);
13151 +            buffer_append_string(ctx->errmsg, err);
13152 +        
13153 +            ctx->ok = 0;
13154 +        }
13155 +    }
13156 +
13157 +    HDR = NULL;
13158 +}
13159 +/* HTTP/1.0 <status> ... */
13160 +response_hdr ::= protocol(B) number(C) reason(D) CRLF headers(HDR) CRLF . {
13161 +    http_resp *resp = ctx->resp;
13162 +    
13163 +    resp->status = C;
13164 +    resp->protocol = B;
13165 +    buffer_copy_string_buffer(resp->reason, D);
13166 +    buffer_free(D); 
13167 +
13168 +    array_free(resp->headers);
13169 +    
13170 +    resp->headers = HDR;
13171 +}
13172 +
13173 +protocol(A) ::= STRING(B). {
13174 +    if (buffer_is_equal_string(B, CONST_STR_LEN("HTTP/1.0"))) {
13175 +        A = HTTP_VERSION_1_0;
13176 +    } else if (buffer_is_equal_string(B, CONST_STR_LEN("HTTP/1.1"))) {
13177 +        A = HTTP_VERSION_1_1;
13178 +    } else {
13179 +        buffer_copy_string(ctx->errmsg, "unknown protocol: ");
13180 +        buffer_append_string_buffer(ctx->errmsg, B);
13181 +        
13182 +        ctx->ok = 0;
13183 +    }
13184 +    buffer_free(B);
13185 +}
13186 +
13187 +number(A) ::= STRING(B). {
13188 +    char *err;
13189 +    A = strtol(B->ptr, &err, 10);
13190 +    
13191 +    if (*err != '\0') {
13192 +        buffer_copy_string(ctx->errmsg, "expected a number, got: ");
13193 +        buffer_append_string_buffer(ctx->errmsg, B);
13194 +        
13195 +        ctx->ok = 0;
13196 +    }
13197 +    buffer_free(B);
13198 +}
13199 +
13200 +reason(A) ::= STRING(B). {
13201 +    A = B;
13202 +}
13203 +
13204 +reason(A) ::= reason(C) STRING(B). {
13205 +    A = C;
13206 +    
13207 +    buffer_append_string(A, " ");
13208 +    buffer_append_string_buffer(A, B);
13209 +
13210 +    buffer_free(B); 
13211 +}
13212 +
13213 +headers(HDRS) ::= headers(SRC) header(HDR). {
13214 +    HDRS = SRC;
13215 +    
13216 +    array_insert_unique(HDRS, (data_unset *)HDR);
13217 +}
13218 +
13219 +headers(HDRS) ::= header(HDR). {
13220 +    HDRS = array_init();
13221 +
13222 +    array_insert_unique(HDRS, (data_unset *)HDR);
13223 +}
13224 +header(HDR) ::= STRING(A) COLON STRING(B) CRLF. {
13225 +    HDR = data_string_init();
13226 +    
13227 +    buffer_copy_string_buffer(HDR->key, A);
13228 +    buffer_copy_string_buffer(HDR->value, B);    
13229 +    buffer_free(A);
13230 +    buffer_free(B);
13231 +}
13232 --- ../lighttpd-1.4.11/src/inet_ntop_cache.c    2005-08-11 01:26:38.000000000 +0300
13233 +++ lighttpd-1.4.12/src/inet_ntop_cache.c       2006-07-16 00:26:04.000000000 +0300
13234 @@ -8,7 +8,7 @@
13235  #include "sys-socket.h"
13236  
13237  const char * inet_ntop_cache_get_ip(server *srv, sock_addr *addr) {
13238 -#ifdef HAVE_IPV6       
13239 +#ifdef HAVE_IPV6
13240         size_t ndx = 0, i;
13241         for (i = 0; i < INET_NTOP_CACHE_MAX; i++) {
13242                 if (srv->inet_ntop_cache[i].ts != 0) {
13243 @@ -20,31 +20,31 @@
13244                                    srv->inet_ntop_cache[i].addr.ipv4.s_addr == addr->ipv4.sin_addr.s_addr) {
13245                                 /* IPv4 found in cache */
13246                                 break;
13247 -                               
13248 +
13249                         }
13250                 }
13251         }
13252 -       
13253 +
13254         if (i == INET_NTOP_CACHE_MAX) {
13255                 /* not found in cache */
13256 -               
13257 +
13258                 i = ndx;
13259 -               inet_ntop(addr->plain.sa_family, 
13260 -                         addr->plain.sa_family == AF_INET6 ? 
13261 +               inet_ntop(addr->plain.sa_family,
13262 +                         addr->plain.sa_family == AF_INET6 ?
13263                           (const void *) &(addr->ipv6.sin6_addr) :
13264                           (const void *) &(addr->ipv4.sin_addr),
13265                           srv->inet_ntop_cache[i].b2, INET6_ADDRSTRLEN);
13266 -               
13267 +
13268                 srv->inet_ntop_cache[i].ts = srv->cur_ts;
13269                 srv->inet_ntop_cache[i].family = addr->plain.sa_family;
13270 -               
13271 +
13272                 if (srv->inet_ntop_cache[i].family == AF_INET) {
13273                         srv->inet_ntop_cache[i].addr.ipv4.s_addr = addr->ipv4.sin_addr.s_addr;
13274                 } else if (srv->inet_ntop_cache[i].family == AF_INET6) {
13275                         memcpy(srv->inet_ntop_cache[i].addr.ipv6.s6_addr, addr->ipv6.sin6_addr.s6_addr, 16);
13276                 }
13277         }
13278 -       
13279 +
13280         return srv->inet_ntop_cache[i].b2;
13281  #else
13282         UNUSED(srv);
13283 --- ../lighttpd-1.4.11/src/iosocket.c   1970-01-01 03:00:00.000000000 +0300
13284 +++ lighttpd-1.4.12/src/iosocket.c      2006-07-18 13:03:40.000000000 +0300
13285 @@ -0,0 +1,36 @@
13286 +#include <stdlib.h>
13287 +
13288 +#include "iosocket.h"
13289 +#include "sys-socket.h"
13290 +#include "sys-files.h"
13291 +#include "array-static.h"
13292 +
13293 +iosocket *iosocket_init(void) {
13294 +       STRUCT_INIT(iosocket, sock);
13295 +
13296 +       sock->fde_ndx = -1;
13297 +       sock->fd = -1;
13298 +
13299 +       sock->type = IOSOCKET_TYPE_SOCKET;
13300 +
13301 +       return sock;
13302 +}
13303 +
13304 +void iosocket_free(iosocket *sock) {
13305 +       if (!sock) return;
13306 +
13307 +       if (sock->fd != -1) {
13308 +               switch (sock->type) {
13309 +               case IOSOCKET_TYPE_SOCKET:
13310 +                       closesocket(sock->fd);
13311 +                       break;
13312 +               case IOSOCKET_TYPE_PIPE:
13313 +                       close(sock->fd);
13314 +                       break;
13315 +               default:
13316 +                       break;
13317 +               }
13318 +       }
13319 +
13320 +       free(sock);
13321 +}
13322 --- ../lighttpd-1.4.11/src/iosocket.h   1970-01-01 03:00:00.000000000 +0300
13323 +++ lighttpd-1.4.12/src/iosocket.h      2006-07-20 01:14:57.000000000 +0300
13324 @@ -0,0 +1,44 @@
13325 +#ifndef _IOSOCKET_H_
13326 +#define _IOSOCKET_H_
13327 +
13328 +/**
13329 + * make sure we know about OPENSSL all the time
13330 + *
13331 + * if we don't include config.h here we run into different sizes 
13332 + * for the iosocket-struct depending on config.h include before 
13333 + * iosocket.h or not
13334 + */
13335 +
13336 +#ifdef HAVE_CONFIG_H
13337 +# include "config.h"
13338 +#endif
13339 +
13340 +#if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
13341 +# define USE_OPENSSL
13342 +# include <openssl/ssl.h>
13343 +#endif
13344 +
13345 +typedef enum {
13346 +       IOSOCKET_TYPE_UNSET,
13347 +       IOSOCKET_TYPE_SOCKET,
13348 +       IOSOCKET_TYPE_PIPE
13349 +} iosocket_t;
13350 +
13351 +/**
13352 + * a non-blocking fd
13353 + */
13354 +typedef struct {
13355 +       int fd;
13356 +       int fde_ndx;
13357 +
13358 +#ifdef USE_OPENSSL
13359 +       SSL *ssl;
13360 +#endif
13361 +
13362 +       iosocket_t type; /**< sendfile on solaris doesn't work on pipes */
13363 +} iosocket;
13364 +
13365 +iosocket *iosocket_init(void);
13366 +void iosocket_free(iosocket *sock);
13367 +
13368 +#endif
13369 --- ../lighttpd-1.4.11/src/joblist.c    2005-08-11 01:26:41.000000000 +0300
13370 +++ lighttpd-1.4.12/src/joblist.c       2006-07-16 00:26:03.000000000 +0300
13371 @@ -7,7 +7,7 @@
13372  
13373  int joblist_append(server *srv, connection *con) {
13374         if (con->in_joblist) return 0;
13375 -       
13376 +
13377         if (srv->joblist->size == 0) {
13378                 srv->joblist->size  = 16;
13379                 srv->joblist->ptr   = malloc(sizeof(*srv->joblist->ptr) * srv->joblist->size);
13380 @@ -15,15 +15,15 @@
13381                 srv->joblist->size += 16;
13382                 srv->joblist->ptr   = realloc(srv->joblist->ptr, sizeof(*srv->joblist->ptr) * srv->joblist->size);
13383         }
13384 -       
13385 +
13386         srv->joblist->ptr[srv->joblist->used++] = con;
13387 -       
13388 +
13389         return 0;
13390  }
13391  
13392  void joblist_free(server *srv, connections *joblist) {
13393         UNUSED(srv);
13394 -               
13395 +
13396         free(joblist->ptr);
13397         free(joblist);
13398  }
13399 @@ -31,14 +31,14 @@
13400  connection *fdwaitqueue_unshift(server *srv, connections *fdwaitqueue) {
13401         connection *con;
13402         UNUSED(srv);
13403 -               
13404 -       
13405 +
13406 +
13407         if (fdwaitqueue->used == 0) return NULL;
13408 -       
13409 +
13410         con = fdwaitqueue->ptr[0];
13411 -       
13412 +
13413         memmove(fdwaitqueue->ptr, &(fdwaitqueue->ptr[1]), --fdwaitqueue->used * sizeof(*(fdwaitqueue->ptr)));
13414 -       
13415 +
13416         return con;
13417  }
13418  
13419 @@ -50,9 +50,9 @@
13420                 srv->fdwaitqueue->size += 16;
13421                 srv->fdwaitqueue->ptr   = realloc(srv->fdwaitqueue->ptr, sizeof(*(srv->fdwaitqueue->ptr)) * srv->fdwaitqueue->size);
13422         }
13423 -       
13424 +
13425         srv->fdwaitqueue->ptr[srv->fdwaitqueue->used++] = con;
13426 -       
13427 +
13428         return 0;
13429  }
13430  
13431 --- ../lighttpd-1.4.11/src/keyvalue.c   2006-03-02 16:08:06.000000000 +0200
13432 +++ lighttpd-1.4.12/src/keyvalue.c      2006-07-16 00:26:03.000000000 +0300
13433 @@ -87,7 +87,8 @@
13434         { 504, "Gateway Timeout" },
13435         { 505, "HTTP Version Not Supported" },
13436         { 507, "Insufficient Storage" }, /* WebDAV */
13437 -       
13438 +       { 509, "Bandwidth Limit exceeded" },
13439 +
13440         { -1, NULL }
13441  };
13442  
13443 @@ -102,12 +103,12 @@
13444         { 501, "501.html" },
13445         { 503, "503.html" },
13446         { 505, "505.html" },
13447 -       
13448 +
13449         { -1, NULL }
13450  };
13451  
13452  
13453 -const char *keyvalue_get_value(keyvalue *kv, int k) { 
13454 +const char *keyvalue_get_value(keyvalue *kv, int k) {
13455         int i;
13456         for (i = 0; kv[i].value; i++) {
13457                 if (kv[i].key == k) return kv[i].value;
13458 @@ -115,7 +116,7 @@
13459         return NULL;
13460  }
13461  
13462 -int keyvalue_get_key(keyvalue *kv, const char *s) { 
13463 +int keyvalue_get_key(keyvalue *kv, const char *s) {
13464         int i;
13465         for (i = 0; kv[i].value; i++) {
13466                 if (0 == strcmp(kv[i].value, s)) return kv[i].key;
13467 @@ -125,9 +126,9 @@
13468  
13469  keyvalue_buffer *keyvalue_buffer_init(void) {
13470         keyvalue_buffer *kvb;
13471 -       
13472 +
13473         kvb = calloc(1, sizeof(*kvb));
13474 -       
13475 +
13476         return kvb;
13477  }
13478  
13479 @@ -135,49 +136,49 @@
13480         size_t i;
13481         if (kvb->size == 0) {
13482                 kvb->size = 4;
13483 -               
13484 +
13485                 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13486 -               
13487 +
13488                 for(i = 0; i < kvb->size; i++) {
13489                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13490                 }
13491         } else if (kvb->used == kvb->size) {
13492                 kvb->size += 4;
13493 -               
13494 +
13495                 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13496 -               
13497 +
13498                 for(i = kvb->used; i < kvb->size; i++) {
13499                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13500                 }
13501         }
13502 -       
13503 +
13504         kvb->kv[kvb->used]->key = key;
13505         kvb->kv[kvb->used]->value = strdup(value);
13506 -       
13507 +
13508         kvb->used++;
13509 -       
13510 +
13511         return 0;
13512  }
13513  
13514  void keyvalue_buffer_free(keyvalue_buffer *kvb) {
13515         size_t i;
13516 -       
13517 +
13518         for (i = 0; i < kvb->size; i++) {
13519                 if (kvb->kv[i]->value) free(kvb->kv[i]->value);
13520                 free(kvb->kv[i]);
13521         }
13522 -       
13523 +
13524         if (kvb->kv) free(kvb->kv);
13525 -       
13526 +
13527         free(kvb);
13528  }
13529  
13530  
13531  s_keyvalue_buffer *s_keyvalue_buffer_init(void) {
13532         s_keyvalue_buffer *kvb;
13533 -       
13534 +
13535         kvb = calloc(1, sizeof(*kvb));
13536 -       
13537 +
13538         return kvb;
13539  }
13540  
13541 @@ -186,50 +187,50 @@
13542         if (kvb->size == 0) {
13543                 kvb->size = 4;
13544                 kvb->used = 0;
13545 -               
13546 +
13547                 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13548 -               
13549 +
13550                 for(i = 0; i < kvb->size; i++) {
13551                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13552                 }
13553         } else if (kvb->used == kvb->size) {
13554                 kvb->size += 4;
13555 -               
13556 +
13557                 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13558 -               
13559 +
13560                 for(i = kvb->used; i < kvb->size; i++) {
13561                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13562                 }
13563         }
13564 -       
13565 +
13566         kvb->kv[kvb->used]->key = key ? strdup(key) : NULL;
13567         kvb->kv[kvb->used]->value = strdup(value);
13568 -       
13569 +
13570         kvb->used++;
13571 -       
13572 +
13573         return 0;
13574  }
13575  
13576  void s_keyvalue_buffer_free(s_keyvalue_buffer *kvb) {
13577         size_t i;
13578 -       
13579 +
13580         for (i = 0; i < kvb->size; i++) {
13581                 if (kvb->kv[i]->key) free(kvb->kv[i]->key);
13582                 if (kvb->kv[i]->value) free(kvb->kv[i]->value);
13583                 free(kvb->kv[i]);
13584         }
13585 -       
13586 +
13587         if (kvb->kv) free(kvb->kv);
13588 -       
13589 +
13590         free(kvb);
13591  }
13592  
13593  
13594  httpauth_keyvalue_buffer *httpauth_keyvalue_buffer_init(void) {
13595         httpauth_keyvalue_buffer *kvb;
13596 -       
13597 +
13598         kvb = calloc(1, sizeof(*kvb));
13599 -       
13600 +
13601         return kvb;
13602  }
13603  
13604 @@ -237,42 +238,42 @@
13605         size_t i;
13606         if (kvb->size == 0) {
13607                 kvb->size = 4;
13608 -               
13609 +
13610                 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13611 -               
13612 +
13613                 for(i = 0; i < kvb->size; i++) {
13614                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13615                 }
13616         } else if (kvb->used == kvb->size) {
13617                 kvb->size += 4;
13618 -               
13619 +
13620                 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13621 -               
13622 +
13623                 for(i = kvb->used; i < kvb->size; i++) {
13624                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13625                 }
13626         }
13627 -       
13628 +
13629         kvb->kv[kvb->used]->key = strdup(key);
13630         kvb->kv[kvb->used]->realm = strdup(realm);
13631         kvb->kv[kvb->used]->type = type;
13632 -       
13633 +
13634         kvb->used++;
13635 -       
13636 +
13637         return 0;
13638  }
13639  
13640  void httpauth_keyvalue_buffer_free(httpauth_keyvalue_buffer *kvb) {
13641         size_t i;
13642 -       
13643 +
13644         for (i = 0; i < kvb->size; i++) {
13645                 if (kvb->kv[i]->key) free(kvb->kv[i]->key);
13646                 if (kvb->kv[i]->realm) free(kvb->kv[i]->realm);
13647                 free(kvb->kv[i]);
13648         }
13649 -       
13650 +
13651         if (kvb->kv) free(kvb->kv);
13652 -       
13653 +
13654         free(kvb);
13655  }
13656  
13657 @@ -306,9 +307,9 @@
13658  
13659  pcre_keyvalue_buffer *pcre_keyvalue_buffer_init(void) {
13660         pcre_keyvalue_buffer *kvb;
13661 -       
13662 +
13663         kvb = calloc(1, sizeof(*kvb));
13664 -       
13665 +
13666         return kvb;
13667  }
13668  
13669 @@ -319,46 +320,46 @@
13670         int erroff;
13671         pcre_keyvalue *kv;
13672  #endif
13673 -       
13674 +
13675         if (!key) return -1;
13676  
13677  #ifdef HAVE_PCRE_H
13678         if (kvb->size == 0) {
13679                 kvb->size = 4;
13680                 kvb->used = 0;
13681 -               
13682 +
13683                 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13684 -               
13685 +
13686                 for(i = 0; i < kvb->size; i++) {
13687                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13688                 }
13689         } else if (kvb->used == kvb->size) {
13690                 kvb->size += 4;
13691 -               
13692 +
13693                 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13694 -               
13695 +
13696                 for(i = kvb->used; i < kvb->size; i++) {
13697                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13698                 }
13699         }
13700 -       
13701 +
13702         kv = kvb->kv[kvb->used];
13703         if (NULL == (kv->key = pcre_compile(key,
13704                                           0, &errptr, &erroff, NULL))) {
13705 -               
13706 +
13707                 fprintf(stderr, "%s.%d: rexexp compilation error at %s\n", __FILE__, __LINE__, errptr);
13708                 return -1;
13709         }
13710  
13711 -       if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) &&  
13712 +       if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) &&
13713                         errptr != NULL) {
13714                 return -1;
13715         }
13716 -       
13717 +
13718         kv->value = buffer_init_string(value);
13719 -       
13720 +
13721         kvb->used++;
13722 -       
13723 +
13724         return 0;
13725  #else
13726         UNUSED(kvb);
13727 @@ -380,9 +381,9 @@
13728                 if (kv->value) buffer_free(kv->value);
13729                 free(kv);
13730         }
13731 -       
13732 +
13733         if (kvb->kv) free(kvb->kv);
13734  #endif
13735 -       
13736 +
13737         free(kvb);
13738  }
13739 --- ../lighttpd-1.4.11/src/keyvalue.h   2006-03-02 16:08:06.000000000 +0200
13740 +++ lighttpd-1.4.12/src/keyvalue.h      2006-07-16 00:26:04.000000000 +0300
13741 @@ -9,19 +9,19 @@
13742  # include <pcre.h>
13743  #endif
13744  
13745 -typedef enum { 
13746 -       HTTP_METHOD_UNSET = -1, 
13747 -       HTTP_METHOD_GET, 
13748 -       HTTP_METHOD_POST, 
13749 -       HTTP_METHOD_HEAD, 
13750 -       HTTP_METHOD_OPTIONS, 
13751 +typedef enum {
13752 +       HTTP_METHOD_UNSET = -1,
13753 +       HTTP_METHOD_GET,
13754 +       HTTP_METHOD_POST,
13755 +       HTTP_METHOD_HEAD,
13756 +       HTTP_METHOD_OPTIONS,
13757         HTTP_METHOD_PROPFIND,  /* WebDAV */
13758 -       HTTP_METHOD_MKCOL, 
13759 -       HTTP_METHOD_PUT, 
13760 -       HTTP_METHOD_DELETE, 
13761 -       HTTP_METHOD_COPY, 
13762 -       HTTP_METHOD_MOVE, 
13763 -       HTTP_METHOD_PROPPATCH, 
13764 +       HTTP_METHOD_MKCOL,
13765 +       HTTP_METHOD_PUT,
13766 +       HTTP_METHOD_DELETE,
13767 +       HTTP_METHOD_COPY,
13768 +       HTTP_METHOD_MOVE,
13769 +       HTTP_METHOD_PROPPATCH,
13770         HTTP_METHOD_REPORT, /* DeltaV */
13771         HTTP_METHOD_CHECKOUT,
13772         HTTP_METHOD_CHECKIN,
13773 @@ -39,13 +39,13 @@
13774  
13775  typedef struct {
13776         int key;
13777 -       
13778 +
13779         char *value;
13780  } keyvalue;
13781  
13782  typedef struct {
13783         char *key;
13784 -       
13785 +
13786         char *value;
13787  } s_keyvalue;
13788  
13789 @@ -54,7 +54,7 @@
13790         pcre *key;
13791         pcre_extra *key_extra;
13792  #endif
13793 -       
13794 +
13795         buffer *value;
13796  } pcre_keyvalue;
13797  
13798 @@ -62,7 +62,7 @@
13799  
13800  typedef struct {
13801         char *key;
13802 -       
13803 +
13804         char *realm;
13805         httpauth_type type;
13806  } httpauth_keyvalue;
13807 --- ../lighttpd-1.4.11/src/lemon.c      2005-09-01 00:21:34.000000000 +0300
13808 +++ lighttpd-1.4.12/src/lemon.c 2006-07-16 00:26:03.000000000 +0300
13809 @@ -579,7 +579,7 @@
13810  */
13811  
13812  /* Find a precedence symbol of every rule in the grammar.
13813 -** 
13814 +**
13815  ** Those rules which have a precedence symbol coded in the input
13816  ** grammar using the "[symbol]" construct will already have the
13817  ** rp->precsym field filled.  Other rules take as their precedence
13818 @@ -869,7 +869,7 @@
13819        cfp->status = INCOMPLETE;
13820      }
13821    }
13822 -  
13823 +
13824    do{
13825      progress = 0;
13826      for(i=0; i<lemp->nstate; i++){
13827 @@ -900,7 +900,7 @@
13828    struct symbol *sp;
13829    struct rule *rp;
13830  
13831 -  /* Add all of the reduce actions 
13832 +  /* Add all of the reduce actions
13833    ** A reduce action is added for each element of the followset of
13834    ** a configuration which has its dot at the extreme right.
13835    */
13836 @@ -1017,7 +1017,7 @@
13837        apx->type = RD_RESOLVED;
13838      }
13839    }else{
13840 -    assert( 
13841 +    assert(
13842        apx->type==SH_RESOLVED ||
13843        apx->type==RD_RESOLVED ||
13844        apx->type==CONFLICT ||
13845 @@ -1350,7 +1350,7 @@
13846    OptInit(argv,options,stderr);
13847    if( version ){
13848       printf("Lemon version 1.0\n");
13849 -     exit(0); 
13850 +     exit(0);
13851    }
13852    if( OptNArgs() < 1 ){
13853      fprintf(stderr,"Exactly one filename argument is required.\n");
13854 @@ -2031,7 +2031,7 @@
13855      case IN_RHS:
13856        if( x[0]=='.' ){
13857          struct rule *rp;
13858 -        rp = (struct rule *)malloc( sizeof(struct rule) + 
13859 +        rp = (struct rule *)malloc( sizeof(struct rule) +
13860               sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs );
13861          if( rp==0 ){
13862            ErrorMsg(psp->filename,psp->tokenlineno,
13863 @@ -2546,7 +2546,7 @@
13864    return fp;
13865  }
13866  
13867 -/* Duplicate the input file without comments and without actions 
13868 +/* Duplicate the input file without comments and without actions
13869  ** on rules */
13870  void Reprint(lemp)
13871  struct lemon *lemp;
13872 @@ -2822,7 +2822,7 @@
13873  PRIVATE FILE *tplt_open(lemp)
13874  struct lemon *lemp;
13875  {
13876 -  
13877 +
13878    char buf[1000];
13879    FILE *in;
13880    char *tpltname;
13881 @@ -2930,7 +2930,7 @@
13882    return ret;
13883  }
13884  
13885 -/* 
13886 +/*
13887  ** Generate code which executes when the rule "rp" is reduced.  Write
13888  ** the code to "out".  Make sure lineno stays up-to-date.
13889  */
13890 @@ -3384,7 +3384,7 @@
13891  
13892    /* Output the yy_shift_ofst[] table */
13893    fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++;
13894 -  fprintf(out, "static %s yy_shift_ofst[] = {\n", 
13895 +  fprintf(out, "static %s yy_shift_ofst[] = {\n",
13896            minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++;
13897    n = lemp->nstate;
13898    for(i=j=0; i<n; i++){
13899 @@ -3405,7 +3405,7 @@
13900  
13901    /* Output the yy_reduce_ofst[] table */
13902    fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++;
13903 -  fprintf(out, "static %s yy_reduce_ofst[] = {\n", 
13904 +  fprintf(out, "static %s yy_reduce_ofst[] = {\n",
13905            minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++;
13906    n = lemp->nstate;
13907    for(i=j=0; i<n; i++){
13908 @@ -3480,7 +3480,7 @@
13909    tplt_xfer(lemp->name,in,out,&lineno);
13910  
13911    /* Generate code which executes every time a symbol is popped from
13912 -  ** the stack while processing errors or while destroying the parser. 
13913 +  ** the stack while processing errors or while destroying the parser.
13914    ** (In other words, generate the %destructor actions)
13915    */
13916    if( lemp->tokendest ){
13917 @@ -3522,7 +3522,7 @@
13918    tplt_print(out,lemp,lemp->overflow,lemp->overflowln,&lineno);
13919    tplt_xfer(lemp->name,in,out,&lineno);
13920  
13921 -  /* Generate the table of rule information 
13922 +  /* Generate the table of rule information
13923    **
13924    ** Note: This code depends on the fact that rules are number
13925    ** sequentually beginning with 0.
13926 @@ -3589,7 +3589,7 @@
13927      for(i=1; i<lemp->nterminal; i++){
13928        fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
13929      }
13930 -    fclose(out);  
13931 +    fclose(out);
13932    }
13933    return;
13934  }
13935 @@ -3630,7 +3630,7 @@
13936          rbest = rp;
13937        }
13938      }
13939
13940 +
13941      /* Do not make a default if the number of rules to default
13942      ** is not at least 2 */
13943      if( nbest<2 ) continue;
13944 @@ -3781,7 +3781,7 @@
13945    if( x1a ){
13946      x1a->size = 1024;
13947      x1a->count = 0;
13948 -    x1a->tbl = (x1node*)malloc( 
13949 +    x1a->tbl = (x1node*)malloc(
13950        (sizeof(x1node) + sizeof(x1node*))*1024 );
13951      if( x1a->tbl==0 ){
13952        free(x1a);
13953 @@ -3943,7 +3943,7 @@
13954    if( x2a ){
13955      x2a->size = 128;
13956      x2a->count = 0;
13957 -    x2a->tbl = (x2node*)malloc( 
13958 +    x2a->tbl = (x2node*)malloc(
13959        (sizeof(x2node) + sizeof(x2node*))*128 );
13960      if( x2a->tbl==0 ){
13961        free(x2a);
13962 @@ -4149,7 +4149,7 @@
13963    if( x3a ){
13964      x3a->size = 128;
13965      x3a->count = 0;
13966 -    x3a->tbl = (x3node*)malloc( 
13967 +    x3a->tbl = (x3node*)malloc(
13968        (sizeof(x3node) + sizeof(x3node*))*128 );
13969      if( x3a->tbl==0 ){
13970        free(x3a);
13971 @@ -4295,7 +4295,7 @@
13972    if( x4a ){
13973      x4a->size = 64;
13974      x4a->count = 0;
13975 -    x4a->tbl = (x4node*)malloc( 
13976 +    x4a->tbl = (x4node*)malloc(
13977        (sizeof(x4node) + sizeof(x4node*))*64 );
13978      if( x4a->tbl==0 ){
13979        free(x4a);
13980 --- ../lighttpd-1.4.11/src/lempar.c     2005-08-11 01:26:40.000000000 +0300
13981 +++ lighttpd-1.4.12/src/lempar.c        2006-07-16 00:26:03.000000000 +0300
13982 @@ -8,10 +8,10 @@
13983  /* Next is all token values, in a form suitable for use by makeheaders.
13984  ** This section will be null unless lemon is run with the -m switch.
13985  */
13986 -/* 
13987 +/*
13988  ** These constants (all generated automatically by the parser generator)
13989  ** specify the various kinds of tokens (terminals) that the parser
13990 -** understands. 
13991 +** understands.
13992  **
13993  ** Each symbol here is a terminal symbol in the grammar.
13994  */
13995 @@ -29,7 +29,7 @@
13996  **                       and nonterminals.  "int" is used otherwise.
13997  **    YYNOCODE           is a number of type YYCODETYPE which corresponds
13998  **                       to no legal terminal or nonterminal number.  This
13999 -**                       number is used to fill in empty slots of the hash 
14000 +**                       number is used to fill in empty slots of the hash
14001  **                       table.
14002  **    YYFALLBACK         If defined, this indicates that one or more tokens
14003  **                       have fall-back values which should be used if the
14004 @@ -38,7 +38,7 @@
14005  **                       and nonterminal numbers.  "unsigned char" is
14006  **                       used if there are fewer than 250 rules and
14007  **                       states combined.  "int" is used otherwise.
14008 -**    ParseTOKENTYPE     is the data type used for minor tokens given 
14009 +**    ParseTOKENTYPE     is the data type used for minor tokens given
14010  **                       directly to the parser from the tokenizer.
14011  **    YYMINORTYPE        is the data type used for all minor tokens.
14012  **                       This is typically a union of many types, one of
14013 @@ -62,7 +62,7 @@
14014  /* Next are that tables used to determine what action to take based on the
14015  ** current state and lookahead token.  These tables are used to implement
14016  ** functions that take a state number and lookahead value and return an
14017 -** action integer.  
14018 +** action integer.
14019  **
14020  ** Suppose the action integer is N.  Then the action is determined as
14021  ** follows
14022 @@ -87,7 +87,7 @@
14023  ** If the index value yy_shift_ofst[S]+X is out of range or if the value
14024  ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
14025  ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
14026 -** and that yy_default[S] should be used instead.  
14027 +** and that yy_default[S] should be used instead.
14028  **
14029  ** The formula above is for computing the action when the lookahead is
14030  ** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
14031 @@ -111,7 +111,7 @@
14032  
14033  /* The next table maps tokens into fallback tokens.  If a construct
14034  ** like the following:
14035 -** 
14036 +**
14037  **      %fallback ID X Y Z.
14038  **
14039  ** appears in the grammer, then ID becomes a fallback token for X, Y,
14040 @@ -163,10 +163,10 @@
14041  #endif /* NDEBUG */
14042  
14043  #ifndef NDEBUG
14044 -/* 
14045 +/*
14046  ** Turn parser tracing on by giving a stream to which to write the trace
14047  ** and a prompt to preface each trace message.  Tracing is turned off
14048 -** by making either argument NULL 
14049 +** by making either argument NULL
14050  **
14051  ** Inputs:
14052  ** <ul>
14053 @@ -191,7 +191,7 @@
14054  #ifndef NDEBUG
14055  /* For tracing shifts, the names of all terminals and nonterminals
14056  ** are required.  The following table supplies these names */
14057 -static const char *yyTokenName[] = { 
14058 +static const char *yyTokenName[] = {
14059  %%
14060  };
14061  #endif /* NDEBUG */
14062 @@ -220,7 +220,7 @@
14063  #endif
14064  }
14065  
14066 -/* 
14067 +/*
14068  ** This function allocates a new parser.
14069  ** The only argument is a pointer to a function which works like
14070  ** malloc.
14071 @@ -251,7 +251,7 @@
14072      /* Here is inserted the actions which take place when a
14073      ** terminal or non-terminal is destroyed.  This can happen
14074      ** when the symbol is popped from the stack during a
14075 -    ** reduce or during error processing or when a parser is 
14076 +    ** reduce or during error processing or when a parser is
14077      ** being destroyed before it is finished parsing.
14078      **
14079      ** Note: during a reduce, the only symbols destroyed are those
14080 @@ -289,7 +289,7 @@
14081    return yymajor;
14082  }
14083  
14084 -/* 
14085 +/*
14086  ** Deallocate and destroy a parser.  Destructors are all called for
14087  ** all stack elements before shutting the parser down.
14088  **
14089 @@ -325,7 +325,7 @@
14090  ){
14091    int i;
14092    int stateno = pParser->yystack[pParser->yyidx].stateno;
14093
14094 +
14095    /* if( pParser->yyidx<0 ) return YY_NO_ACTION;  */
14096    i = yy_shift_ofst[stateno];
14097    if( i==YY_SHIFT_USE_DFLT ){
14098 @@ -369,7 +369,7 @@
14099  ){
14100    int i;
14101    int stateno = pParser->yystack[pParser->yyidx].stateno;
14102
14103 +
14104    i = yy_reduce_ofst[stateno];
14105    if( i==YY_REDUCE_USE_DFLT ){
14106      return yy_default[stateno];
14107 @@ -455,7 +455,7 @@
14108    ParseARG_FETCH;
14109    yymsp = &yypParser->yystack[yypParser->yyidx];
14110  #ifndef NDEBUG
14111 -  if( yyTraceFILE && yyruleno>=0 
14112 +  if( yyTraceFILE && yyruleno>=0
14113          && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
14114      fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
14115        yyRuleName[yyruleno]);
14116 @@ -608,7 +608,7 @@
14117  #ifdef YYERRORSYMBOL
14118        /* A syntax error has occurred.
14119        ** The response to an error depends upon whether or not the
14120 -      ** grammar defines an error token "ERROR".  
14121 +      ** grammar defines an error token "ERROR".
14122        **
14123        ** This is what we do if the grammar does define ERROR:
14124        **
14125 --- ../lighttpd-1.4.11/src/log.c        2005-11-07 15:01:35.000000000 +0200
14126 +++ lighttpd-1.4.12/src/log.c   2006-07-18 13:03:40.000000000 +0300
14127 @@ -5,7 +5,6 @@
14128  #include <errno.h>
14129  #include <fcntl.h>
14130  #include <time.h>
14131 -#include <unistd.h>
14132  #include <string.h>
14133  #include <stdlib.h>
14134  
14135 @@ -16,6 +15,10 @@
14136  #include "config.h"
14137  #endif
14138  
14139 +#ifdef _WIN32
14140 +#undef HAVE_SYSLOG_H
14141 +#endif
14142 +
14143  #ifdef HAVE_SYSLOG_H
14144  #include <syslog.h>
14145  #endif
14146 @@ -23,6 +26,8 @@
14147  #include "log.h"
14148  #include "array.h"
14149  
14150 +#include "sys-files.h"
14151 +
14152  #ifdef HAVE_VALGRIND_VALGRIND_H
14153  #include <valgrind/valgrind.h>
14154  #endif
14155 @@ -31,55 +36,114 @@
14156  # define O_LARGEFILE 0
14157  #endif
14158  
14159 -/** 
14160 +/**
14161   * open the errorlog
14162 - * 
14163 + *
14164   * we have 3 possibilities:
14165   * - stderr (default)
14166 - * - syslog 
14167 + * - syslog
14168   * - logfile
14169 - * 
14170 + *
14171   * if the open failed, report to the user and die
14172 - * 
14173 + *
14174   */
14175  
14176 -int log_error_open(server *srv) {
14177 +
14178 +typedef struct {
14179 +       buffer *file;
14180 +       unsigned short use_syslog;
14181 +
14182 +       /* the errorlog */
14183         int fd;
14184 -       int close_stderr = 1;
14185 +       enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG } mode;
14186 +       buffer *buf;
14187 +
14188 +       time_t cached_ts;
14189 +       buffer *cached_ts_str;
14190 +} errorlog;
14191 +
14192 +errorlog *myconfig = NULL;
14193 +
14194 +void log_init(void) {
14195 +       /* use syslog */
14196 +       errorlog *err;
14197 +
14198 +       err = calloc(1, sizeof(*err));
14199         
14200 +       err->fd = -1;
14201 +       err->mode = ERRORLOG_STDERR;
14202 +       err->buf = buffer_init();
14203 +       err->cached_ts_str = buffer_init();
14204 +
14205 +       myconfig = err;
14206 +}
14207 +
14208 +void log_free(void) {
14209 +       errorlog *err = myconfig;
14210 +
14211 +       if (!err) return;
14212 +
14213 +       TRACE("%s", "server stopped");
14214 +
14215 +       switch(err->mode) {
14216 +       case ERRORLOG_FILE:
14217 +               close(err->fd);
14218 +               break;
14219 +       case ERRORLOG_SYSLOG:
14220 +#ifdef HAVE_SYSLOG_H
14221 +               closelog();
14222 +#endif
14223 +               break;
14224 +       case ERRORLOG_STDERR:
14225 +               break;
14226 +       }
14227 +
14228 +       buffer_free(err->buf);
14229 +       buffer_free(err->cached_ts_str);
14230 +       if (err->file) buffer_free(err->file);
14231 +
14232 +       free(err);
14233 +
14234 +       myconfig = NULL;
14235 +}
14236 +
14237 +int log_error_open(buffer *file, int use_syslog) {
14238 +       int fd;
14239 +       int close_stderr = 1;
14240 +
14241 +       errorlog *err = myconfig;
14242 +
14243  #ifdef HAVE_SYSLOG_H
14244         /* perhaps someone wants to use syslog() */
14245         openlog("lighttpd", LOG_CONS | LOG_PID, LOG_DAEMON);
14246  #endif
14247 -       srv->errorlog_mode = ERRORLOG_STDERR;
14248 -       
14249 -       if (srv->srvconf.errorlog_use_syslog) {
14250 -               srv->errorlog_mode = ERRORLOG_SYSLOG;
14251 -       } else if (!buffer_is_empty(srv->srvconf.errorlog_file)) {
14252 -               const char *logfile = srv->srvconf.errorlog_file->ptr;
14253 -               
14254 -               if (-1 == (srv->errorlog_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14255 -                       log_error_write(srv, __FILE__, __LINE__, "SSSS", 
14256 -                                       "opening errorlog '", logfile,
14257 +       err->mode = ERRORLOG_STDERR;
14258 +
14259 +       if (use_syslog) {
14260 +               err->mode = ERRORLOG_SYSLOG;
14261 +       } else if (!buffer_is_empty(file)) {
14262 +               if (-1 == (err->fd = open(file->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14263 +                       log_error_write(NULL, __FILE__, __LINE__, "SBSS",
14264 +                                       "opening errorlog '", file,
14265                                         "' failed: ", strerror(errno));
14266 -                       
14267 +
14268                         return -1;
14269                 }
14270  #ifdef FD_CLOEXEC
14271                 /* close fd on exec (cgi) */
14272 -               fcntl(srv->errorlog_fd, F_SETFD, FD_CLOEXEC);
14273 +               fcntl(err->fd, F_SETFD, FD_CLOEXEC);
14274  #endif
14275 -               srv->errorlog_mode = ERRORLOG_FILE;
14276 +               err->mode = ERRORLOG_FILE;
14277         }
14278 -       
14279 -       log_error_write(srv, __FILE__, __LINE__, "s", "server started");
14280 -       
14281 +
14282 +       TRACE("%s", "server started");
14283 +
14284  #ifdef HAVE_VALGRIND_VALGRIND_H
14285         /* don't close stderr for debugging purposes if run in valgrind */
14286         if (RUNNING_ON_VALGRIND) close_stderr = 0;
14287  #endif
14288 -       if (srv->errorlog_mode == ERRORLOG_STDERR) close_stderr = 0;
14289 -       
14290 +       if (err->mode == ERRORLOG_STDERR) close_stderr = 0;
14291 +
14292         /* move stderr to /dev/null */
14293         if (close_stderr &&
14294             -1 != (fd = open("/dev/null", O_WRONLY))) {
14295 @@ -90,167 +154,202 @@
14296         return 0;
14297  }
14298  
14299 -/** 
14300 +/**
14301   * open the errorlog
14302 - * 
14303 + *
14304   * if the open failed, report to the user and die
14305   * if no filename is given, use syslog instead
14306 - * 
14307 + *
14308   */
14309  
14310 -int log_error_cycle(server *srv) {
14311 +int log_error_cycle(void) {
14312         /* only cycle if we are not in syslog-mode */
14313 -       
14314 -       if (srv->errorlog_mode == ERRORLOG_FILE) {
14315 -               const char *logfile = srv->srvconf.errorlog_file->ptr;
14316 +
14317 +       errorlog *err = myconfig;
14318 +
14319 +       if (err->mode == ERRORLOG_FILE) {
14320 +               buffer *file = err->file;
14321                 /* already check of opening time */
14322 -               
14323 +
14324                 int new_fd;
14325 -               
14326 -               if (-1 == (new_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14327 +
14328 +               if (-1 == (new_fd = open(file->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14329                         /* write to old log */
14330 -                       log_error_write(srv, __FILE__, __LINE__, "SSSSS", 
14331 -                                       "cycling errorlog '", logfile,
14332 +                       log_error_write(NULL, __FILE__, __LINE__, "SBSSS",
14333 +                                       "cycling errorlog '", file,
14334                                         "' failed: ", strerror(errno),
14335                                         ", falling back to syslog()");
14336 -                       
14337 -                       close(srv->errorlog_fd);
14338 -                       srv->errorlog_fd = -1;
14339 -#ifdef HAVE_SYSLOG_H   
14340 -                       srv->errorlog_mode = ERRORLOG_SYSLOG;
14341 +
14342 +                       close(err->fd);
14343 +                       err->fd = -1;
14344 +#ifdef HAVE_SYSLOG_H
14345 +                       err->mode = ERRORLOG_SYSLOG;
14346  #endif
14347                 } else {
14348                         /* ok, new log is open, close the old one */
14349 -                       close(srv->errorlog_fd);
14350 -                       srv->errorlog_fd = new_fd;
14351 +                       close(err->fd);
14352 +                       err->fd = new_fd;
14353                 }
14354         }
14355 -       
14356 -       log_error_write(srv, __FILE__, __LINE__, "s", "logfiles cycled");
14357 -       
14358 -       return 0;
14359 -}
14360  
14361 -int log_error_close(server *srv) {
14362 -       log_error_write(srv, __FILE__, __LINE__, "s", "server stopped");
14363 -       
14364 -       switch(srv->errorlog_mode) {
14365 -       case ERRORLOG_FILE:
14366 -               close(srv->errorlog_fd);
14367 -               break;
14368 -       case ERRORLOG_SYSLOG:
14369 -#ifdef HAVE_SYSLOG_H
14370 -               closelog();
14371 -#endif
14372 -               break;
14373 -       case ERRORLOG_STDERR:
14374 -               break;
14375 -       }
14376 -       
14377 +       TRACE("%s", "logfiles cycled");
14378 +
14379         return 0;
14380  }
14381  
14382 -int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...) {
14383 +int log_error_write(void *srv, const char *filename, unsigned int line, const char *fmt, ...) {
14384         va_list ap;
14385 -       
14386 -       switch(srv->errorlog_mode) {
14387 +       time_t t;
14388 +
14389 +       errorlog *err = myconfig;
14390 +
14391 +       switch(err->mode) {
14392         case ERRORLOG_FILE:
14393         case ERRORLOG_STDERR:
14394                 /* cache the generated timestamp */
14395 -               if (srv->cur_ts != srv->last_generated_debug_ts) {
14396 -                       buffer_prepare_copy(srv->ts_debug_str, 255);
14397 -                       strftime(srv->ts_debug_str->ptr, srv->ts_debug_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts)));
14398 -                       srv->ts_debug_str->used = strlen(srv->ts_debug_str->ptr) + 1;
14399 -                       
14400 -                       srv->last_generated_debug_ts = srv->cur_ts;
14401 +               t = time(NULL);
14402 +               
14403 +               if (t != err->cached_ts) {
14404 +                       buffer_prepare_copy(err->cached_ts_str, 255);
14405 +                       strftime(err->cached_ts_str->ptr, err->cached_ts_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(t)));
14406 +                       err->cached_ts_str->used = strlen(err->cached_ts_str->ptr) + 1;
14407 +                       err->cached_ts = t;
14408                 }
14409  
14410 -               buffer_copy_string_buffer(srv->errorlog_buf, srv->ts_debug_str);
14411 -               BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ": (");
14412 +               buffer_copy_string_buffer(err->buf, err->cached_ts_str);
14413 +               BUFFER_APPEND_STRING_CONST(err->buf, ": (");
14414                 break;
14415         case ERRORLOG_SYSLOG:
14416                 /* syslog is generating its own timestamps */
14417 -               BUFFER_COPY_STRING_CONST(srv->errorlog_buf, "(");
14418 +               BUFFER_COPY_STRING_CONST(err->buf, "(");
14419                 break;
14420         }
14421 -       
14422 -       buffer_append_string(srv->errorlog_buf, filename);
14423 -       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ".");
14424 -       buffer_append_long(srv->errorlog_buf, line);
14425 -       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ") ");
14426 -       
14427 -       
14428 +
14429 +       buffer_append_string(err->buf, filename);
14430 +       BUFFER_APPEND_STRING_CONST(err->buf, ".");
14431 +       buffer_append_long(err->buf, line);
14432 +       BUFFER_APPEND_STRING_CONST(err->buf, ") ");
14433 +
14434         for(va_start(ap, fmt); *fmt; fmt++) {
14435                 int d;
14436                 char *s;
14437                 buffer *b;
14438                 off_t o;
14439 -               
14440 +
14441                 switch(*fmt) {
14442                 case 's':           /* string */
14443                         s = va_arg(ap, char *);
14444 -                       buffer_append_string(srv->errorlog_buf, s);
14445 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14446 +                       buffer_append_string(err->buf, s);
14447 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
14448                         break;
14449                 case 'b':           /* buffer */
14450                         b = va_arg(ap, buffer *);
14451 -                       buffer_append_string_buffer(srv->errorlog_buf, b);
14452 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14453 +                       buffer_append_string_buffer(err->buf, b);
14454 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
14455                         break;
14456                 case 'd':           /* int */
14457                         d = va_arg(ap, int);
14458 -                       buffer_append_long(srv->errorlog_buf, d);
14459 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14460 +                       buffer_append_long(err->buf, d);
14461 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
14462                         break;
14463                 case 'o':           /* off_t */
14464                         o = va_arg(ap, off_t);
14465 -                       buffer_append_off_t(srv->errorlog_buf, o);
14466 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14467 +                       buffer_append_off_t(err->buf, o);
14468 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
14469                         break;
14470                 case 'x':           /* int (hex) */
14471                         d = va_arg(ap, int);
14472 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "0x");
14473 -                       buffer_append_long_hex(srv->errorlog_buf, d);
14474 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14475 +                       BUFFER_APPEND_STRING_CONST(err->buf, "0x");
14476 +                       buffer_append_long_hex(err->buf, d);
14477 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
14478                         break;
14479                 case 'S':           /* string */
14480                         s = va_arg(ap, char *);
14481 -                       buffer_append_string(srv->errorlog_buf, s);
14482 +                       buffer_append_string(err->buf, s);
14483                         break;
14484                 case 'B':           /* buffer */
14485                         b = va_arg(ap, buffer *);
14486 -                       buffer_append_string_buffer(srv->errorlog_buf, b);
14487 +                       buffer_append_string_buffer(err->buf, b);
14488                         break;
14489                 case 'D':           /* int */
14490                         d = va_arg(ap, int);
14491 -                       buffer_append_long(srv->errorlog_buf, d);
14492 +                       buffer_append_long(err->buf, d);
14493                         break;
14494                 case '(':
14495                 case ')':
14496 -               case '<':       
14497 +               case '<':
14498                 case '>':
14499                 case ',':
14500                 case ' ':
14501 -                       buffer_append_string_len(srv->errorlog_buf, fmt, 1);
14502 +                       buffer_append_string_len(err->buf, fmt, 1);
14503                         break;
14504                 }
14505         }
14506         va_end(ap);
14507 -       
14508 -       switch(srv->errorlog_mode) {
14509 +
14510 +       switch(err->mode) {
14511         case ERRORLOG_FILE:
14512 -               BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "\n");
14513 -               write(srv->errorlog_fd, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1);
14514 +               BUFFER_APPEND_STRING_CONST(err->buf, "\n");
14515 +               write(err->fd, err->buf->ptr, err->buf->used - 1);
14516                 break;
14517         case ERRORLOG_STDERR:
14518 -               BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "\n");
14519 -               write(STDERR_FILENO, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1);
14520 +               BUFFER_APPEND_STRING_CONST(err->buf, "\n");
14521 +               write(STDERR_FILENO, err->buf->ptr, err->buf->used - 1);
14522                 break;
14523 +#ifdef HAVE_SYSLOG_H
14524 +       case ERRORLOG_SYSLOG:
14525 +               syslog(LOG_ERR, "%s", err->buf->ptr);
14526 +               break;
14527 +#endif
14528 +       }
14529 +
14530 +       return 0;
14531 +}
14532 +
14533 +static int log_trace_write(const char *fmt, va_list ap) {
14534 +       buffer *b;
14535 +       int l;
14536 +       errorlog *err = myconfig;
14537 +       
14538 +       b = buffer_init();
14539 +       buffer_prepare_copy(b, 1024);
14540 +       l = vsnprintf(b->ptr, b->size - 1, fmt, ap);
14541 +       if (l > 0) {
14542 +               b->used = (l > b->size - 1) ? b->size : l + 1;
14543 +       }
14544 +
14545 +       /* write b */
14546 +       switch(err->mode) {
14547 +       case ERRORLOG_FILE:
14548 +               buffer_append_string(b, "\r\n");
14549 +               write(err->fd, b->ptr, b->used - 1);
14550 +               break;
14551 +       case ERRORLOG_STDERR:
14552 +               buffer_append_string(b, "\r\n");
14553 +               write(STDERR_FILENO, b->ptr, b->used - 1);
14554 +               break;
14555 +#ifdef HAVE_SYSLOG_H
14556         case ERRORLOG_SYSLOG:
14557 -               syslog(LOG_ERR, "%s", srv->errorlog_buf->ptr);
14558 +               syslog(LOG_ERR, "%s", b->ptr);
14559                 break;
14560 +#endif
14561         }
14562         
14563 +       buffer_free(b);
14564 +
14565 +       return 0;
14566 +}
14567 +
14568 +int log_trace(const char *fmt, ...) {
14569 +       va_list ap;
14570 +
14571 +       va_start(ap, fmt);
14572 +
14573 +       log_trace_write(fmt, ap);
14574 +
14575 +       va_end(ap);
14576 +
14577         return 0;
14578  }
14579  
14580 +
14581 --- ../lighttpd-1.4.11/src/log.h        2005-08-11 01:26:36.000000000 +0300
14582 +++ lighttpd-1.4.12/src/log.h   2006-07-18 13:03:40.000000000 +0300
14583 @@ -1,13 +1,22 @@
14584  #ifndef _LOG_H_
14585  #define _LOG_H_
14586  
14587 -#include "server.h"
14588 +#include "buffer.h"
14589  
14590 -#define WP() log_error_write(srv, __FILE__, __LINE__, "");
14591 +void log_init(void); 
14592 +void log_free(void); 
14593  
14594 -int log_error_open(server *srv);
14595 -int log_error_close(server *srv);
14596 -int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...);
14597 -int log_error_cycle(server *srv);
14598 -       
14599 +int log_error_open(buffer *file, int use_syslog);
14600 +int log_error_close();
14601 +int log_error_write(void *srv, const char *filename, unsigned int line, const char *fmt, ...);
14602 +int log_error_cycle();
14603 +
14604 +#define ERROR(fmt, ...) \
14605 +       log_trace("%s.%d: (error) "fmt, __FILE__, __LINE__, __VA_ARGS__)
14606 +
14607 +#define TRACE(fmt, ...) \
14608 +       log_trace("%s.%d: (trace) "fmt, __FILE__, __LINE__, __VA_ARGS__)
14609 +
14610 +#define SEGFAULT() do { ERROR("%s", "Ooh, Ooh, Ooh. Something is not good ... going down"); abort(); } while(0)
14611 +int log_trace(const char *fmt, ...);
14612  #endif
14613 --- ../lighttpd-1.4.11/src/md5.h        2005-11-17 16:20:40.000000000 +0200
14614 +++ lighttpd-1.4.12/src/md5.h   2006-07-16 00:26:04.000000000 +0300
14615 @@ -30,9 +30,15 @@
14616  # include <inttypes.h>
14617  #endif
14618  
14619 +#ifdef _WIN32
14620 +#define UINT4 unsigned __int32
14621 +#define UINT2 unsigned __int16
14622 +#define POINTER unsigned char *
14623 +#else
14624  #define UINT4 uint32_t
14625  #define UINT2 uint16_t
14626  #define POINTER unsigned char *
14627 +#endif
14628  
14629  /* MD5 context. */
14630  typedef struct {
14631 --- ../lighttpd-1.4.11/src/mod_access.c 2006-01-14 19:44:54.000000000 +0200
14632 +++ lighttpd-1.4.12/src/mod_access.c    2006-07-16 00:26:04.000000000 +0300
14633 @@ -8,126 +8,125 @@
14634  
14635  #include "plugin.h"
14636  
14637 +#include "sys-strings.h"
14638 +
14639  typedef struct {
14640         array *access_deny;
14641  } plugin_config;
14642  
14643  typedef struct {
14644         PLUGIN_DATA;
14645 -       
14646 +
14647         plugin_config **config_storage;
14648 -       
14649 -       plugin_config conf; 
14650 +
14651 +       plugin_config conf;
14652  } plugin_data;
14653  
14654  INIT_FUNC(mod_access_init) {
14655         plugin_data *p;
14656 -       
14657 +
14658         p = calloc(1, sizeof(*p));
14659 -       
14660 +
14661         return p;
14662  }
14663  
14664  FREE_FUNC(mod_access_free) {
14665         plugin_data *p = p_d;
14666 -       
14667 +
14668         UNUSED(srv);
14669  
14670         if (!p) return HANDLER_GO_ON;
14671 -       
14672 +
14673         if (p->config_storage) {
14674                 size_t i;
14675                 for (i = 0; i < srv->config_context->used; i++) {
14676                         plugin_config *s = p->config_storage[i];
14677 -                       
14678 +
14679                         array_free(s->access_deny);
14680 -                       
14681 +
14682                         free(s);
14683                 }
14684                 free(p->config_storage);
14685         }
14686 -       
14687 +
14688         free(p);
14689 -       
14690 +
14691         return HANDLER_GO_ON;
14692  }
14693  
14694  SETDEFAULTS_FUNC(mod_access_set_defaults) {
14695         plugin_data *p = p_d;
14696         size_t i = 0;
14697 -       
14698 -       config_values_t cv[] = { 
14699 +
14700 +       config_values_t cv[] = {
14701                 { "url.access-deny",             NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
14702                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
14703         };
14704 -       
14705 +
14706         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
14707 -       
14708 +
14709         for (i = 0; i < srv->config_context->used; i++) {
14710                 plugin_config *s;
14711 -               
14712 +
14713                 s = calloc(1, sizeof(plugin_config));
14714                 s->access_deny    = array_init();
14715 -               
14716 +
14717                 cv[0].destination = s->access_deny;
14718 -               
14719 +
14720                 p->config_storage[i] = s;
14721 -       
14722 +
14723                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
14724                         return HANDLER_ERROR;
14725                 }
14726         }
14727 -       
14728 +
14729         return HANDLER_GO_ON;
14730  }
14731  
14732 -#define PATCH(x) \
14733 -       p->conf.x = s->x;
14734  static int mod_access_patch_connection(server *srv, connection *con, plugin_data *p) {
14735         size_t i, j;
14736         plugin_config *s = p->config_storage[0];
14737  
14738 -       PATCH(access_deny);
14739 -       
14740 +       PATCH_OPTION(access_deny);
14741 +
14742         /* skip the first, the global context */
14743         for (i = 1; i < srv->config_context->used; i++) {
14744                 data_config *dc = (data_config *)srv->config_context->data[i];
14745                 s = p->config_storage[i];
14746 -               
14747 +
14748                 /* condition didn't match */
14749                 if (!config_check_cond(srv, con, dc)) continue;
14750 -               
14751 +
14752                 /* merge config */
14753                 for (j = 0; j < dc->value->used; j++) {
14754                         data_unset *du = dc->value->data[j];
14755 -                       
14756 +
14757                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.access-deny"))) {
14758 -                               PATCH(access_deny);
14759 +                               PATCH_OPTION(access_deny);
14760                         }
14761                 }
14762         }
14763 -       
14764 +
14765         return 0;
14766  }
14767 -#undef PATCH
14768  
14769  URIHANDLER_FUNC(mod_access_uri_handler) {
14770         plugin_data *p = p_d;
14771         int s_len;
14772         size_t k;
14773 -       
14774 +
14775         if (con->uri.path->used == 0) return HANDLER_GO_ON;
14776 -       
14777 +
14778         mod_access_patch_connection(srv, con, p);
14779 -       
14780 +
14781         s_len = con->uri.path->used - 1;
14782 -       
14783 +
14784         for (k = 0; k < p->conf.access_deny->used; k++) {
14785                 data_string *ds = (data_string *)p->conf.access_deny->data[k];
14786                 int ct_len = ds->value->used - 1;
14787 -               
14788 +
14789                 if (ct_len > s_len) continue;
14790 -               
14791 +
14792                 if (ds->value->used == 0) continue;
14793  
14794                 /* if we have a case-insensitive FS we have to lower-case the URI here too */
14795 @@ -135,18 +134,18 @@
14796                 if (con->conf.force_lowercase_filenames) {
14797                         if (0 == strncasecmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
14798                                 con->http_status = 403;
14799 -                       
14800 +
14801                                 return HANDLER_FINISHED;
14802                         }
14803                 } else {
14804                         if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
14805                                 con->http_status = 403;
14806 -                       
14807 +
14808                                 return HANDLER_FINISHED;
14809                         }
14810                 }
14811         }
14812 -       
14813 +
14814         /* not found */
14815         return HANDLER_GO_ON;
14816  }
14817 @@ -155,13 +154,13 @@
14818  int mod_access_plugin_init(plugin *p) {
14819         p->version     = LIGHTTPD_VERSION_ID;
14820         p->name        = buffer_init_string("access");
14821 -       
14822 +
14823         p->init        = mod_access_init;
14824         p->set_defaults = mod_access_set_defaults;
14825         p->handle_uri_clean  = mod_access_uri_handler;
14826         p->cleanup     = mod_access_free;
14827 -       
14828 +
14829         p->data        = NULL;
14830 -       
14831 +
14832         return 0;
14833  }
14834 --- ../lighttpd-1.4.11/src/mod_accesslog.c      2006-01-31 14:01:43.000000000 +0200
14835 +++ lighttpd-1.4.12/src/mod_accesslog.c 2006-07-16 00:26:04.000000000 +0300
14836 @@ -6,8 +6,7 @@
14837  #include <ctype.h>
14838  #include <stdlib.h>
14839  #include <string.h>
14840 -#include <fcntl.h>
14841 -#include <unistd.h>
14842 +#include <fcntl.h> /* only the defines on windows */
14843  #include <errno.h>
14844  #include <time.h>
14845  
14846 @@ -22,6 +21,7 @@
14847  #include "inet_ntop_cache.h"
14848  
14849  #include "sys-socket.h"
14850 +#include "sys-files.h"
14851  
14852  #ifdef HAVE_SYSLOG_H
14853  # include <syslog.h>
14854 @@ -29,7 +29,7 @@
14855  
14856  typedef struct {
14857         char key;
14858 -       enum { 
14859 +       enum {
14860                 FORMAT_UNSET,
14861                         FORMAT_UNSUPPORTED,
14862                         FORMAT_PERCENT,
14863 @@ -41,7 +41,7 @@
14864                         FORMAT_STATUS,
14865                         FORMAT_BYTES_OUT_NO_HEADER,
14866                         FORMAT_HEADER,
14867 -                       
14868 +
14869                         FORMAT_REMOTE_ADDR,
14870                         FORMAT_LOCAL_ADDR,
14871                         FORMAT_COOKIE,
14872 @@ -59,20 +59,20 @@
14873                         FORMAT_CONNECTION_STATUS,
14874                         FORMAT_BYTES_IN,
14875                         FORMAT_BYTES_OUT,
14876 -                       
14877 +
14878                         FORMAT_RESPONSE_HEADER
14879         } type;
14880  } format_mapping;
14881  
14882  /**
14883 - * 
14884 - * 
14885 + *
14886 + *
14887   * "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
14888 - * 
14889 + *
14890   */
14891  
14892 -const format_mapping fmap[] = 
14893 -{ 
14894 +const format_mapping fmap[] =
14895 +{
14896         { '%', FORMAT_PERCENT },
14897         { 'h', FORMAT_REMOTE_HOST },
14898         { 'l', FORMAT_REMOTE_IDENT },
14899 @@ -82,7 +82,7 @@
14900         { 's', FORMAT_STATUS },
14901         { 'b', FORMAT_BYTES_OUT_NO_HEADER },
14902         { 'i', FORMAT_HEADER },
14903 -       
14904 +
14905         { 'a', FORMAT_REMOTE_ADDR },
14906         { 'A', FORMAT_LOCAL_ADDR },
14907         { 'B', FORMAT_BYTES_OUT_NO_HEADER },
14908 @@ -103,23 +103,23 @@
14909         { 'X', FORMAT_CONNECTION_STATUS },
14910         { 'I', FORMAT_BYTES_IN },
14911         { 'O', FORMAT_BYTES_OUT },
14912 -       
14913 +
14914         { 'o', FORMAT_RESPONSE_HEADER },
14915 -       
14916 +
14917         { '\0', FORMAT_UNSET }
14918  };
14919  
14920  
14921  typedef struct {
14922         enum { FIELD_UNSET, FIELD_STRING, FIELD_FORMAT } type;
14923 -       
14924 +
14925         buffer *string;
14926         int field;
14927  } format_field;
14928  
14929  typedef struct {
14930         format_field **ptr;
14931 -       
14932 +
14933         size_t used;
14934         size_t size;
14935  } format_fields;
14936 @@ -128,39 +128,39 @@
14937         buffer *access_logfile;
14938         buffer *format;
14939         unsigned short use_syslog;
14940 -       
14941 -       
14942 +
14943 +
14944         int    log_access_fd;
14945         time_t last_generated_accesslog_ts;
14946         time_t *last_generated_accesslog_ts_ptr;
14947 -       
14948 -       
14949 +
14950 +
14951         buffer *access_logbuffer;
14952         buffer *ts_accesslog_str;
14953 -       
14954 +
14955         format_fields *parsed_format;
14956  } plugin_config;
14957  
14958  typedef struct {
14959         PLUGIN_DATA;
14960 -       
14961 +
14962         plugin_config **config_storage;
14963 -       plugin_config conf; 
14964 +       plugin_config conf;
14965  } plugin_data;
14966  
14967  INIT_FUNC(mod_accesslog_init) {
14968         plugin_data *p;
14969 -       
14970 +
14971         p = calloc(1, sizeof(*p));
14972 -       
14973 +
14974         return p;
14975  }
14976  
14977  int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) {
14978         size_t i, j, k = 0, start = 0;
14979 -       
14980 +
14981         for (i = 0; i < format->used - 1; i++) {
14982 -               
14983 +
14984                 switch(format->ptr[i]) {
14985                 case '%':
14986                         if (start != i) {
14987 @@ -173,19 +173,19 @@
14988                                         fields->size += 16;
14989                                         fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
14990                                 }
14991 -                               
14992 +
14993                                 fields->ptr[fields->used] = malloc(sizeof(format_fields));
14994                                 fields->ptr[fields->used]->type = FIELD_STRING;
14995                                 fields->ptr[fields->used]->string = buffer_init();
14996 -                               
14997 +
14998                                 buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
14999 -                               
15000 +
15001                                 fields->used++;
15002                         }
15003 -                       
15004 -                       
15005 +
15006 +
15007                         /* we need a new field */
15008 -                       
15009 +
15010                         if (fields->size == 0) {
15011                                 fields->size = 16;
15012                                 fields->used = 0;
15013 @@ -194,43 +194,43 @@
15014                                 fields->size += 16;
15015                                 fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
15016                         }
15017 -                       
15018 +
15019                         /* search for the terminating command */
15020                         switch (format->ptr[i+1]) {
15021                         case '>':
15022                         case '<':
15023                                 /* only for s */
15024 -                               
15025 +
15026                                 for (j = 0; fmap[j].key != '\0'; j++) {
15027                                         if (fmap[j].key != format->ptr[i+2]) continue;
15028 -                                       
15029 +
15030                                         /* found key */
15031 -                                               
15032 +
15033                                         fields->ptr[fields->used] = malloc(sizeof(format_fields));
15034                                         fields->ptr[fields->used]->type = FIELD_FORMAT;
15035                                         fields->ptr[fields->used]->field = fmap[j].type;
15036                                         fields->ptr[fields->used]->string = NULL;
15037 -                                       
15038 +
15039                                         fields->used++;
15040 -                                       
15041 +
15042                                         break;
15043                                 }
15044 -                               
15045 +
15046                                 if (fmap[j].key == '\0') {
15047                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15048                                         return -1;
15049                                 }
15050 -                               
15051 +
15052                                 start = i + 3;
15053 -                               
15054 +
15055                                 break;
15056                         case '{':
15057                                 /* go forward to } */
15058 -                               
15059 +
15060                                 for (k = i+2; k < format->used - 1; k++) {
15061                                         if (format->ptr[k] == '}') break;
15062                                 }
15063 -                               
15064 +
15065                                 if (k == format->used - 1) {
15066                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15067                                         return -1;
15068 @@ -239,62 +239,62 @@
15069                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15070                                         return -1;
15071                                 }
15072 -                               
15073 +
15074                                 for (j = 0; fmap[j].key != '\0'; j++) {
15075                                         if (fmap[j].key != format->ptr[k+1]) continue;
15076 -                                       
15077 +
15078                                         /* found key */
15079 -                                               
15080 +
15081                                         fields->ptr[fields->used] = malloc(sizeof(format_fields));
15082                                         fields->ptr[fields->used]->type = FIELD_FORMAT;
15083                                         fields->ptr[fields->used]->field = fmap[j].type;
15084                                         fields->ptr[fields->used]->string = buffer_init();
15085 -                                       
15086 +
15087                                         buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + i + 2, k - (i + 2));
15088 -                                       
15089 +
15090                                         fields->used++;
15091 -                                       
15092 +
15093                                         break;
15094                                 }
15095 -                               
15096 +
15097                                 if (fmap[j].key == '\0') {
15098                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15099                                         return -1;
15100                                 }
15101 -                               
15102 +
15103                                 start = k + 2;
15104 -                               
15105 +
15106                                 break;
15107                         default:
15108                                 for (j = 0; fmap[j].key != '\0'; j++) {
15109                                         if (fmap[j].key != format->ptr[i+1]) continue;
15110 -                                       
15111 +
15112                                         /* found key */
15113 -                                               
15114 +
15115                                         fields->ptr[fields->used] = malloc(sizeof(format_fields));
15116                                         fields->ptr[fields->used]->type = FIELD_FORMAT;
15117                                         fields->ptr[fields->used]->field = fmap[j].type;
15118                                         fields->ptr[fields->used]->string = NULL;
15119 -                                       
15120 +
15121                                         fields->used++;
15122 -                                       
15123 +
15124                                         break;
15125                                 }
15126 -                               
15127 +
15128                                 if (fmap[j].key == '\0') {
15129                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15130                                         return -1;
15131                                 }
15132 -                               
15133 +
15134                                 start = i + 2;
15135 -                               
15136 +
15137                                 break;
15138                         }
15139 -                       
15140 +
15141                         break;
15142                 }
15143         }
15144 -       
15145 +
15146         if (start < i) {
15147                 /* copy the string */
15148                 if (fields->size == 0) {
15149 @@ -305,32 +305,32 @@
15150                         fields->size += 16;
15151                         fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
15152                 }
15153 -               
15154 +
15155                 fields->ptr[fields->used] = malloc(sizeof(format_fields));
15156                 fields->ptr[fields->used]->type = FIELD_STRING;
15157                 fields->ptr[fields->used]->string = buffer_init();
15158 -               
15159 +
15160                 buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
15161 -               
15162 +
15163                 fields->used++;
15164         }
15165 -       
15166 +
15167         return 0;
15168  }
15169  
15170  FREE_FUNC(mod_accesslog_free) {
15171         plugin_data *p = p_d;
15172         size_t i;
15173 -       
15174 +
15175         if (!p) return HANDLER_GO_ON;
15176 -       
15177 +
15178         if (p->config_storage) {
15179 -               
15180 +
15181                 for (i = 0; i < srv->config_context->used; i++) {
15182                         plugin_config *s = p->config_storage[i];
15183  
15184                         if (!s) continue;
15185 -                       
15186 +
15187                         if (s->access_logbuffer->used) {
15188                                 if (s->use_syslog) {
15189  # ifdef HAVE_SYSLOG_H
15190 @@ -342,14 +342,14 @@
15191                                         write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
15192                                 }
15193                         }
15194 -                       
15195 +
15196                         if (s->log_access_fd != -1) close(s->log_access_fd);
15197 -                       
15198 +
15199                         buffer_free(s->ts_accesslog_str);
15200                         buffer_free(s->access_logbuffer);
15201                         buffer_free(s->format);
15202                         buffer_free(s->access_logfile);
15203 -                       
15204 +
15205                         if (s->parsed_format) {
15206                                 size_t j;
15207                                 for (j = 0; j < s->parsed_format->used; j++) {
15208 @@ -359,36 +359,36 @@
15209                                 free(s->parsed_format->ptr);
15210                                 free(s->parsed_format);
15211                         }
15212 -                       
15213 +
15214                         free(s);
15215                 }
15216 -       
15217 +
15218                 free(p->config_storage);
15219         }
15220 -       
15221 +
15222         free(p);
15223 -       
15224 +
15225         return HANDLER_GO_ON;
15226  }
15227  
15228  SETDEFAULTS_FUNC(log_access_open) {
15229         plugin_data *p = p_d;
15230         size_t i = 0;
15231 -       
15232 -       config_values_t cv[] = { 
15233 +
15234 +       config_values_t cv[] = {
15235                 { "accesslog.filename",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
15236                 { "accesslog.use-syslog",           NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
15237                 { "accesslog.format",               NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
15238                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
15239         };
15240 -       
15241 +
15242         if (!p) return HANDLER_ERROR;
15243 -       
15244 +
15245         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
15246 -       
15247 +
15248         for (i = 0; i < srv->config_context->used; i++) {
15249                 plugin_config *s;
15250 -               
15251 +
15252                 s = calloc(1, sizeof(plugin_config));
15253                 s->access_logfile = buffer_init();
15254                 s->format = buffer_init();
15255 @@ -397,44 +397,44 @@
15256                 s->log_access_fd = -1;
15257                 s->last_generated_accesslog_ts = 0;
15258                 s->last_generated_accesslog_ts_ptr = &(s->last_generated_accesslog_ts);
15259 -               
15260 -       
15261 +
15262 +
15263                 cv[0].destination = s->access_logfile;
15264                 cv[1].destination = &(s->use_syslog);
15265                 cv[2].destination = s->format;
15266 -       
15267 +
15268                 p->config_storage[i] = s;
15269 -               
15270 +
15271                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
15272                         return HANDLER_ERROR;
15273                 }
15274 -               
15275 +
15276                 if (i == 0 && buffer_is_empty(s->format)) {
15277                         /* set a default logfile string */
15278 -                       
15279 +
15280                         buffer_copy_string(s->format, "%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"");
15281                 }
15282 -               
15283 +
15284                 /* parse */
15285 -               
15286 +
15287                 if (s->format->used) {
15288                         s->parsed_format = calloc(1, sizeof(*(s->parsed_format)));
15289 -                       
15290 +
15291                         if (-1 == accesslog_parse_format(srv, s->parsed_format, s->format)) {
15292  
15293 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
15294 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
15295                                                 "parsing accesslog-definition failed:", s->format);
15296  
15297                                 return HANDLER_ERROR;
15298                         }
15299  #if 0
15300 -                       /* debugging */                 
15301 +                       /* debugging */
15302                         for (j = 0; j < s->parsed_format->used; j++) {
15303                                 switch (s->parsed_format->ptr[j]->type) {
15304                                 case FIELD_FORMAT:
15305 -                                       log_error_write(srv, __FILE__, __LINE__, "ssds", 
15306 +                                       log_error_write(srv, __FILE__, __LINE__, "ssds",
15307                                                         "config:", "format", s->parsed_format->ptr[j]->field,
15308 -                                                       s->parsed_format->ptr[j]->string ? 
15309 +                                                       s->parsed_format->ptr[j]->string ?
15310                                                         s->parsed_format->ptr[j]->string->ptr : "" );
15311                                         break;
15312                                 case FIELD_STRING:
15313 @@ -446,52 +446,52 @@
15314                         }
15315  #endif
15316                 }
15317 -               
15318 +
15319                 if (s->use_syslog) {
15320                         /* ignore the next checks */
15321                         continue;
15322                 }
15323 -               
15324 +
15325                 if (buffer_is_empty(s->access_logfile)) continue;
15326 -               
15327 +
15328                 if (s->access_logfile->ptr[0] == '|') {
15329  #ifdef HAVE_FORK
15330                         /* create write pipe and spawn process */
15331 -                       
15332 +
15333                         int to_log_fds[2];
15334                         pid_t pid;
15335 -                       
15336 +
15337                         if (pipe(to_log_fds)) {
15338                                 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed: ", strerror(errno));
15339                                 return HANDLER_ERROR;
15340                         }
15341 -                       
15342 +
15343                         /* fork, execve */
15344                         switch (pid = fork()) {
15345 -                       case 0: 
15346 +                       case 0:
15347                                 /* child */
15348 -                               
15349 +
15350                                 close(STDIN_FILENO);
15351                                 dup2(to_log_fds[0], STDIN_FILENO);
15352                                 close(to_log_fds[0]);
15353                                 /* not needed */
15354                                 close(to_log_fds[1]);
15355 -                               
15356 +
15357                                 /* we don't need the client socket */
15358                                 for (i = 3; i < 256; i++) {
15359                                         close(i);
15360                                 }
15361 -                               
15362 -                               /* exec the log-process (skip the | ) 
15363 -                                * 
15364 +
15365 +                               /* exec the log-process (skip the | )
15366 +                                *
15367                                  */
15368 -                               
15369 +
15370                                 execl("/bin/sh", "sh", "-c", s->access_logfile->ptr + 1, NULL);
15371  
15372 -                               log_error_write(srv, __FILE__, __LINE__, "sss", 
15373 -                                               "spawning log-process failed: ", strerror(errno), 
15374 +                               log_error_write(srv, __FILE__, __LINE__, "sss",
15375 +                                               "spawning log-process failed: ", strerror(errno),
15376                                                 s->access_logfile->ptr + 1);
15377 -                               
15378 +
15379                                 exit(-1);
15380                                 break;
15381                         case -1:
15382 @@ -500,27 +500,28 @@
15383                                 break;
15384                         default:
15385                                 close(to_log_fds[0]);
15386 -                               
15387 +
15388                                 s->log_access_fd = to_log_fds[1];
15389 -                               
15390 +
15391                                 break;
15392                         }
15393  #else
15394                         return -1;
15395  #endif
15396 -               } else if (-1 == (s->log_access_fd = 
15397 +               } else if (-1 == (s->log_access_fd =
15398                                   open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
15399 -                       
15400 -                       log_error_write(srv, __FILE__, __LINE__, "ssb", 
15401 -                                       "opening access-log failed:", 
15402 +
15403 +                       log_error_write(srv, __FILE__, __LINE__, "ssb",
15404 +                                       "opening access-log failed:",
15405                                         strerror(errno), s->access_logfile);
15406 -                       
15407 +
15408                         return HANDLER_ERROR;
15409                 }
15410 +#ifndef _WIN32
15411                 fcntl(s->log_access_fd, F_SETFD, FD_CLOEXEC);
15412 -       
15413 +#endif
15414         }
15415 -       
15416 +
15417         return HANDLER_GO_ON;
15418  }
15419  
15420 @@ -529,7 +530,7 @@
15421         size_t i;
15422  
15423         if (!p->config_storage) return HANDLER_GO_ON;
15424 -               
15425 +
15426         for (i = 0; i < srv->config_context->used; i++) {
15427                 plugin_config *s = p->config_storage[i];
15428  
15429 @@ -544,90 +545,87 @@
15430                         } else if (s->log_access_fd != -1) {
15431                                 write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
15432                         }
15433 -                       
15434 +
15435                         buffer_reset(s->access_logbuffer);
15436                 }
15437 -               
15438 +
15439                 if (s->use_syslog == 0 &&
15440                     !buffer_is_empty(s->access_logfile) &&
15441                     s->access_logfile->ptr[0] != '|') {
15442 -                       
15443 +
15444                         close(s->log_access_fd);
15445 -                       
15446 -                       if (-1 == (s->log_access_fd = 
15447 +
15448 +                       if (-1 == (s->log_access_fd =
15449                                    open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
15450 -                               
15451 +
15452                                 log_error_write(srv, __FILE__, __LINE__, "ss", "cycling access-log failed:", strerror(errno));
15453 -                               
15454 +
15455                                 return HANDLER_ERROR;
15456                         }
15457                 }
15458         }
15459 -       
15460 +
15461         return HANDLER_GO_ON;
15462  }
15463  
15464 -#define PATCH(x) \
15465 -       p->conf.x = s->x;
15466  static int mod_accesslog_patch_connection(server *srv, connection *con, plugin_data *p) {
15467         size_t i, j;
15468         plugin_config *s = p->config_storage[0];
15469 -       
15470 -       PATCH(access_logfile);
15471 -       PATCH(format);
15472 -       PATCH(log_access_fd);
15473 -       PATCH(last_generated_accesslog_ts_ptr);
15474 -       PATCH(access_logbuffer);
15475 -       PATCH(ts_accesslog_str);
15476 -       PATCH(parsed_format);
15477 -       PATCH(use_syslog);
15478 -       
15479 +
15480 +       PATCH_OPTION(access_logfile);
15481 +       PATCH_OPTION(format);
15482 +       PATCH_OPTION(log_access_fd);
15483 +       PATCH_OPTION(last_generated_accesslog_ts_ptr);
15484 +       PATCH_OPTION(access_logbuffer);
15485 +       PATCH_OPTION(ts_accesslog_str);
15486 +       PATCH_OPTION(parsed_format);
15487 +       PATCH_OPTION(use_syslog);
15488 +
15489         /* skip the first, the global context */
15490         for (i = 1; i < srv->config_context->used; i++) {
15491                 data_config *dc = (data_config *)srv->config_context->data[i];
15492                 s = p->config_storage[i];
15493 -               
15494 +
15495                 /* condition didn't match */
15496                 if (!config_check_cond(srv, con, dc)) continue;
15497 -               
15498 +
15499                 /* merge config */
15500                 for (j = 0; j < dc->value->used; j++) {
15501                         data_unset *du = dc->value->data[j];
15502 -                       
15503 +
15504                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.filename"))) {
15505 -                               PATCH(access_logfile);
15506 -                               PATCH(log_access_fd);
15507 -                               PATCH(last_generated_accesslog_ts_ptr);
15508 -                               PATCH(access_logbuffer);
15509 -                               PATCH(ts_accesslog_str);
15510 +                               PATCH_OPTION(access_logfile);
15511 +                               PATCH_OPTION(log_access_fd);
15512 +                               PATCH_OPTION(last_generated_accesslog_ts_ptr);
15513 +                               PATCH_OPTION(access_logbuffer);
15514 +                               PATCH_OPTION(ts_accesslog_str);
15515                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.format"))) {
15516 -                               PATCH(format);
15517 -                               PATCH(parsed_format);
15518 +                               PATCH_OPTION(format);
15519 +                               PATCH_OPTION(parsed_format);
15520                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.use-syslog"))) {
15521 -                               PATCH(use_syslog);
15522 +                               PATCH_OPTION(use_syslog);
15523                         }
15524                 }
15525         }
15526 -       
15527 +
15528         return 0;
15529  }
15530 -#undef PATCH
15531  
15532  REQUESTDONE_FUNC(log_access_write) {
15533         plugin_data *p = p_d;
15534         buffer *b;
15535         size_t j;
15536 -       
15537 +
15538         int newts = 0;
15539         data_string *ds;
15540 -       
15541 +
15542         mod_accesslog_patch_connection(srv, con, p);
15543 -       
15544 +
15545         b = p->conf.access_logbuffer;
15546         if (b->used == 0) {
15547                 buffer_copy_string(b, "");
15548         }
15549 -       
15550 +
15551         for (j = 0; j < p->conf.parsed_format->used; j++) {
15552                 switch(p->conf.parsed_format->ptr[j]->type) {
15553                 case FIELD_STRING:
15554 @@ -636,14 +634,14 @@
15555                 case FIELD_FORMAT:
15556                         switch(p->conf.parsed_format->ptr[j]->field) {
15557                         case FORMAT_TIMESTAMP:
15558 -                               
15559 +
15560                                 /* cache the generated timestamp */
15561                                 if (srv->cur_ts != *(p->conf.last_generated_accesslog_ts_ptr)) {
15562                                         struct tm tm;
15563  #if defined(HAVE_STRUCT_TM_GMTOFF)
15564                                         long scd, hrs, min;
15565  #endif
15566 -               
15567 +
15568                                         buffer_prepare_copy(p->conf.ts_accesslog_str, 255);
15569  #if defined(HAVE_STRUCT_TM_GMTOFF)
15570  # ifdef HAVE_LOCALTIME_R
15571 @@ -653,17 +651,17 @@
15572                                         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)));
15573  # endif
15574                                         p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
15575 -                                       
15576 +
15577                                         buffer_append_string(p->conf.ts_accesslog_str, tm.tm_gmtoff >= 0 ? "+" : "-");
15578 -                                       
15579 +
15580                                         scd = abs(tm.tm_gmtoff);
15581                                         hrs = scd / 3600;
15582                                         min = (scd % 3600) / 60;
15583 -                                       
15584 +
15585                                         /* hours */
15586                                         if (hrs < 10) buffer_append_string(p->conf.ts_accesslog_str, "0");
15587                                         buffer_append_long(p->conf.ts_accesslog_str, hrs);
15588 -                                       
15589 +
15590                                         if (min < 10) buffer_append_string(p->conf.ts_accesslog_str, "0");
15591                                         buffer_append_long(p->conf.ts_accesslog_str, min);
15592                                         BUFFER_APPEND_STRING_CONST(p->conf.ts_accesslog_str, "]");
15593 @@ -676,20 +674,20 @@
15594  #endif
15595                                         p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
15596  #endif
15597 -                                       
15598 +
15599                                         *(p->conf.last_generated_accesslog_ts_ptr) = srv->cur_ts;
15600                                         newts = 1;
15601                                 }
15602 -                               
15603 +
15604                                 buffer_append_string_buffer(b, p->conf.ts_accesslog_str);
15605 -                               
15606 +
15607                                 break;
15608                         case FORMAT_REMOTE_HOST:
15609 -       
15610 +
15611                                 /* handle inet_ntop cache */
15612 -       
15613 +
15614                                 buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
15615 -                               
15616 +
15617                                 break;
15618                         case FORMAT_REMOTE_IDENT:
15619                                 /* ident */
15620 @@ -710,10 +708,10 @@
15621                         case FORMAT_STATUS:
15622                                 buffer_append_long(b, con->http_status);
15623                                 break;
15624 -       
15625 +
15626                         case FORMAT_BYTES_OUT_NO_HEADER:
15627                                 if (con->bytes_written > 0) {
15628 -                                       buffer_append_off_t(b, 
15629 +                                       buffer_append_off_t(b,
15630                                                             con->bytes_written - con->bytes_header <= 0 ? 0 : con->bytes_written - con->bytes_header);
15631                                 } else {
15632                                         BUFFER_APPEND_STRING_CONST(b, "-");
15633 @@ -772,7 +770,7 @@
15634                                 }
15635                                 break;
15636                         case FORMAT_REQUEST_PROTOCOL:
15637 -                               buffer_append_string(b, 
15638 +                               buffer_append_string(b,
15639                                                      con->request.http_version == HTTP_VERSION_1_1 ? "HTTP/1.1" : "HTTP/1.0");
15640                                 break;
15641                         case FORMAT_REQUEST_METHOD:
15642 @@ -801,7 +799,7 @@
15643                                  { 'D', FORMAT_TIME_USED_MS },
15644                                  { 'e', FORMAT_ENV },
15645                                  */
15646 -                               
15647 +
15648                                 break;
15649                         }
15650                         break;
15651 @@ -809,7 +807,7 @@
15652                         break;
15653                 }
15654         }
15655 -       
15656 +
15657         BUFFER_APPEND_STRING_CONST(b, "\n");
15658  
15659         if (p->conf.use_syslog ||  /* syslog doesn't cache */
15660 @@ -828,7 +826,7 @@
15661                 }
15662                 buffer_reset(b);
15663         }
15664 -       
15665 +
15666         return HANDLER_GO_ON;
15667  }
15668  
15669 @@ -836,15 +834,15 @@
15670  int mod_accesslog_plugin_init(plugin *p) {
15671         p->version     = LIGHTTPD_VERSION_ID;
15672         p->name        = buffer_init_string("accesslog");
15673 -       
15674 +
15675         p->init        = mod_accesslog_init;
15676         p->set_defaults= log_access_open;
15677         p->cleanup     = mod_accesslog_free;
15678 -       
15679 +
15680         p->handle_request_done  = log_access_write;
15681         p->handle_sighup        = log_access_cycle;
15682 -       
15683 +
15684         p->data        = NULL;
15685 -       
15686 +
15687         return 0;
15688  }
15689 --- ../lighttpd-1.4.11/src/mod_alias.c  2006-03-01 23:18:51.000000000 +0200
15690 +++ lighttpd-1.4.12/src/mod_alias.c     2006-07-16 00:26:03.000000000 +0300
15691 @@ -8,6 +8,7 @@
15692  #include "buffer.h"
15693  
15694  #include "plugin.h"
15695 +#include "sys-strings.h"
15696  
15697  /* plugin config for all request/connections */
15698  typedef struct {
15699 @@ -16,44 +17,44 @@
15700  
15701  typedef struct {
15702         PLUGIN_DATA;
15703 -       
15704 +
15705         plugin_config **config_storage;
15706 -       
15707 -       plugin_config conf; 
15708 +
15709 +       plugin_config conf;
15710  } plugin_data;
15711  
15712  /* init the plugin data */
15713  INIT_FUNC(mod_alias_init) {
15714         plugin_data *p;
15715 -       
15716 +
15717         p = calloc(1, sizeof(*p));
15718 -       
15719 -       
15720 -       
15721 +
15722 +
15723 +
15724         return p;
15725  }
15726  
15727  /* detroy the plugin data */
15728  FREE_FUNC(mod_alias_free) {
15729         plugin_data *p = p_d;
15730 -       
15731 +
15732         if (!p) return HANDLER_GO_ON;
15733 -       
15734 +
15735         if (p->config_storage) {
15736                 size_t i;
15737 -               
15738 +
15739                 for (i = 0; i < srv->config_context->used; i++) {
15740                         plugin_config *s = p->config_storage[i];
15741 -                       
15742 +
15743                         array_free(s->alias);
15744 -                       
15745 +
15746                         free(s);
15747                 }
15748                 free(p->config_storage);
15749         }
15750 -       
15751 +
15752         free(p);
15753 -       
15754 +
15755         return HANDLER_GO_ON;
15756  }
15757  
15758 @@ -62,25 +63,25 @@
15759  SETDEFAULTS_FUNC(mod_alias_set_defaults) {
15760         plugin_data *p = p_d;
15761         size_t i = 0;
15762 -       
15763 -       config_values_t cv[] = { 
15764 +
15765 +       config_values_t cv[] = {
15766                 { "alias.url",                  NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
15767                 { NULL,                         NULL, T_CONFIG_UNSET,  T_CONFIG_SCOPE_UNSET }
15768         };
15769 -       
15770 +
15771         if (!p) return HANDLER_ERROR;
15772 -       
15773 +
15774         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
15775 -       
15776 +
15777         for (i = 0; i < srv->config_context->used; i++) {
15778                 plugin_config *s;
15779 -               
15780 +
15781                 s = calloc(1, sizeof(plugin_config));
15782 -               s->alias = array_init();        
15783 +               s->alias = array_init();
15784                 cv[0].destination = s->alias;
15785 -               
15786 +
15787                 p->config_storage[i] = s;
15788 -               
15789 +
15790                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
15791                         return HANDLER_ERROR;
15792                 }
15793 @@ -110,76 +111,73 @@
15794                         }
15795                 }
15796         }
15797 -       
15798 +
15799         return HANDLER_GO_ON;
15800  }
15801  
15802 -#define PATCH(x) \
15803 -       p->conf.x = s->x;
15804  static int mod_alias_patch_connection(server *srv, connection *con, plugin_data *p) {
15805         size_t i, j;
15806         plugin_config *s = p->config_storage[0];
15807 -       
15808 -       PATCH(alias);
15809 -       
15810 +
15811 +       PATCH_OPTION(alias);
15812 +
15813         /* skip the first, the global context */
15814         for (i = 1; i < srv->config_context->used; i++) {
15815                 data_config *dc = (data_config *)srv->config_context->data[i];
15816                 s = p->config_storage[i];
15817 -               
15818 +
15819                 /* condition didn't match */
15820                 if (!config_check_cond(srv, con, dc)) continue;
15821 -               
15822 +
15823                 /* merge config */
15824                 for (j = 0; j < dc->value->used; j++) {
15825                         data_unset *du = dc->value->data[j];
15826 -                       
15827 +
15828                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("alias.url"))) {
15829 -                               PATCH(alias);
15830 +                               PATCH_OPTION(alias);
15831                         }
15832                 }
15833         }
15834 -       
15835 +
15836         return 0;
15837  }
15838 -#undef PATCH
15839  
15840  PHYSICALPATH_FUNC(mod_alias_physical_handler) {
15841         plugin_data *p = p_d;
15842         int uri_len, basedir_len;
15843         char *uri_ptr;
15844         size_t k;
15845 -       
15846 +
15847         if (con->physical.path->used == 0) return HANDLER_GO_ON;
15848 -       
15849 +
15850         mod_alias_patch_connection(srv, con, p);
15851 -       
15852 +
15853         /* not to include the tailing slash */
15854         basedir_len = (con->physical.basedir->used - 1) - 1;
15855         uri_len = con->physical.path->used - 1 - basedir_len;
15856         uri_ptr = con->physical.path->ptr + basedir_len;
15857 -       
15858 +
15859         for (k = 0; k < p->conf.alias->used; k++) {
15860                 data_string *ds = (data_string *)p->conf.alias->data[k];
15861                 int alias_len = ds->key->used - 1;
15862 -               
15863 +
15864                 if (alias_len > uri_len) continue;
15865                 if (ds->key->used == 0) continue;
15866 -               
15867 +
15868                 if (0 == (con->conf.force_lowercase_filenames ?
15869                                         strncasecmp(uri_ptr, ds->key->ptr, alias_len) :
15870                                         strncmp(uri_ptr, ds->key->ptr, alias_len))) {
15871                         /* matched */
15872 -                       
15873 +
15874                         buffer_copy_string_buffer(con->physical.basedir, ds->value);
15875                         buffer_copy_string_buffer(srv->tmp_buf, ds->value);
15876                         buffer_append_string(srv->tmp_buf, uri_ptr + alias_len);
15877                         buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
15878 -                       
15879 +
15880                         return HANDLER_GO_ON;
15881                 }
15882         }
15883 -       
15884 +
15885         /* not found */
15886         return HANDLER_GO_ON;
15887  }
15888 @@ -189,13 +187,13 @@
15889  int mod_alias_plugin_init(plugin *p) {
15890         p->version     = LIGHTTPD_VERSION_ID;
15891         p->name        = buffer_init_string("alias");
15892 -       
15893 +
15894         p->init           = mod_alias_init;
15895         p->handle_physical= mod_alias_physical_handler;
15896         p->set_defaults   = mod_alias_set_defaults;
15897         p->cleanup        = mod_alias_free;
15898 -       
15899 +
15900         p->data        = NULL;
15901 -       
15902 +
15903         return 0;
15904  }
15905 --- ../lighttpd-1.4.11/src/mod_auth.c   2006-02-15 20:01:31.000000000 +0200
15906 +++ lighttpd-1.4.12/src/mod_auth.c      2006-07-18 13:03:40.000000000 +0300
15907 @@ -5,168 +5,167 @@
15908  #include <string.h>
15909  #include <errno.h>
15910  #include <fcntl.h>
15911 -#include <unistd.h>
15912  
15913  #include "plugin.h"
15914  #include "http_auth.h"
15915  #include "log.h"
15916  #include "response.h"
15917  
15918 +#include "sys-strings.h"
15919 +#include "sys-files.h"
15920 +
15921  handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s);
15922  
15923  
15924  /**
15925   * the basic and digest auth framework
15926 - * 
15927 + *
15928   * - config handling
15929   * - protocol handling
15930 - * 
15931 - * http_auth.c 
15932 - * http_auth_digest.c 
15933 - * 
15934 + *
15935 + * http_auth.c
15936 + * http_auth_digest.c
15937 + *
15938   * do the real work
15939   */
15940  
15941  INIT_FUNC(mod_auth_init) {
15942         mod_auth_plugin_data *p;
15943 -       
15944 +
15945         p = calloc(1, sizeof(*p));
15946 -       
15947 +
15948         p->tmp_buf = buffer_init();
15949 -       
15950 +
15951         p->auth_user = buffer_init();
15952  #ifdef USE_LDAP
15953         p->ldap_filter = buffer_init();
15954  #endif
15955 -       
15956 +
15957         return p;
15958  }
15959  
15960  FREE_FUNC(mod_auth_free) {
15961         mod_auth_plugin_data *p = p_d;
15962 -       
15963 +
15964         UNUSED(srv);
15965  
15966         if (!p) return HANDLER_GO_ON;
15967 -       
15968 +
15969         buffer_free(p->tmp_buf);
15970         buffer_free(p->auth_user);
15971  #ifdef USE_LDAP
15972         buffer_free(p->ldap_filter);
15973  #endif
15974 -       
15975 +
15976         if (p->config_storage) {
15977                 size_t i;
15978                 for (i = 0; i < srv->config_context->used; i++) {
15979                         mod_auth_plugin_config *s = p->config_storage[i];
15980 -                       
15981 +
15982                         if (!s) continue;
15983 -                       
15984 +
15985                         array_free(s->auth_require);
15986                         buffer_free(s->auth_plain_groupfile);
15987                         buffer_free(s->auth_plain_userfile);
15988                         buffer_free(s->auth_htdigest_userfile);
15989                         buffer_free(s->auth_htpasswd_userfile);
15990                         buffer_free(s->auth_backend_conf);
15991 -                       
15992 +
15993                         buffer_free(s->auth_ldap_hostname);
15994                         buffer_free(s->auth_ldap_basedn);
15995                         buffer_free(s->auth_ldap_binddn);
15996                         buffer_free(s->auth_ldap_bindpw);
15997                         buffer_free(s->auth_ldap_filter);
15998                         buffer_free(s->auth_ldap_cafile);
15999 -                       
16000 +
16001  #ifdef USE_LDAP
16002                         buffer_free(s->ldap_filter_pre);
16003                         buffer_free(s->ldap_filter_post);
16004 -                       
16005 +
16006                         if (s->ldap) ldap_unbind_s(s->ldap);
16007  #endif
16008 -                       
16009 +
16010                         free(s);
16011                 }
16012                 free(p->config_storage);
16013         }
16014 -       
16015 +
16016         free(p);
16017 -       
16018 +
16019         return HANDLER_GO_ON;
16020  }
16021  
16022 -#define PATCH(x) \
16023 -       p->conf.x = s->x;
16024  static int mod_auth_patch_connection(server *srv, connection *con, mod_auth_plugin_data *p) {
16025         size_t i, j;
16026         mod_auth_plugin_config *s = p->config_storage[0];
16027  
16028 -       PATCH(auth_backend);
16029 -       PATCH(auth_plain_groupfile);
16030 -       PATCH(auth_plain_userfile);
16031 -       PATCH(auth_htdigest_userfile);
16032 -       PATCH(auth_htpasswd_userfile);
16033 -       PATCH(auth_require);
16034 -       PATCH(auth_debug);
16035 -       PATCH(auth_ldap_hostname);
16036 -       PATCH(auth_ldap_basedn);
16037 -       PATCH(auth_ldap_binddn);
16038 -       PATCH(auth_ldap_bindpw);
16039 -       PATCH(auth_ldap_filter);
16040 -       PATCH(auth_ldap_cafile);
16041 -       PATCH(auth_ldap_starttls);
16042 +       PATCH_OPTION(auth_backend);
16043 +       PATCH_OPTION(auth_plain_groupfile);
16044 +       PATCH_OPTION(auth_plain_userfile);
16045 +       PATCH_OPTION(auth_htdigest_userfile);
16046 +       PATCH_OPTION(auth_htpasswd_userfile);
16047 +       PATCH_OPTION(auth_require);
16048 +       PATCH_OPTION(auth_debug);
16049 +       PATCH_OPTION(auth_ldap_hostname);
16050 +       PATCH_OPTION(auth_ldap_basedn);
16051 +       PATCH_OPTION(auth_ldap_binddn);
16052 +       PATCH_OPTION(auth_ldap_bindpw);
16053 +       PATCH_OPTION(auth_ldap_filter);
16054 +       PATCH_OPTION(auth_ldap_cafile);
16055 +       PATCH_OPTION(auth_ldap_starttls);
16056  #ifdef USE_LDAP
16057 -       PATCH(ldap);
16058 -       PATCH(ldap_filter_pre);
16059 -       PATCH(ldap_filter_post);
16060 +       PATCH_OPTION(ldap);
16061 +       PATCH_OPTION(ldap_filter_pre);
16062 +       PATCH_OPTION(ldap_filter_post);
16063  #endif
16064 -       
16065 +
16066         /* skip the first, the global context */
16067         for (i = 1; i < srv->config_context->used; i++) {
16068                 data_config *dc = (data_config *)srv->config_context->data[i];
16069                 s = p->config_storage[i];
16070 -               
16071 +
16072                 /* condition didn't match */
16073                 if (!config_check_cond(srv, con, dc)) continue;
16074 -               
16075 +
16076                 /* merge config */
16077                 for (j = 0; j < dc->value->used; j++) {
16078                         data_unset *du = dc->value->data[j];
16079 -                       
16080 +
16081                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend"))) {
16082 -                               PATCH(auth_backend);
16083 +                               PATCH_OPTION(auth_backend);
16084                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.groupfile"))) {
16085 -                               PATCH(auth_plain_groupfile);
16086 +                               PATCH_OPTION(auth_plain_groupfile);
16087                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.userfile"))) {
16088 -                               PATCH(auth_plain_userfile);
16089 +                               PATCH_OPTION(auth_plain_userfile);
16090                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htdigest.userfile"))) {
16091 -                               PATCH(auth_htdigest_userfile);
16092 +                               PATCH_OPTION(auth_htdigest_userfile);
16093                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htpasswd.userfile"))) {
16094 -                               PATCH(auth_htpasswd_userfile);
16095 +                               PATCH_OPTION(auth_htpasswd_userfile);
16096                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.require"))) {
16097 -                               PATCH(auth_require);
16098 +                               PATCH_OPTION(auth_require);
16099                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.debug"))) {
16100 -                               PATCH(auth_debug);
16101 +                               PATCH_OPTION(auth_debug);
16102                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.hostname"))) {
16103 -                               PATCH(auth_ldap_hostname);
16104 +                               PATCH_OPTION(auth_ldap_hostname);
16105  #ifdef USE_LDAP
16106 -                               PATCH(ldap);
16107 -                               PATCH(ldap_filter_pre);
16108 -                               PATCH(ldap_filter_post);
16109 +                               PATCH_OPTION(ldap);
16110 +                               PATCH_OPTION(ldap_filter_pre);
16111 +                               PATCH_OPTION(ldap_filter_post);
16112  #endif
16113                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.base-dn"))) {
16114 -                               PATCH(auth_ldap_basedn);
16115 +                               PATCH_OPTION(auth_ldap_basedn);
16116                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.filter"))) {
16117 -                               PATCH(auth_ldap_filter);
16118 +                               PATCH_OPTION(auth_ldap_filter);
16119                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.ca-file"))) {
16120 -                               PATCH(auth_ldap_cafile);
16121 +                               PATCH_OPTION(auth_ldap_cafile);
16122                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.starttls"))) {
16123 -                               PATCH(auth_ldap_starttls);
16124 +                               PATCH_OPTION(auth_ldap_starttls);
16125                         }
16126                 }
16127         }
16128 -       
16129 +
16130         return 0;
16131  }
16132 -#undef PATCH
16133  
16134  static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
16135         size_t k;
16136 @@ -175,22 +174,22 @@
16137         data_string *ds;
16138         mod_auth_plugin_data *p = p_d;
16139         array *req;
16140 -       
16141 +
16142         /* select the right config */
16143         mod_auth_patch_connection(srv, con, p);
16144 -       
16145 +
16146         if (p->conf.auth_require == NULL) return HANDLER_GO_ON;
16147 -       
16148 +
16149         /*
16150          * AUTH
16151 -        *  
16152 +        *
16153          */
16154 -       
16155 +
16156         /* do we have to ask for auth ? */
16157 -       
16158 +
16159         auth_required = 0;
16160         auth_satisfied = 0;
16161 -       
16162 +
16163         /* search auth-directives for path */
16164         for (k = 0; k < p->conf.auth_require->used; k++) {
16165                 buffer *req = p->conf.auth_require->data[k]->key;
16166 @@ -212,76 +211,76 @@
16167                         }
16168                 }
16169         }
16170 -       
16171 +
16172         /* nothing to do for us */
16173         if (auth_required == 0) return HANDLER_GO_ON;
16174 -       
16175 +
16176         req = ((data_array *)(p->conf.auth_require->data[k]))->value;
16177 -       
16178 +
16179         /* try to get Authorization-header */
16180 -               
16181 +
16182         if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Authorization"))) {
16183                 http_authorization = ds->value->ptr;
16184         }
16185 -       
16186 +
16187         if (ds && ds->value && ds->value->used) {
16188                 char *auth_realm;
16189                 data_string *method;
16190 -               
16191 +
16192                 method = (data_string *)array_get_element(req, "method");
16193 -               
16194 +
16195                 /* parse auth-header */
16196                 if (NULL != (auth_realm = strchr(http_authorization, ' '))) {
16197                         int auth_type_len = auth_realm - http_authorization;
16198 -                       
16199 +
16200                         if ((auth_type_len == 5) &&
16201                             (0 == strncmp(http_authorization, "Basic", auth_type_len))) {
16202 -                               
16203 -                               if (0 == strcmp(method->value->ptr, "basic")) {
16204 +
16205 +                               if (buffer_is_equal_string(method->value, CONST_STR_LEN("basic"))) {
16206                                         auth_satisfied = http_auth_basic_check(srv, con, p, req, con->uri.path, auth_realm+1);
16207                                 }
16208                         } else if ((auth_type_len == 6) &&
16209                                    (0 == strncmp(http_authorization, "Digest", auth_type_len))) {
16210 -                               if (0 == strcmp(method->value->ptr, "digest")) {
16211 +                               if (buffer_is_equal_string(method->value, CONST_STR_LEN("digest"))) {
16212                                         if (-1 == (auth_satisfied = http_auth_digest_check(srv, con, p, req, con->uri.path, auth_realm+1))) {
16213                                                 con->http_status = 400;
16214 -                                               
16215 +
16216                                                 /* a field was missing */
16217 -                                               
16218 +
16219                                                 return HANDLER_FINISHED;
16220                                         }
16221                                 }
16222                         } else {
16223 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
16224 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
16225                                                 "unknown authentification type:",
16226                                                 http_authorization);
16227                         }
16228                 }
16229         }
16230 -       
16231 +
16232         if (!auth_satisfied) {
16233                 data_string *method, *realm;
16234                 method = (data_string *)array_get_element(req, "method");
16235                 realm = (data_string *)array_get_element(req, "realm");
16236 -               
16237 +
16238                 con->http_status = 401;
16239 -                       
16240 -               if (0 == strcmp(method->value->ptr, "basic")) {
16241 +
16242 +               if (buffer_is_equal_string(method->value, CONST_STR_LEN("basic"))) {
16243                         buffer_copy_string(p->tmp_buf, "Basic realm=\"");
16244                         buffer_append_string_buffer(p->tmp_buf, realm->value);
16245                         buffer_append_string(p->tmp_buf, "\"");
16246 -                       
16247 +
16248                         response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
16249 -               } else if (0 == strcmp(method->value->ptr, "digest")) {
16250 +               } else if (buffer_is_equal_string(method->value, CONST_STR_LEN("digest"))) {
16251                         char hh[33];
16252                         http_auth_digest_generate_nonce(srv, p, srv->tmp_buf, hh);
16253 -                       
16254 +
16255                         buffer_copy_string(p->tmp_buf, "Digest realm=\"");
16256                         buffer_append_string_buffer(p->tmp_buf, realm->value);
16257                         buffer_append_string(p->tmp_buf, "\", nonce=\"");
16258                         buffer_append_string(p->tmp_buf, hh);
16259                         buffer_append_string(p->tmp_buf, "\", qop=\"auth\"");
16260 -                       
16261 +
16262                         response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
16263                 } else {
16264                         /* evil */
16265 @@ -289,18 +288,18 @@
16266                 return HANDLER_FINISHED;
16267         } else {
16268                 /* the REMOTE_USER header */
16269 -               
16270 +
16271                 buffer_copy_string_buffer(con->authed_user, p->auth_user);
16272         }
16273 -       
16274 +
16275         return HANDLER_GO_ON;
16276  }
16277  
16278  SETDEFAULTS_FUNC(mod_auth_set_defaults) {
16279         mod_auth_plugin_data *p = p_d;
16280         size_t i;
16281 -       
16282 -       config_values_t cv[] = { 
16283 +
16284 +       config_values_t cv[] = {
16285                 { "auth.backend",                   NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
16286                 { "auth.backend.plain.groupfile",   NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
16287                 { "auth.backend.plain.userfile",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
16288 @@ -317,7 +316,7 @@
16289                 { "auth.debug",                     NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },  /* 13 */
16290                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
16291         };
16292 -       
16293 +
16294         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
16295  
16296         for (i = 0; i < srv->config_context->used; i++) {
16297 @@ -325,14 +324,14 @@
16298                 size_t n;
16299                 data_array *da;
16300                 array *ca;
16301 -               
16302 +
16303                 s = calloc(1, sizeof(mod_auth_plugin_config));
16304                 s->auth_plain_groupfile = buffer_init();
16305                 s->auth_plain_userfile = buffer_init();
16306                 s->auth_htdigest_userfile = buffer_init();
16307                 s->auth_htpasswd_userfile = buffer_init();
16308                 s->auth_backend_conf = buffer_init();
16309 -               
16310 +
16311                 s->auth_ldap_hostname = buffer_init();
16312                 s->auth_ldap_basedn = buffer_init();
16313                 s->auth_ldap_binddn = buffer_init();
16314 @@ -341,15 +340,15 @@
16315                 s->auth_ldap_cafile = buffer_init();
16316                 s->auth_ldap_starttls = 0;
16317                 s->auth_debug = 0;
16318 -               
16319 +
16320                 s->auth_require = array_init();
16321 -               
16322 +
16323  #ifdef USE_LDAP
16324                 s->ldap_filter_pre = buffer_init();
16325                 s->ldap_filter_post = buffer_init();
16326                 s->ldap = NULL;
16327  #endif
16328 -       
16329 +
16330                 cv[0].destination = s->auth_backend_conf;
16331                 cv[1].destination = s->auth_plain_groupfile;
16332                 cv[2].destination = s->auth_plain_userfile;
16333 @@ -364,146 +363,148 @@
16334                 cv[11].destination = s->auth_htdigest_userfile;
16335                 cv[12].destination = s->auth_htpasswd_userfile;
16336                 cv[13].destination = &(s->auth_debug);
16337 -               
16338 +
16339                 p->config_storage[i] = s;
16340                 ca = ((data_config *)srv->config_context->data[i])->value;
16341 -               
16342 +
16343                 if (0 != config_insert_values_global(srv, ca, cv)) {
16344                         return HANDLER_ERROR;
16345                 }
16346 -               
16347 -               if (s->auth_backend_conf->used) {
16348 -                       if (0 == strcmp(s->auth_backend_conf->ptr, "htpasswd")) {
16349 +
16350 +               if (!buffer_is_empty(s->auth_backend_conf)) {
16351 +                       if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("htpasswd"))) {
16352                                 s->auth_backend = AUTH_BACKEND_HTPASSWD;
16353 -                       } else if (0 == strcmp(s->auth_backend_conf->ptr, "htdigest")) {
16354 +                       } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("htdigest"))) {
16355                                 s->auth_backend = AUTH_BACKEND_HTDIGEST;
16356 -                       } else if (0 == strcmp(s->auth_backend_conf->ptr, "plain")) {
16357 +                       } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("plain"))) {
16358                                 s->auth_backend = AUTH_BACKEND_PLAIN;
16359 -                       } else if (0 == strcmp(s->auth_backend_conf->ptr, "ldap")) {
16360 +                       } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("ldap"))) {
16361                                 s->auth_backend = AUTH_BACKEND_LDAP;
16362                         } else {
16363                                 log_error_write(srv, __FILE__, __LINE__, "sb", "auth.backend not supported:", s->auth_backend_conf);
16364 -                               
16365 +
16366                                 return HANDLER_ERROR;
16367                         }
16368                 }
16369  
16370                 /* no auth.require for this section */
16371                 if (NULL == (da = (data_array *)array_get_element(ca, "auth.require"))) continue;
16372 -               
16373 +
16374                 if (da->type != TYPE_ARRAY) continue;
16375 -               
16376 +
16377                 for (n = 0; n < da->value->used; n++) {
16378                         size_t m;
16379                         data_array *da_file = (data_array *)da->value->data[n];
16380 -                       const char *method, *realm, *require;
16381 -                       
16382 +                       buffer *method, *realm, *require;
16383 +
16384                         if (da->value->data[n]->type != TYPE_ARRAY) {
16385 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
16386 -                                               "auth.require should contain an array as in:", 
16387 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
16388 +                                               "auth.require should contain an array as in:",
16389                                                 "auth.require = ( \"...\" => ( ..., ...) )");
16390  
16391                                 return HANDLER_ERROR;
16392                         }
16393 -                                       
16394 +
16395                         method = realm = require = NULL;
16396 -                                       
16397 +
16398                         for (m = 0; m < da_file->value->used; m++) {
16399 -                               if (da_file->value->data[m]->type == TYPE_STRING) {
16400 -                                       if (0 == strcmp(da_file->value->data[m]->key->ptr, "method")) {
16401 -                                               method = ((data_string *)(da_file->value->data[m]))->value->ptr;
16402 -                                       } else if (0 == strcmp(da_file->value->data[m]->key->ptr, "realm")) {
16403 -                                               realm = ((data_string *)(da_file->value->data[m]))->value->ptr;
16404 -                                       } else if (0 == strcmp(da_file->value->data[m]->key->ptr, "require")) {
16405 -                                               require = ((data_string *)(da_file->value->data[m]))->value->ptr;
16406 -                                       } else {
16407 -                                               log_error_write(srv, __FILE__, __LINE__, "ssbs", 
16408 -                                                       "the field is unknown in:", 
16409 +                               data_string *ds_auth_req = (data_string *)da_file->value->data[m];
16410 +
16411 +                               if (ds_auth_req->type != TYPE_STRING) {
16412 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbs",
16413 +                                               "a string was expected for:",
16414 +                                               "auth.require = ( \"...\" => ( ..., -> \"",
16415 +                                               ds_auth_req->key,
16416 +                                               "\" <- => \"...\" ) )");
16417 +
16418 +                                       return HANDLER_ERROR;
16419 +                               }
16420 +
16421 +                               if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("method"))) {
16422 +                                       method = ds_auth_req->value;
16423 +                               } else if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("realm"))) {
16424 +                                       realm = ds_auth_req->value;
16425 +                               } else if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("require"))) {
16426 +                                       require = ds_auth_req->value;
16427 +                               } else {
16428 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbs",
16429 +                                                       "the field is unknown in:",
16430                                                         "auth.require = ( \"...\" => ( ..., -> \"",
16431                                                         da_file->value->data[m]->key,
16432                                                         "\" <- => \"...\" ) )");
16433  
16434 -                                               return HANDLER_ERROR;
16435 -                                       }
16436 -                               } else {
16437 -                                       log_error_write(srv, __FILE__, __LINE__, "ssbs", 
16438 -                                               "a string was expected for:", 
16439 -                                               "auth.require = ( \"...\" => ( ..., -> \"",
16440 -                                               da_file->value->data[m]->key,
16441 -                                               "\" <- => \"...\" ) )");
16442 -                                       
16443                                         return HANDLER_ERROR;
16444 +
16445                                 }
16446                         }
16447 -                                       
16448 +
16449                         if (method == NULL) {
16450 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
16451 -                                               "the require field is missing in:", 
16452 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
16453 +                                               "the require field is missing in:",
16454                                                 "auth.require = ( \"...\" => ( ..., \"method\" => \"...\" ) )");
16455                                 return HANDLER_ERROR;
16456 -                       } else {
16457 -                               if (0 != strcmp(method, "basic") &&
16458 -                                   0 != strcmp(method, "digest")) {
16459 -                                       log_error_write(srv, __FILE__, __LINE__, "ss",
16460 -                                                       "method has to be either \"basic\" or \"digest\" in",
16461 -                                                       "auth.require = ( \"...\" => ( ..., \"method\" => \"...\") )");
16462 -                                       return HANDLER_ERROR;
16463 -                               }
16464 +                       } 
16465 +                       if (!buffer_is_equal_string(method, CONST_STR_LEN("basic")) &&
16466 +                           !buffer_is_equal_string(method, CONST_STR_LEN("digest"))) {
16467 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
16468 +                                               "method has to be either \"basic\" or \"digest\" in",
16469 +                                               "auth.require = ( \"...\" => ( ..., \"method\" => \"...\") )");
16470 +                               return HANDLER_ERROR;
16471                         }
16472 -                       
16473 +
16474                         if (realm == NULL) {
16475 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
16476 -                                               "the require field is missing in:", 
16477 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
16478 +                                               "the require field is missing in:",
16479                                                 "auth.require = ( \"...\" => ( ..., \"realm\" => \"...\" ) )");
16480                                 return HANDLER_ERROR;
16481                         }
16482 -                       
16483 +
16484                         if (require == NULL) {
16485 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
16486 -                                               "the require field is missing in:", 
16487 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
16488 +                                               "the require field is missing in:",
16489                                                 "auth.require = ( \"...\" => ( ..., \"require\" => \"...\" ) )");
16490                                 return HANDLER_ERROR;
16491                         }
16492 -                       
16493 +
16494                         if (method && realm && require) {
16495                                 data_string *ds;
16496                                 data_array *a;
16497 -                               
16498 +
16499                                 a = data_array_init();
16500                                 buffer_copy_string_buffer(a->key, da_file->key);
16501 -                               
16502 +
16503                                 ds = data_string_init();
16504 -                               
16505 +
16506                                 buffer_copy_string(ds->key, "method");
16507 -                               buffer_copy_string(ds->value, method);
16508 -                               
16509 +                               buffer_copy_string_buffer(ds->value, method);
16510 +
16511                                 array_insert_unique(a->value, (data_unset *)ds);
16512 -                               
16513 +
16514                                 ds = data_string_init();
16515 -                               
16516 +
16517                                 buffer_copy_string(ds->key, "realm");
16518 -                               buffer_copy_string(ds->value, realm);
16519 -                               
16520 +                               buffer_copy_string_buffer(ds->value, realm);
16521 +
16522                                 array_insert_unique(a->value, (data_unset *)ds);
16523 -                               
16524 +
16525                                 ds = data_string_init();
16526 -                               
16527 +
16528                                 buffer_copy_string(ds->key, "require");
16529 -                               buffer_copy_string(ds->value, require);
16530 -                               
16531 +                               buffer_copy_string_buffer(ds->value, require);
16532 +
16533                                 array_insert_unique(a->value, (data_unset *)ds);
16534 -                               
16535 +
16536                                 array_insert_unique(s->auth_require, (data_unset *)a);
16537                         }
16538                 }
16539 -       
16540 +
16541                 switch(s->auth_backend) {
16542                 case AUTH_BACKEND_PLAIN:
16543                         if (s->auth_plain_userfile->used) {
16544                                 int fd;
16545                                 /* try to read */
16546                                 if (-1 == (fd = open(s->auth_plain_userfile->ptr, O_RDONLY))) {
16547 -                                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
16548 +                                       log_error_write(srv, __FILE__, __LINE__, "sbss",
16549                                                         "opening auth.backend.plain.userfile:", s->auth_plain_userfile,
16550                                                         "failed:", strerror(errno));
16551                                         return HANDLER_ERROR;
16552 @@ -516,7 +517,7 @@
16553                                 int fd;
16554                                 /* try to read */
16555                                 if (-1 == (fd = open(s->auth_htpasswd_userfile->ptr, O_RDONLY))) {
16556 -                                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
16557 +                                       log_error_write(srv, __FILE__, __LINE__, "sbss",
16558                                                         "opening auth.backend.htpasswd.userfile:", s->auth_htpasswd_userfile,
16559                                                         "failed:", strerror(errno));
16560                                         return HANDLER_ERROR;
16561 @@ -529,7 +530,7 @@
16562                                 int fd;
16563                                 /* try to read */
16564                                 if (-1 == (fd = open(s->auth_htdigest_userfile->ptr, O_RDONLY))) {
16565 -                                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
16566 +                                       log_error_write(srv, __FILE__, __LINE__, "sbss",
16567                                                         "opening auth.backend.htdigest.userfile:", s->auth_htdigest_userfile,
16568                                                         "failed:", strerror(errno));
16569                                         return HANDLER_ERROR;
16570 @@ -554,75 +555,75 @@
16571  handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s) {
16572  #ifdef USE_LDAP
16573                         int ret;
16574 -#if 0                  
16575 +#if 0
16576                         if (s->auth_ldap_basedn->used == 0) {
16577                                 log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.base-dn has to be set");
16578 -                               
16579 +
16580                                 return HANDLER_ERROR;
16581                         }
16582  #endif
16583 -                       
16584 +
16585                         if (s->auth_ldap_filter->used) {
16586                                 char *dollar;
16587 -                               
16588 +
16589                                 /* parse filter */
16590 -                       
16591 +
16592                                 if (NULL == (dollar = strchr(s->auth_ldap_filter->ptr, '$'))) {
16593                                         log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.filter is missing a replace-operator '$'");
16594 -                                       
16595 +
16596                                         return HANDLER_ERROR;
16597                                 }
16598 -                               
16599 +
16600                                 buffer_copy_string_len(s->ldap_filter_pre, s->auth_ldap_filter->ptr, dollar - s->auth_ldap_filter->ptr);
16601                                 buffer_copy_string(s->ldap_filter_post, dollar+1);
16602                         }
16603 -                       
16604 +
16605                         if (s->auth_ldap_hostname->used) {
16606                                 if (NULL == (s->ldap = ldap_init(s->auth_ldap_hostname->ptr, LDAP_PORT))) {
16607                                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno));
16608 -                                       
16609 +
16610                                         return HANDLER_ERROR;
16611                                 }
16612 -                               
16613 +
16614                                 ret = LDAP_VERSION3;
16615                                 if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(s->ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) {
16616                                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
16617 -                               
16618 +
16619                                         return HANDLER_ERROR;
16620                                 }
16621  
16622                                 if (s->auth_ldap_starttls) {
16623 -                                       /* if no CA file is given, it is ok, as we will use encryption 
16624 +                                       /* if no CA file is given, it is ok, as we will use encryption
16625                                          * if the server requires a CAfile it will tell us */
16626                                         if (!buffer_is_empty(s->auth_ldap_cafile)) {
16627 -                                               if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, 
16628 +                                               if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
16629                                                                                 s->auth_ldap_cafile->ptr))) {
16630 -                                                       log_error_write(srv, __FILE__, __LINE__, "ss", 
16631 +                                                       log_error_write(srv, __FILE__, __LINE__, "ss",
16632                                                                         "Loading CA certificate failed:", ldap_err2string(ret));
16633 -                                               
16634 +
16635                                                         return HANDLER_ERROR;
16636                                                 }
16637                                         }
16638 -       
16639 +
16640                                         if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(s->ldap, NULL,  NULL))) {
16641                                                 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
16642 -                                               
16643 +
16644                                                 return HANDLER_ERROR;
16645                                         }
16646                                 }
16647 -                               
16648 -                               
16649 +
16650 +
16651                                 /* 1. */
16652                                 if (s->auth_ldap_binddn->used) {
16653                                         if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, s->auth_ldap_binddn->ptr, s->auth_ldap_bindpw->ptr))) {
16654                                                 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
16655 -                                               
16656 +
16657                                                 return HANDLER_ERROR;
16658                                         }
16659                                 } else {
16660                                         if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, NULL, NULL))) {
16661                                                 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
16662 -                                               
16663 +
16664                                                 return HANDLER_ERROR;
16665                                         }
16666                                 }
16667 @@ -641,8 +642,8 @@
16668         p->set_defaults = mod_auth_set_defaults;
16669         p->handle_uri_clean = mod_auth_uri_handler;
16670         p->cleanup     = mod_auth_free;
16671 -       
16672 +
16673         p->data        = NULL;
16674 -       
16675 +
16676         return 0;
16677  }
16678 --- ../lighttpd-1.4.11/src/mod_cgi.c    2006-02-22 15:15:10.000000000 +0200
16679 +++ lighttpd-1.4.12/src/mod_cgi.c       2006-07-18 17:34:32.000000000 +0300
16680 @@ -1,21 +1,8 @@
16681  #include <sys/types.h>
16682 -#ifdef __WIN32
16683 -#include <winsock2.h>
16684 -#else
16685 -#include <sys/socket.h>
16686 -#include <sys/wait.h>
16687 -#include <sys/mman.h>
16688 -
16689 -#include <netinet/in.h>
16690 -
16691 -#include <arpa/inet.h>
16692 -#endif
16693  
16694 -#include <unistd.h>
16695  #include <errno.h>
16696  #include <stdlib.h>
16697  #include <string.h>
16698 -#include <fdevent.h>
16699  #include <signal.h>
16700  #include <ctype.h>
16701  #include <assert.h>
16702 @@ -29,8 +16,16 @@
16703  #include "connections.h"
16704  #include "joblist.h"
16705  #include "http_chunk.h"
16706 +#include "fdevent.h"
16707  
16708  #include "plugin.h"
16709 +#include "http_resp.h"
16710 +
16711 +#include "sys-files.h"
16712 +#include "sys-mmap.h"
16713 +#include "sys-socket.h"
16714 +#include "sys-strings.h"
16715 +#include "sys-process.h"
16716  
16717  #ifdef HAVE_SYS_FILIO_H
16718  # include <sys/filio.h>
16719 @@ -40,11 +35,12 @@
16720  
16721  typedef struct {
16722         char **ptr;
16723 -       
16724 +
16725         size_t size;
16726         size_t used;
16727  } char_array;
16728  
16729 +#define pid_t int
16730  typedef struct {
16731         pid_t *ptr;
16732         size_t used;
16733 @@ -58,57 +54,68 @@
16734  typedef struct {
16735         PLUGIN_DATA;
16736         buffer_pid_t cgi_pid;
16737 -       
16738 +
16739         buffer *tmp_buf;
16740 -       buffer *parse_response;
16741 -       
16742 +
16743 +       http_resp *resp;
16744 +
16745         plugin_config **config_storage;
16746 -       
16747 -       plugin_config conf; 
16748 +
16749 +       plugin_config conf;
16750  } plugin_data;
16751  
16752 +typedef enum {
16753 +       CGI_STATE_UNSET,
16754 +       CGI_STATE_CONNECTING,
16755 +       CGI_STATE_READ_RESPONSE_HEADER,
16756 +       CGI_STATE_READ_RESPONSE_CONTENT
16757 +} cgi_state_t;
16758 +
16759  typedef struct {
16760         pid_t pid;
16761 -       int fd;
16762 -       int fde_ndx; /* index into the fd-event buffer */
16763 -       
16764 -       connection *remote_conn;  /* dumb pointer */
16765 -       plugin_data *plugin_data; /* dumb pointer */
16766 -       
16767 -       buffer *response;
16768 -       buffer *response_header;
16769 -} handler_ctx;
16770  
16771 -static handler_ctx * cgi_handler_ctx_init() {
16772 -       handler_ctx *hctx = calloc(1, sizeof(*hctx));
16773 +       iosocket *sock;
16774  
16775 -       assert(hctx);
16776 -       
16777 -       hctx->response = buffer_init();
16778 -       hctx->response_header = buffer_init();
16779 -       
16780 -       return hctx;
16781 -}
16782 +       chunkqueue *rb;
16783 +       chunkqueue *wb;
16784  
16785 -static void cgi_handler_ctx_free(handler_ctx *hctx) {
16786 -       buffer_free(hctx->response);
16787 -       buffer_free(hctx->response_header);
16788 -       
16789 -       free(hctx);
16790 +       cgi_state_t state;
16791 +
16792 +       connection *remote_con;  /* dumb pointer */
16793 +} cgi_session;
16794 +
16795 +static cgi_session * cgi_session_init() {
16796 +       cgi_session *sess = calloc(1, sizeof(*sess));
16797 +       assert(sess);
16798 +
16799 +       sess->sock = iosocket_init();
16800 +       sess->wb = chunkqueue_init();
16801 +       sess->rb = chunkqueue_init();
16802 +
16803 +       return sess;
16804  }
16805  
16806 -enum {FDEVENT_HANDLED_UNSET, FDEVENT_HANDLED_FINISHED, FDEVENT_HANDLED_NOT_FINISHED, FDEVENT_HANDLED_ERROR};
16807 +static void cgi_session_free(cgi_session *sess) {
16808 +       if (!sess) return;
16809 +
16810 +       iosocket_free(sess->sock);
16811 +
16812 +       chunkqueue_free(sess->wb);
16813 +       chunkqueue_free(sess->rb);
16814 +
16815 +       free(sess);
16816 +}
16817  
16818  INIT_FUNC(mod_cgi_init) {
16819         plugin_data *p;
16820 -       
16821 +
16822         p = calloc(1, sizeof(*p));
16823  
16824         assert(p);
16825 -       
16826 +
16827         p->tmp_buf = buffer_init();
16828 -       p->parse_response = buffer_init();
16829 -       
16830 +       p->resp = http_response_init();
16831 +
16832         return p;
16833  }
16834  
16835 @@ -116,62 +123,62 @@
16836  FREE_FUNC(mod_cgi_free) {
16837         plugin_data *p = p_d;
16838         buffer_pid_t *r = &(p->cgi_pid);
16839 -       
16840 +
16841         UNUSED(srv);
16842 -       
16843 +
16844         if (p->config_storage) {
16845                 size_t i;
16846                 for (i = 0; i < srv->config_context->used; i++) {
16847                         plugin_config *s = p->config_storage[i];
16848 -                       
16849 +
16850                         array_free(s->cgi);
16851 -                       
16852 +
16853                         free(s);
16854                 }
16855                 free(p->config_storage);
16856         }
16857 -       
16858 +
16859  
16860         if (r->ptr) free(r->ptr);
16861 -       
16862 +
16863         buffer_free(p->tmp_buf);
16864 -       buffer_free(p->parse_response);
16865 -       
16866 +       http_response_free(p->resp);
16867 +
16868         free(p);
16869 -       
16870 +
16871         return HANDLER_GO_ON;
16872  }
16873  
16874  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
16875         plugin_data *p = p_d;
16876         size_t i = 0;
16877 -       
16878 -       config_values_t cv[] = { 
16879 +
16880 +       config_values_t cv[] = {
16881                 { "cgi.assign",                  NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
16882                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET}
16883         };
16884  
16885         if (!p) return HANDLER_ERROR;
16886 -       
16887 +
16888         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
16889 -       
16890 +
16891         for (i = 0; i < srv->config_context->used; i++) {
16892                 plugin_config *s;
16893 -               
16894 +
16895                 s = calloc(1, sizeof(plugin_config));
16896                 assert(s);
16897 -               
16898 +
16899                 s->cgi    = array_init();
16900 -               
16901 +
16902                 cv[0].destination = s->cgi;
16903 -               
16904 +
16905                 p->config_storage[i] = s;
16906 -       
16907 +
16908                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
16909                         return HANDLER_ERROR;
16910                 }
16911         }
16912 -       
16913 +
16914         return HANDLER_GO_ON;
16915  }
16916  
16917 @@ -180,13 +187,13 @@
16918         int m = -1;
16919         size_t i;
16920         buffer_pid_t *r = &(p->cgi_pid);
16921 -       
16922 +
16923         UNUSED(srv);
16924  
16925         for (i = 0; i < r->used; i++) {
16926                 if (r->ptr[i] > m) m = r->ptr[i];
16927         }
16928 -       
16929 +
16930         if (r->size == 0) {
16931                 r->size = 16;
16932                 r->ptr = malloc(sizeof(*r->ptr) * r->size);
16933 @@ -194,321 +201,179 @@
16934                 r->size += 16;
16935                 r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
16936         }
16937 -       
16938 +
16939         r->ptr[r->used++] = pid;
16940 -       
16941 +
16942         return m;
16943  }
16944  
16945  static int cgi_pid_del(server *srv, plugin_data *p, pid_t pid) {
16946         size_t i;
16947         buffer_pid_t *r = &(p->cgi_pid);
16948 -       
16949 +
16950         UNUSED(srv);
16951  
16952         for (i = 0; i < r->used; i++) {
16953                 if (r->ptr[i] == pid) break;
16954         }
16955 -       
16956 +
16957         if (i != r->used) {
16958                 /* found */
16959 -               
16960 +
16961                 if (i != r->used - 1) {
16962                         r->ptr[i] = r->ptr[r->used - 1];
16963                 }
16964                 r->used--;
16965         }
16966 -       
16967 +
16968         return 0;
16969  }
16970  
16971 -static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in, int eol) {
16972 -       char *ns;
16973 -       const char *s;
16974 -       int line = 0;
16975 -       
16976 -       UNUSED(srv);
16977 -       
16978 -       buffer_copy_string_buffer(p->parse_response, in);
16979 -       
16980 -       for (s = p->parse_response->ptr; 
16981 -            NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n'))); 
16982 -            s = ns + (eol == EOL_RN ? 2 : 1), line++) {
16983 -               const char *key, *value;
16984 -               int key_len;
16985 -               data_string *ds;
16986 -               
16987 -               ns[0] = '\0';
16988 -               
16989 -               if (line == 0 && 
16990 -                   0 == strncmp(s, "HTTP/1.", 7)) {
16991 -                       /* non-parsed header ... we parse them anyway */
16992 -                       
16993 -                       if ((s[7] == '1' ||
16994 -                            s[7] == '0') &&
16995 -                           s[8] == ' ') {
16996 -                               int status;
16997 -                               /* after the space should be a status code for us */
16998 -                               
16999 -                               status = strtol(s+9, NULL, 10);
17000 -                               
17001 -                               if (con->http_status >= 100 &&
17002 -                                   con->http_status < 1000) {
17003 -                                       /* we expected 3 digits and didn't got them */
17004 -                                       con->parsed_response |= HTTP_STATUS;
17005 -                                       con->http_status = status;
17006 -                               }
17007 -                       }
17008 -               } else {
17009 -               
17010 -                       key = s;
17011 -                       if (NULL == (value = strchr(s, ':'))) {
17012 -                               /* we expect: "<key>: <value>\r\n" */
17013 -                               continue;
17014 -                       }
17015 -                       
17016 -                       key_len = value - key;
17017 -                       value += 1;
17018 -                       
17019 -                       /* skip LWS */
17020 -                       while (*value == ' ' || *value == '\t') value++;
17021 -                       
17022 -                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
17023 -                               ds = data_response_init();
17024 -                       }
17025 -                       buffer_copy_string_len(ds->key, key, key_len);
17026 -                       buffer_copy_string(ds->value, value);
17027 -                       
17028 -                       array_insert_unique(con->response.headers, (data_unset *)ds);
17029 -                       
17030 -                       switch(key_len) {
17031 -                       case 4:
17032 -                               if (0 == strncasecmp(key, "Date", key_len)) {
17033 -                                       con->parsed_response |= HTTP_DATE;
17034 -                               }
17035 -                               break;
17036 -                       case 6:
17037 -                               if (0 == strncasecmp(key, "Status", key_len)) {
17038 -                                       con->http_status = strtol(value, NULL, 10);
17039 -                                       con->parsed_response |= HTTP_STATUS;
17040 -                               }
17041 -                               break;
17042 -                       case 8:
17043 -                               if (0 == strncasecmp(key, "Location", key_len)) {
17044 -                                       con->parsed_response |= HTTP_LOCATION;
17045 -                               }
17046 -                               break;
17047 -                       case 10:
17048 -                               if (0 == strncasecmp(key, "Connection", key_len)) {
17049 -                                       con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
17050 -                                       con->parsed_response |= HTTP_CONNECTION;
17051 -                               }
17052 -                               break;
17053 -                       case 14:
17054 -                               if (0 == strncasecmp(key, "Content-Length", key_len)) {
17055 -                                       con->response.content_length = strtol(value, NULL, 10);
17056 -                                       con->parsed_response |= HTTP_CONTENT_LENGTH;
17057 -                               }
17058 -                               break;
17059 -                       default:
17060 -                               break;
17061 -                       }
17062 -               }
17063 -       }
17064 -       
17065 -       /* CGI/1.1 rev 03 - 7.2.1.2 */
17066 -       if ((con->parsed_response & HTTP_LOCATION) &&
17067 -           !(con->parsed_response & HTTP_STATUS)) {
17068 -               con->http_status = 302;
17069 +static int cgi_demux_response(server *srv, connection *con, plugin_data *p) {
17070 +       cgi_session *sess = con->plugin_ctx[p->id];
17071 +       chunk *c = NULL;
17072 +
17073 +       switch(srv->network_backend_read(srv, con, sess->sock, sess->rb)) {
17074 +       case NETWORK_STATUS_SUCCESS:
17075 +               /* we got content */
17076 +               break;
17077 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
17078 +               return 0;
17079 +       case NETWORK_STATUS_CONNECTION_CLOSE:
17080 +               /* this is a bit too early */
17081 +               ERROR("%s", "cgi-connection got closed before we read the response-header (CGI died ?)");
17082 +               return -1;
17083 +       default:
17084 +               /* oops */
17085 +               ERROR("%s", "oops, read-pipe-read failed and I don't know why");
17086 +               return -1;
17087         }
17088 -       
17089 -       return 0;
17090 -}
17091  
17092 +       /* looks like we got some content
17093 +       *
17094 +       * split off the header from the incoming stream
17095 +       */
17096  
17097 -static int cgi_demux_response(server *srv, handler_ctx *hctx) {
17098 -       plugin_data *p    = hctx->plugin_data;
17099 -       connection  *con  = hctx->remote_conn;
17100 -       
17101 -       while(1) {
17102 -               int n;
17103 -               
17104 -               buffer_prepare_copy(hctx->response, 1024);
17105 -               if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {
17106 -                       if (errno == EAGAIN || errno == EINTR) {
17107 -                               /* would block, wait for signal */
17108 -                               return FDEVENT_HANDLED_NOT_FINISHED;
17109 -                       }
17110 -                       /* error */
17111 -                       log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd);
17112 -                       return FDEVENT_HANDLED_ERROR;
17113 -               }
17114 -               
17115 -               if (n == 0) {
17116 -                       /* read finished */
17117 -                       
17118 -                       con->file_finished = 1;
17119 -                       
17120 -                       /* send final chunk */
17121 -                       http_chunk_append_mem(srv, con, NULL, 0);
17122 -                       joblist_append(srv, con);
17123 -                       
17124 -                       return FDEVENT_HANDLED_FINISHED;
17125 -               }
17126 -               
17127 -               hctx->response->ptr[n] = '\0';
17128 -               hctx->response->used = n+1;
17129 -               
17130 -               /* split header from body */
17131 -               
17132 -               if (con->file_started == 0) {
17133 -                       char *c;
17134 -                       int in_header = 0;
17135 -                       int header_end = 0;
17136 -                       int cp, eol = EOL_UNSET;
17137 -                       size_t used = 0;
17138 -                       
17139 -                       buffer_append_string_buffer(hctx->response_header, hctx->response);
17140 -                       
17141 -                       /* nph (non-parsed headers) */
17142 -                       if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;
17143 -                       
17144 -                       /* search for the \r\n\r\n or \n\n in the string */
17145 -                       for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) {
17146 -                               if (*c == ':') in_header = 1;
17147 -                               else if (*c == '\n') {
17148 -                                       if (in_header == 0) {
17149 -                                               /* got a response without a response header */
17150 -                                               
17151 -                                               c = NULL;
17152 -                                               header_end = 1;
17153 -                                               break;
17154 -                                       }
17155 -                                       
17156 -                                       if (eol == EOL_UNSET) eol = EOL_N;
17157 -                                       
17158 -                                       if (*(c+1) == '\n') {
17159 -                                               header_end = 1;
17160 -                                               break;
17161 -                                       }
17162 -                                       
17163 -                               } else if (used > 1 && *c == '\r' && *(c+1) == '\n') {
17164 -                                       if (in_header == 0) {
17165 -                                               /* got a response without a response header */
17166 -                                               
17167 -                                               c = NULL;
17168 -                                               header_end = 1;
17169 -                                               break;
17170 -                                       }
17171 -                                       
17172 -                                       if (eol == EOL_UNSET) eol = EOL_RN;
17173 -                                       
17174 -                                       if (used > 3 &&
17175 -                                           *(c+2) == '\r' && 
17176 -                                           *(c+3) == '\n') {
17177 -                                               header_end = 1;
17178 -                                               break;
17179 -                                       }
17180 -                                       
17181 -                                       /* skip the \n */
17182 -                                       c++;
17183 -                                       cp++;
17184 -                                       used--;
17185 +       if (con->file_started == 0) {
17186 +               size_t i;
17187 +               int have_content_length = 0;
17188 +
17189 +               http_response_reset(p->resp);
17190 +
17191 +               /* the response header is not fully received yet,
17192 +               *
17193 +               * extract the http-response header from the rb-cq
17194 +               */
17195 +               switch (http_response_parse_cq(sess->rb, p->resp)) {
17196 +               case PARSE_ERROR:
17197 +                       /* parsing failed */
17198 +
17199 +                       TRACE("%s", "response parser failed");
17200 +
17201 +                       con->http_status = 502; /* Bad Gateway */
17202 +                       return -1;
17203 +               case PARSE_NEED_MORE:
17204 +                       return 0;
17205 +               case PARSE_SUCCESS:
17206 +                       con->http_status = p->resp->status;
17207 +
17208 +                       chunkqueue_remove_finished_chunks(sess->rb);
17209 +
17210 +                       /* copy the http-headers */
17211 +                       for (i = 0; i < p->resp->headers->used; i++) {
17212 +                               const char *ign[] = { "Status", "Connection", NULL };
17213 +                               size_t j;
17214 +                               data_string *ds;
17215 +
17216 +                               data_string *header = (data_string *)p->resp->headers->data[i];
17217 +
17218 +                               /* some headers are ignored by default */
17219 +                               for (j = 0; ign[j]; j++) {
17220 +                                       if (0 == strcasecmp(ign[j], header->key->ptr)) break;
17221                                 }
17222 -                       }
17223 -                       
17224 -                       if (header_end) {
17225 -                               if (c == NULL) {
17226 -                                       /* no header, but a body */
17227 -                                       
17228 -                                       if (con->request.http_version == HTTP_VERSION_1_1) {
17229 -                                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
17230 -                                       }
17231 -                                       
17232 -                                       http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
17233 -                                       joblist_append(srv, con);
17234 -                               } else {
17235 -                                       size_t hlen = c - hctx->response_header->ptr + (eol == EOL_RN ? 4 : 2);
17236 -                                       size_t blen = hctx->response_header->used - hlen - 1;
17237 -                               
17238 -                                       /* a small hack: terminate after at the second \r */
17239 -                                       hctx->response_header->used = hlen + 1 - (eol == EOL_RN ? 2 : 1);
17240 -                                       hctx->response_header->ptr[hlen - (eol == EOL_RN ? 2 : 1)] = '\0';
17241 -                               
17242 -                                       /* parse the response header */
17243 -                                       cgi_response_parse(srv, con, p, hctx->response_header, eol);
17244 -                                       
17245 -                                       /* enable chunked-transfer-encoding */
17246 -                                       if (con->request.http_version == HTTP_VERSION_1_1 &&
17247 -                                           !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
17248 -                                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
17249 -                                       }
17250 -                                       
17251 -                                       if ((hctx->response->used != hlen) && blen > 0) {
17252 -                                               http_chunk_append_mem(srv, con, c + (eol == EOL_RN ? 4: 2), blen + 1);
17253 -                                               joblist_append(srv, con);
17254 -                                       }
17255 +                               if (ign[j]) continue;
17256 +
17257 +                               if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
17258 +                                       /* CGI/1.1 rev 03 - 7.2.1.2 */
17259 +                                       if (con->http_status == 0) con->http_status = 302;
17260 +                               } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
17261 +                                       have_content_length = 1;
17262                                 }
17263                                 
17264 -                               con->file_started = 1;
17265 +                               if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
17266 +                                       ds = data_response_init();
17267 +                               }
17268 +                               buffer_copy_string_buffer(ds->key, header->key);
17269 +                               buffer_copy_string_buffer(ds->value, header->value);
17270 +
17271 +                               array_insert_unique(con->response.headers, (data_unset *)ds);
17272                         }
17273 -               } else {
17274 -                       http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
17275 -                       joblist_append(srv, con);
17276 +
17277 +                       con->file_started = 1;
17278 +                       sess->state = CGI_STATE_READ_RESPONSE_CONTENT;
17279 +
17280 +                       if (con->request.http_version == HTTP_VERSION_1_1 &&
17281 +                           !have_content_length) {
17282 +                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
17283 +                       }
17284 +
17285 +                       break;
17286                 }
17287 -               
17288 -#if 0          
17289 -               log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr);
17290 -#endif
17291         }
17292 -       
17293 -       return FDEVENT_HANDLED_NOT_FINISHED;
17294 +
17295 +       /* FIXME: pass the response-header to the other plugins to
17296 +       * setup the filter-queue
17297 +       *
17298 +       * - use next-queue instead of con->write_queue
17299 +       */
17300 +
17301 +       /* copy the content to the next cq */
17302 +       for (c = sess->rb->first; c; c = c->next) {
17303 +               http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
17304 +
17305 +               c->offset = c->mem->used - 1;
17306 +       }
17307 +
17308 +       chunkqueue_remove_finished_chunks(sess->rb);
17309 +       joblist_append(srv, con);
17310 +
17311 +       return 0;
17312  }
17313  
17314 -static handler_t cgi_connection_close(server *srv, handler_ctx *hctx) {
17315 +static handler_t cgi_connection_close(server *srv, connection *con, plugin_data *p) {
17316 +       cgi_session *sess = con->plugin_ctx[p->id];
17317         int status;
17318         pid_t pid;
17319 -       plugin_data *p;
17320 -       connection  *con;
17321 -       
17322 -       if (NULL == hctx) return HANDLER_GO_ON;
17323 -       
17324 -       p    = hctx->plugin_data;
17325 -       con  = hctx->remote_conn;
17326 -       
17327 +
17328 +       if (NULL == sess) return HANDLER_GO_ON;
17329         if (con->mode != p->id) return HANDLER_GO_ON;
17330  
17331 -#ifndef __WIN32
17332 -       
17333 +#ifndef _WIN32
17334 +
17335         /* the connection to the browser went away, but we still have a connection
17336 -        * to the CGI script 
17337 +        * to the CGI script
17338          *
17339          * close cgi-connection
17340          */
17341 -       
17342 -       if (hctx->fd != -1) {
17343 +
17344 +       if (sess->sock->fd != -1) {
17345                 /* close connection to the cgi-script */
17346 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
17347 -               fdevent_unregister(srv->ev, hctx->fd);
17348 -               
17349 -               if (close(hctx->fd)) {
17350 -                       log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
17351 -               }
17352 -               
17353 -               hctx->fd = -1;
17354 -               hctx->fde_ndx = -1;
17355 +               fdevent_event_del(srv->ev, sess->sock);
17356 +               fdevent_unregister(srv->ev, sess->sock);
17357         }
17358 -       
17359 -       pid = hctx->pid;
17360 -       
17361 +
17362 +       pid = sess->pid;
17363 +
17364         con->plugin_ctx[p->id] = NULL;
17365 -       
17366 +
17367         /* is this a good idea ? */
17368 -       cgi_handler_ctx_free(hctx);
17369 -       
17370 +       cgi_session_free(sess);
17371 +       sess = NULL;
17372 +
17373         /* if waitpid hasn't been called by response.c yet, do it here */
17374         if (pid) {
17375                 /* check if the CGI-script is already gone */
17376 +#ifndef _WIN32
17377                 switch(waitpid(pid, &status, WNOHANG)) {
17378                 case 0:
17379                         /* not finished yet */
17380 @@ -519,35 +384,35 @@
17381                 case -1:
17382                         /* */
17383                         if (errno == EINTR) break;
17384 -                       
17385 -                       /* 
17386 -                        * errno == ECHILD happens if _subrequest catches the process-status before 
17387 +
17388 +                       /*
17389 +                        * errno == ECHILD happens if _subrequest catches the process-status before
17390                          * we have read the response of the cgi process
17391 -                        * 
17392 +                        *
17393                          * -> catch status
17394                          * -> WAIT_FOR_EVENT
17395                          * -> read response
17396                          * -> we get here with waitpid == ECHILD
17397 -                        * 
17398 +                        *
17399                          */
17400                         if (errno == ECHILD) return HANDLER_GO_ON;
17401 -                       
17402 +
17403                         log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
17404                         return HANDLER_ERROR;
17405                 default:
17406                         /* Send an error if we haven't sent any data yet */
17407                         if (0 == con->file_started) {
17408                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
17409 -                               con->http_status = 500;
17410 +                               if (con->http_status == 0) con->http_status = 500;
17411                                 con->mode = DIRECT;
17412                         }
17413 -                               
17414 +
17415                         if (WIFEXITED(status)) {
17416  #if 0
17417                                 log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) cgi exited fine, pid:", pid);
17418  #endif
17419                                 pid = 0;
17420 -                               
17421 +
17422                                 return HANDLER_GO_ON;
17423                         } else {
17424                                 log_error_write(srv, __FILE__, __LINE__, "sd", "cgi died, pid:", pid);
17425 @@ -555,122 +420,126 @@
17426                                 return HANDLER_GO_ON;
17427                         }
17428                 }
17429 -               
17430 -       
17431 +
17432 +
17433                 kill(pid, SIGTERM);
17434 -               
17435 +#endif
17436                 /* cgi-script is still alive, queue the PID for removal */
17437                 cgi_pid_add(srv, p, pid);
17438         }
17439 -#endif 
17440 +#endif
17441         return HANDLER_GO_ON;
17442  }
17443  
17444  static handler_t cgi_connection_close_callback(server *srv, connection *con, void *p_d) {
17445         plugin_data *p = p_d;
17446 -       
17447 -       return cgi_connection_close(srv, con->plugin_ctx[p->id]);
17448 +
17449 +       return cgi_connection_close(srv, con, p);
17450  }
17451  
17452  
17453  static handler_t cgi_handle_fdevent(void *s, void *ctx, int revents) {
17454         server      *srv  = (server *)s;
17455 -       handler_ctx *hctx = ctx;
17456 -       connection  *con  = hctx->remote_conn;
17457 -       
17458 -       joblist_append(srv, con);
17459 -       
17460 -       if (hctx->fd == -1) {
17461 -               log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "invalid cgi-fd");
17462 -               
17463 -               return HANDLER_ERROR;
17464 -       }
17465 -       
17466 +       cgi_session *sess = ctx;
17467 +       connection  *con  = sess->remote_con;
17468 +       chunk *c;
17469 +
17470         if (revents & FDEVENT_IN) {
17471 -               switch (cgi_demux_response(srv, hctx)) {
17472 -               case FDEVENT_HANDLED_NOT_FINISHED:
17473 +               switch (sess->state) {
17474 +               case CGI_STATE_READ_RESPONSE_HEADER:
17475 +                       /* parse the header and set file-started, the demuxer will care about it */
17476 +                       joblist_append(srv, con);
17477 +
17478                         break;
17479 -               case FDEVENT_HANDLED_FINISHED:
17480 -                       /* we are done */
17481 -                       
17482 +               case CGI_STATE_READ_RESPONSE_CONTENT:
17483 +                       /* just forward the content to the out-going queue */
17484 +
17485 +                       chunkqueue_remove_finished_chunks(sess->rb);
17486 +
17487 +                       switch (srv->network_backend_read(srv, sess->remote_con, sess->sock, sess->rb)) {
17488 +                       case NETWORK_STATUS_CONNECTION_CLOSE:
17489 +                               fdevent_event_del(srv->ev, sess->sock);
17490 +
17491 +                               /* the connection is gone
17492 +                                * make the connect */
17493 +                               sess->remote_con->file_finished = 1;
17494  #if 0
17495 -                       log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "finished");
17496 +                               fdevent_event_del(srv->ev, sess->sock);
17497  #endif
17498 -                       cgi_connection_close(srv, hctx);
17499 -                       
17500 -                       /* if we get a IN|HUP and have read everything don't exec the close twice */ 
17501 -                       return HANDLER_FINISHED;
17502 -               case FDEVENT_HANDLED_ERROR:
17503 -                       connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
17504 -                       con->http_status = 500;
17505 -                       con->mode = DIRECT;
17506 -                       
17507 -                       log_error_write(srv, __FILE__, __LINE__, "s", "demuxer failed: ");
17508 +                       case NETWORK_STATUS_SUCCESS:
17509 +                               /* read even more, do we have all the content */
17510 +
17511 +                               /* how much do we want to read ? */
17512 +                               
17513 +                               /* call stream-decoder (HTTP-chunked, FastCGI, ... ) */
17514 +
17515 +                               chunkqueue_remove_finished_chunks(sess->rb);
17516 +
17517 +                               /* copy the content to the next cq */
17518 +                               for (c = sess->rb->first; c; c = c->next) {
17519 +                                       if (c->mem->used == 0) continue;
17520 +
17521 +                                       http_chunk_append_mem(srv, sess->remote_con, c->mem->ptr + c->offset, c->mem->used - c->offset);
17522 +       
17523 +                                       c->offset = c->mem->used - 1;
17524 +
17525 +                               }
17526 +                               chunkqueue_remove_finished_chunks(sess->rb);
17527 +
17528 +                               if (sess->remote_con->file_finished) {
17529 +                                       /* send final HTTP-Chunk packet */
17530 +                                       http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
17531 +                               }
17532 +                               
17533 +                               break;
17534 +                       default:
17535 +                               ERROR("%s", "oops, we failed to read");
17536 +                               break;
17537 +                       }
17538 +
17539 +                       joblist_append(srv, sess->remote_con);
17540 +                       break;
17541 +               default:
17542 +                       TRACE("unexpected state for a FDEVENT_IN: %d", sess->state);
17543                         break;
17544                 }
17545         }
17546 -       
17547 +
17548         if (revents & FDEVENT_OUT) {
17549                 /* nothing to do */
17550         }
17551 -       
17552 +
17553         /* perhaps this issue is already handled */
17554         if (revents & FDEVENT_HUP) {
17555 -               /* check if we still have a unfinished header package which is a body in reality */
17556 -               if (con->file_started == 0 &&
17557 -                   hctx->response_header->used) {
17558 -                       con->file_started = 1;
17559 -                       http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
17560 -                       joblist_append(srv, con);
17561 -               }
17562 -               
17563 -               if (con->file_finished == 0) {
17564 -                       http_chunk_append_mem(srv, con, NULL, 0);
17565 -                       joblist_append(srv, con);
17566 -               }
17567 -               
17568                 con->file_finished = 1;
17569 -               
17570 -               if (chunkqueue_is_empty(con->write_queue)) {
17571 -                       /* there is nothing left to write */
17572 -                       connection_set_state(srv, con, CON_STATE_RESPONSE_END);
17573 -               } else {
17574 -                       /* used the write-handler to finish the request on demand */
17575 -                       
17576 -               }
17577 -               
17578 -# if 0
17579 -               log_error_write(srv, __FILE__, __LINE__, "sddd", "got HUP from cgi", con->fd, hctx->fd, revents);
17580 -# endif
17581 -               
17582 -               /* rtsigs didn't liked the close */
17583 -               cgi_connection_close(srv, hctx);
17584 +
17585 +               fdevent_event_del(srv->ev, sess->sock);
17586 +
17587 +               /* someone has to close this socket now :) */
17588 +               http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
17589 +               joblist_append(srv, sess->remote_con);
17590         } else if (revents & FDEVENT_ERR) {
17591                 con->file_finished = 1;
17592 -               
17593 +
17594                 /* kill all connections to the cgi process */
17595 -               cgi_connection_close(srv, hctx);
17596 -#if 1
17597 -               log_error_write(srv, __FILE__, __LINE__, "s", "cgi-FDEVENT_ERR");
17598 -#endif                 
17599 -               return HANDLER_ERROR;
17600 +               fdevent_event_del(srv->ev, sess->sock);
17601         }
17602 -       
17603 +
17604         return HANDLER_FINISHED;
17605  }
17606  
17607  
17608  static int cgi_env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
17609         char *dst;
17610 -       
17611 +
17612         if (!key || !val) return -1;
17613 -       
17614 +
17615         dst = malloc(key_len + val_len + 3);
17616         memcpy(dst, key, key_len);
17617         dst[key_len] = '=';
17618         /* add the \0 from the value */
17619         memcpy(dst + key_len + 1, val, val_len + 1);
17620 -       
17621 +
17622         if (env->size == 0) {
17623                 env->size = 16;
17624                 env->ptr = malloc(env->size * sizeof(*env->ptr));
17625 @@ -678,45 +547,45 @@
17626                 env->size += 16;
17627                 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
17628         }
17629 -       
17630 +
17631         env->ptr[env->used++] = dst;
17632 -       
17633 +
17634         return 0;
17635  }
17636  
17637  static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *cgi_handler) {
17638         pid_t pid;
17639 -       
17640 +
17641  #ifdef HAVE_IPV6
17642         char b2[INET6_ADDRSTRLEN + 1];
17643  #endif
17644 -       
17645 +
17646         int to_cgi_fds[2];
17647         int from_cgi_fds[2];
17648         struct stat st;
17649 -       
17650 -#ifndef __WIN32        
17651 -       
17652 +
17653 +#ifndef _WIN32
17654 +
17655         if (cgi_handler->used > 1) {
17656                 /* stat the exec file */
17657                 if (-1 == (stat(cgi_handler->ptr, &st))) {
17658 -                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
17659 +                       log_error_write(srv, __FILE__, __LINE__, "sbss",
17660                                         "stat for cgi-handler", cgi_handler,
17661                                         "failed:", strerror(errno));
17662                         return -1;
17663                 }
17664         }
17665 -       
17666 +
17667         if (pipe(to_cgi_fds)) {
17668                 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
17669                 return -1;
17670         }
17671 -       
17672 +
17673         if (pipe(from_cgi_fds)) {
17674                 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
17675                 return -1;
17676         }
17677 -       
17678 +
17679         /* fork, execve */
17680         switch (pid = fork()) {
17681         case 0: {
17682 @@ -730,44 +599,40 @@
17683                 char *c;
17684                 const char *s;
17685                 server_socket *srv_sock = con->srv_socket;
17686 -               
17687 +
17688                 /* move stdout to from_cgi_fd[1] */
17689                 close(STDOUT_FILENO);
17690                 dup2(from_cgi_fds[1], STDOUT_FILENO);
17691                 close(from_cgi_fds[1]);
17692                 /* not needed */
17693                 close(from_cgi_fds[0]);
17694 -               
17695 +
17696                 /* move the stdin to to_cgi_fd[0] */
17697                 close(STDIN_FILENO);
17698                 dup2(to_cgi_fds[0], STDIN_FILENO);
17699                 close(to_cgi_fds[0]);
17700                 /* not needed */
17701                 close(to_cgi_fds[1]);
17702 -               
17703 -               /* HACK: 
17704 -                * this is not nice, but it works
17705 -                *
17706 -                * we feed the stderr of the CGI to our errorlog, if possible
17707 +
17708 +               /**
17709 +                * FIXME: add a event-handler for STDERR_FILENO and let it LOG()
17710                  */
17711 -               if (srv->errorlog_mode == ERRORLOG_FILE) {
17712 -                       close(STDERR_FILENO);
17713 -                       dup2(srv->errorlog_fd, STDERR_FILENO);
17714 -               }
17715 -               
17716 +
17717 +               close(STDERR_FILENO);
17718 +
17719                 /* create environment */
17720                 env.ptr = NULL;
17721                 env.size = 0;
17722                 env.used = 0;
17723 -               
17724 +
17725                 cgi_env_add(&env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
17726  
17727                 if (!buffer_is_empty(con->server_name)) {
17728                         cgi_env_add(&env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
17729                 } else {
17730  #ifdef HAVE_IPV6
17731 -                       s = inet_ntop(srv_sock->addr.plain.sa_family, 
17732 -                                     srv_sock->addr.plain.sa_family == AF_INET6 ? 
17733 +                       s = inet_ntop(srv_sock->addr.plain.sa_family,
17734 +                                     srv_sock->addr.plain.sa_family == AF_INET6 ?
17735                                       (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
17736                                       (const void *) &(srv_sock->addr.ipv4.sin_addr),
17737                                       b2, sizeof(b2)-1);
17738 @@ -779,10 +644,10 @@
17739                 cgi_env_add(&env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
17740  
17741                 s = get_http_version_name(con->request.http_version);
17742 -               
17743 +
17744                 cgi_env_add(&env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
17745 -               
17746 -               ltostr(buf, 
17747 +
17748 +               ltostr(buf,
17749  #ifdef HAVE_IPV6
17750                         ntohs(srv_sock->addr.plain.sa_family == AF_INET6 ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
17751  #else
17752 @@ -790,10 +655,10 @@
17753  #endif
17754                         );
17755                 cgi_env_add(&env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
17756 -               
17757 +
17758  #ifdef HAVE_IPV6
17759 -               s = inet_ntop(srv_sock->addr.plain.sa_family, 
17760 -                             srv_sock->addr.plain.sa_family == AF_INET6 ? 
17761 +               s = inet_ntop(srv_sock->addr.plain.sa_family,
17762 +                             srv_sock->addr.plain.sa_family == AF_INET6 ?
17763                               (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
17764                               (const void *) &(srv_sock->addr.ipv4.sin_addr),
17765                               b2, sizeof(b2)-1);
17766 @@ -811,15 +676,18 @@
17767                 cgi_env_add(&env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200"));
17768                 if (!buffer_is_empty(con->uri.query)) {
17769                         cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
17770 +               } else {
17771 +                       /* set a empty QUERY_STRING */
17772 +                       cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
17773                 }
17774                 if (!buffer_is_empty(con->request.orig_uri)) {
17775                         cgi_env_add(&env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
17776                 }
17777 -               
17778 -               
17779 +
17780 +
17781  #ifdef HAVE_IPV6
17782 -               s = inet_ntop(con->dst_addr.plain.sa_family, 
17783 -                             con->dst_addr.plain.sa_family == AF_INET6 ? 
17784 +               s = inet_ntop(con->dst_addr.plain.sa_family,
17785 +                             con->dst_addr.plain.sa_family == AF_INET6 ?
17786                               (const void *) &(con->dst_addr.ipv6.sin6_addr) :
17787                               (const void *) &(con->dst_addr.ipv4.sin_addr),
17788                               b2, sizeof(b2)-1);
17789 @@ -828,7 +696,7 @@
17790  #endif
17791                 cgi_env_add(&env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
17792  
17793 -               ltostr(buf, 
17794 +               ltostr(buf,
17795  #ifdef HAVE_IPV6
17796                         ntohs(con->dst_addr.plain.sa_family == AF_INET6 ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
17797  #else
17798 @@ -836,19 +704,19 @@
17799  #endif
17800                         );
17801                 cgi_env_add(&env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
17802 -               
17803 +
17804                 if (!buffer_is_empty(con->authed_user)) {
17805                         cgi_env_add(&env, CONST_STR_LEN("REMOTE_USER"),
17806                                     CONST_BUF_LEN(con->authed_user));
17807                 }
17808 -               
17809 +
17810                 /* request.content_length < SSIZE_MAX, see request.c */
17811                 ltostr(buf, con->request.content_length);
17812                 cgi_env_add(&env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
17813                 cgi_env_add(&env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
17814                 cgi_env_add(&env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
17815                 cgi_env_add(&env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
17816 -               
17817 +
17818                 /* for valgrind */
17819                 if (NULL != (s = getenv("LD_PRELOAD"))) {
17820                         cgi_env_add(&env, CONST_STR_LEN("LD_PRELOAD"), s, strlen(s));
17821 @@ -863,24 +731,24 @@
17822                         cgi_env_add(&env, CONST_STR_LEN("SYSTEMROOT"), s, strlen(s));
17823                 }
17824  #endif
17825 -               
17826 +
17827                 for (n = 0; n < con->request.headers->used; n++) {
17828                         data_string *ds;
17829 -                       
17830 +
17831                         ds = (data_string *)con->request.headers->data[n];
17832 -                       
17833 +
17834                         if (ds->value->used && ds->key->used) {
17835                                 size_t j;
17836 -                               
17837 +
17838                                 buffer_reset(p->tmp_buf);
17839 -                               
17840 +
17841                                 if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
17842                                         buffer_copy_string(p->tmp_buf, "HTTP_");
17843                                         p->tmp_buf->used--; /* strip \0 after HTTP_ */
17844                                 }
17845 -                               
17846 +
17847                                 buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
17848 -                               
17849 +
17850                                 for (j = 0; j < ds->key->used - 1; j++) {
17851                                         char cr = '_';
17852                                         if (light_isalpha(ds->key->ptr[j])) {
17853 @@ -893,46 +761,46 @@
17854                                         p->tmp_buf->ptr[p->tmp_buf->used++] = cr;
17855                                 }
17856                                 p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
17857 -                               
17858 +
17859                                 cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
17860                         }
17861                 }
17862 -               
17863 +
17864                 for (n = 0; n < con->environment->used; n++) {
17865                         data_string *ds;
17866 -                       
17867 +
17868                         ds = (data_string *)con->environment->data[n];
17869 -                       
17870 +
17871                         if (ds->value->used && ds->key->used) {
17872                                 size_t j;
17873 -                               
17874 +
17875                                 buffer_reset(p->tmp_buf);
17876 -                               
17877 +
17878                                 buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
17879 -                               
17880 +
17881                                 for (j = 0; j < ds->key->used - 1; j++) {
17882 -                                       p->tmp_buf->ptr[p->tmp_buf->used++] = 
17883 -                                               isalpha((unsigned char)ds->key->ptr[j]) ? 
17884 +                                       p->tmp_buf->ptr[p->tmp_buf->used++] =
17885 +                                               isalpha((unsigned char)ds->key->ptr[j]) ?
17886                                                 toupper((unsigned char)ds->key->ptr[j]) : '_';
17887                                 }
17888                                 p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
17889 -                               
17890 +
17891                                 cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
17892                         }
17893                 }
17894 -               
17895 +
17896                 if (env.size == env.used) {
17897                         env.size += 16;
17898                         env.ptr = realloc(env.ptr, env.size * sizeof(*env.ptr));
17899                 }
17900 -               
17901 +
17902                 env.ptr[env.used] = NULL;
17903 -               
17904 +
17905                 /* set up args */
17906                 argc = 3;
17907                 args = malloc(sizeof(*args) * argc);
17908                 i = 0;
17909 -               
17910 +
17911                 if (cgi_handler->used > 1) {
17912                         args[i++] = cgi_handler->ptr;
17913                 }
17914 @@ -942,7 +810,7 @@
17915                 /* search for the last / */
17916                 if (NULL != (c = strrchr(con->physical.path->ptr, '/'))) {
17917                         *c = '\0';
17918 -                       
17919 +
17920                         /* change to the physical directory */
17921                         if (-1 == chdir(con->physical.path->ptr)) {
17922                                 log_error_write(srv, __FILE__, __LINE__, "ssb", "chdir failed:", strerror(errno), con->physical.path);
17923 @@ -952,14 +820,14 @@
17924  
17925                 /* we don't need the client socket */
17926                 for (i = 3; i < 256; i++) {
17927 -                       if (i != srv->errorlog_fd) close(i);
17928 +                       close(i);
17929                 }
17930 -               
17931 +
17932                 /* exec the cgi */
17933                 execve(args[0], args, env.ptr);
17934 -               
17935 +
17936                 log_error_write(srv, __FILE__, __LINE__, "sss", "CGI failed:", strerror(errno), args[0]);
17937 -               
17938 +
17939                 /* */
17940                 SEGFAULT();
17941                 break;
17942 @@ -969,16 +837,16 @@
17943                 log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed:", strerror(errno));
17944                 break;
17945         default: {
17946 -               handler_ctx *hctx;
17947 +               cgi_session *sess;
17948                 /* father */
17949  
17950                 close(from_cgi_fds[1]);
17951                 close(to_cgi_fds[0]);
17952 -               
17953 +
17954                 if (con->request.content_length) {
17955                         chunkqueue *cq = con->request_content_queue;
17956                         chunk *c;
17957 -               
17958 +
17959                         assert(chunkqueue_length(cq) == (off_t)con->request.content_length);
17960  
17961                         /* there is content to send */
17962 @@ -993,16 +861,16 @@
17963                                                 if (-1 == c->file.fd &&  /* open the file if not already open */
17964                                                     -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
17965                                                         log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
17966 -                                       
17967 +
17968                                                         close(from_cgi_fds[0]);
17969                                                         close(to_cgi_fds[1]);
17970                                                         return -1;
17971                                                 }
17972  
17973                                                 c->file.mmap.length = c->file.length;
17974 -                               
17975 +
17976                                                 if (MAP_FAILED == (c->file.mmap.start = mmap(0,  c->file.mmap.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
17977 -                                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ", 
17978 +                                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
17979                                                                         strerror(errno), c->file.name,  c->file.fd);
17980  
17981                                                         close(from_cgi_fds[0]);
17982 @@ -1012,7 +880,7 @@
17983  
17984                                                 close(c->file.fd);
17985                                                 c->file.fd = -1;
17986 -       
17987 +
17988                                                 /* chunk_reset() or chunk_free() will cleanup for us */
17989                                         }
17990  
17991 @@ -1020,7 +888,7 @@
17992                                                 switch(errno) {
17993                                                 case ENOSPC:
17994                                                         con->http_status = 507;
17995 -               
17996 +
17997                                                         break;
17998                                                 default:
17999                                                         con->http_status = 403;
18000 @@ -1033,7 +901,7 @@
18001                                                 switch(errno) {
18002                                                 case ENOSPC:
18003                                                         con->http_status = 507;
18004 -               
18005 +
18006                                                         break;
18007                                                 default:
18008                                                         con->http_status = 403;
18009 @@ -1056,103 +924,95 @@
18010                 }
18011  
18012                 close(to_cgi_fds[1]);
18013 -                               
18014 +
18015                 /* register PID and wait for them asyncronously */
18016                 con->mode = p->id;
18017                 buffer_reset(con->physical.path);
18018 -               
18019 -               hctx = cgi_handler_ctx_init();
18020 -               
18021 -               hctx->remote_conn = con;
18022 -               hctx->plugin_data = p;
18023 -               hctx->pid = pid;
18024 -               hctx->fd = from_cgi_fds[0];
18025 -               hctx->fde_ndx = -1;
18026 -               
18027 -               con->plugin_ctx[p->id] = hctx;
18028 -               
18029 -               fdevent_register(srv->ev, hctx->fd, cgi_handle_fdevent, hctx);
18030 -               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
18031 -               
18032 -               if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
18033 +
18034 +               sess = cgi_session_init();
18035 +
18036 +               sess->remote_con = con;
18037 +               sess->pid = pid;
18038 +
18039 +               assert(sess->sock);
18040 +
18041 +               sess->sock->fd = from_cgi_fds[0];
18042 +               sess->sock->type = IOSOCKET_TYPE_PIPE;
18043 +
18044 +               if (-1 == fdevent_fcntl_set(srv->ev, sess->sock)) {
18045                         log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
18046 -                       
18047 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
18048 -                       fdevent_unregister(srv->ev, hctx->fd);
18049 -                       
18050 -                       log_error_write(srv, __FILE__, __LINE__, "sd", "cgi close:", hctx->fd);
18051 -                       
18052 -                       close(hctx->fd);
18053 -                       
18054 -                       cgi_handler_ctx_free(hctx);
18055 -                       
18056 -                       con->plugin_ctx[p->id] = NULL;
18057 -                       
18058 +
18059 +                       cgi_session_free(sess);
18060 +
18061                         return -1;
18062                 }
18063 -               
18064 +
18065 +               con->plugin_ctx[p->id] = sess;
18066 +
18067 +               fdevent_register(srv->ev, sess->sock, cgi_handle_fdevent, sess);
18068 +               fdevent_event_add(srv->ev, sess->sock, FDEVENT_IN);
18069 +
18070 +               sess->state = CGI_STATE_READ_RESPONSE_HEADER;
18071 +
18072                 break;
18073         }
18074         }
18075 -       
18076 +
18077         return 0;
18078  #else
18079         return -1;
18080  #endif
18081  }
18082  
18083 -#define PATCH(x) \
18084 -       p->conf.x = s->x;
18085  static int mod_cgi_patch_connection(server *srv, connection *con, plugin_data *p) {
18086         size_t i, j;
18087         plugin_config *s = p->config_storage[0];
18088 -       
18089 -       PATCH(cgi);
18090 -       
18091 +
18092 +       PATCH_OPTION(cgi);
18093 +
18094         /* skip the first, the global context */
18095         for (i = 1; i < srv->config_context->used; i++) {
18096                 data_config *dc = (data_config *)srv->config_context->data[i];
18097                 s = p->config_storage[i];
18098 -               
18099 +
18100                 /* condition didn't match */
18101                 if (!config_check_cond(srv, con, dc)) continue;
18102 -               
18103 +
18104                 /* merge config */
18105                 for (j = 0; j < dc->value->used; j++) {
18106                         data_unset *du = dc->value->data[j];
18107 -                       
18108 +
18109                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.assign"))) {
18110 -                               PATCH(cgi);
18111 +                               PATCH_OPTION(cgi);
18112                         }
18113                 }
18114         }
18115 -       
18116 +
18117         return 0;
18118  }
18119 -#undef PATCH
18120  
18121  URIHANDLER_FUNC(cgi_is_handled) {
18122         size_t k, s_len;
18123         plugin_data *p = p_d;
18124         buffer *fn = con->physical.path;
18125 -       
18126 +
18127         if (fn->used == 0) return HANDLER_GO_ON;
18128 -       
18129 +
18130         mod_cgi_patch_connection(srv, con, p);
18131 -       
18132 +
18133         s_len = fn->used - 1;
18134 -       
18135 +
18136         for (k = 0; k < p->conf.cgi->used; k++) {
18137                 data_string *ds = (data_string *)p->conf.cgi->data[k];
18138                 size_t ct_len = ds->key->used - 1;
18139 -               
18140 +
18141                 if (ds->key->used == 0) continue;
18142                 if (s_len < ct_len) continue;
18143 -               
18144 +
18145                 if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
18146                         if (cgi_create_env(srv, con, p, ds->value)) {
18147                                 con->http_status = 500;
18148 -                               
18149 +
18150                                 buffer_reset(con->physical.path);
18151                                 return HANDLER_FINISHED;
18152                         }
18153 @@ -1160,7 +1020,7 @@
18154                         break;
18155                 }
18156         }
18157 -       
18158 +
18159         return HANDLER_GO_ON;
18160  }
18161  
18162 @@ -1168,11 +1028,11 @@
18163         plugin_data *p = p_d;
18164         size_t ndx;
18165         /* the trigger handle only cares about lonely PID which we have to wait for */
18166 -#ifndef __WIN32
18167 +#ifndef _WIN32
18168  
18169         for (ndx = 0; ndx < p->cgi_pid.used; ndx++) {
18170                 int status;
18171 -               
18172 +
18173                 switch(waitpid(p->cgi_pid.ptr[ndx], &status, WNOHANG)) {
18174                 case 0:
18175                         /* not finished yet */
18176 @@ -1182,7 +1042,7 @@
18177                         break;
18178                 case -1:
18179                         log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
18180 -                       
18181 +
18182                         return HANDLER_ERROR;
18183                 default:
18184  
18185 @@ -1193,96 +1053,105 @@
18186                         } else {
18187                                 log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?");
18188                         }
18189 -                       
18190 +
18191                         cgi_pid_del(srv, p, p->cgi_pid.ptr[ndx]);
18192 -                       /* del modified the buffer structure 
18193 +                       /* del modified the buffer structure
18194                          * and copies the last entry to the current one
18195                          * -> recheck the current index
18196                          */
18197                         ndx--;
18198                 }
18199         }
18200 -#endif 
18201 +#endif
18202         return HANDLER_GO_ON;
18203  }
18204  
18205  SUBREQUEST_FUNC(mod_cgi_handle_subrequest) {
18206         int status;
18207         plugin_data *p = p_d;
18208 -       handler_ctx *hctx = con->plugin_ctx[p->id];
18209 -       
18210 +       cgi_session *sess = con->plugin_ctx[p->id];
18211 +
18212         if (con->mode != p->id) return HANDLER_GO_ON;
18213 -       if (NULL == hctx) return HANDLER_GO_ON;
18214 -       
18215 +       if (NULL == sess) return HANDLER_GO_ON;
18216 +
18217 +       switch (cgi_demux_response(srv, con, p)) {
18218 +       case 0:
18219 +               break;
18220 +       case 1:
18221 +               cgi_connection_close(srv, con, p);
18222 +
18223 +               /* if we get a IN|HUP and have read everything don't exec the close twice */
18224 +               return HANDLER_FINISHED;
18225 +       case -1:
18226 +               cgi_connection_close(srv, con, p);
18227 +
18228 +               if (0 == con->http_status) con->http_status = 500;
18229 +               connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
18230 +               con->mode = DIRECT;
18231 +
18232 +               return HANDLER_FINISHED;
18233 +       }
18234 +
18235  #if 0
18236 -       log_error_write(srv, __FILE__, __LINE__, "sdd", "subrequest, pid =", hctx, hctx->pid);
18237 -#endif 
18238 -       if (hctx->pid == 0) return HANDLER_FINISHED;
18239 -#ifndef __WIN32        
18240 -       switch(waitpid(hctx->pid, &status, WNOHANG)) {
18241 +       log_error_write(srv, __FILE__, __LINE__, "sdd", "subrequest, pid =", sess, sess->pid);
18242 +#endif
18243 +       if (sess->pid == 0) return HANDLER_FINISHED;
18244 +#ifndef _WIN32
18245 +       switch(waitpid(sess->pid, &status, WNOHANG)) {
18246         case 0:
18247                 /* we only have for events here if we don't have the header yet,
18248                  * otherwise the event-handler will send us the incoming data */
18249 -               if (con->file_started) return HANDLER_FINISHED;
18250  
18251 -               return HANDLER_WAIT_FOR_EVENT;
18252 +               if (!con->file_started) return HANDLER_WAIT_FOR_EVENT;
18253 +               if (con->file_finished) return HANDLER_FINISHED;
18254 +
18255 +               return HANDLER_GO_ON;
18256         case -1:
18257                 if (errno == EINTR) return HANDLER_WAIT_FOR_EVENT;
18258 -               
18259 +
18260                 if (errno == ECHILD && con->file_started == 0) {
18261                         /*
18262 -                        * second round but still not response 
18263 +                        * second round but still not response
18264                          */
18265 -                       return HANDLER_WAIT_FOR_EVENT; 
18266 +                       return HANDLER_WAIT_FOR_EVENT;
18267                 }
18268 -               
18269 +
18270                 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
18271                 con->mode = DIRECT;
18272                 con->http_status = 500;
18273 -               
18274 -               hctx->pid = 0;
18275 -               
18276 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
18277 -               fdevent_unregister(srv->ev, hctx->fd);
18278 -               
18279 -               if (close(hctx->fd)) {
18280 -                       log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
18281 -               }
18282 -               
18283 -               cgi_handler_ctx_free(hctx);
18284 -               
18285 +
18286 +               sess->pid = 0;
18287 +
18288 +               fdevent_event_del(srv->ev, sess->sock);
18289 +               fdevent_unregister(srv->ev, sess->sock);
18290 +
18291 +               cgi_session_free(sess);
18292 +               sess = NULL;
18293 +
18294                 con->plugin_ctx[p->id] = NULL;
18295 -               
18296 +
18297                 return HANDLER_FINISHED;
18298         default:
18299 -               /* cgi process exited cleanly 
18300 -                * 
18301 -                * check if we already got the response 
18302 -                */
18303 -               
18304 -               if (!con->file_started) return HANDLER_WAIT_FOR_EVENT;
18305 -               
18306 +               con->file_finished = 1;
18307 +
18308                 if (WIFEXITED(status)) {
18309                         /* nothing */
18310                 } else {
18311                         log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?");
18312 -                       
18313 +
18314                         con->mode = DIRECT;
18315                         con->http_status = 500;
18316 -                       
18317 +
18318                 }
18319 -               
18320 -               hctx->pid = 0;
18321 -               
18322 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
18323 -               fdevent_unregister(srv->ev, hctx->fd);
18324 -               
18325 -               if (close(hctx->fd)) {
18326 -                       log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
18327 -               }
18328 -               
18329 -               cgi_handler_ctx_free(hctx);
18330 -               
18331 +
18332 +               sess->pid = 0;
18333 +
18334 +               fdevent_event_del(srv->ev, sess->sock);
18335 +               fdevent_unregister(srv->ev, sess->sock);
18336 +
18337 +               cgi_session_free(sess);
18338 +               sess = NULL;
18339 +
18340                 con->plugin_ctx[p->id] = NULL;
18341                 return HANDLER_FINISHED;
18342         }
18343 @@ -1306,8 +1175,8 @@
18344         p->init           = mod_cgi_init;
18345         p->cleanup        = mod_cgi_free;
18346         p->set_defaults   = mod_fastcgi_set_defaults;
18347 -       
18348 +
18349         p->data        = NULL;
18350 -       
18351 +
18352         return 0;
18353  }
18354 --- ../lighttpd-1.4.11/src/mod_cml.c    2006-01-30 13:51:48.000000000 +0200
18355 +++ lighttpd-1.4.12/src/mod_cml.c       2006-07-16 00:26:03.000000000 +0300
18356 @@ -4,7 +4,6 @@
18357  #include <stdlib.h>
18358  #include <string.h>
18359  #include <errno.h>
18360 -#include <unistd.h>
18361  #include <stdio.h>
18362  
18363  #include "buffer.h"
18364 @@ -20,50 +19,50 @@
18365  /* init the plugin data */
18366  INIT_FUNC(mod_cml_init) {
18367         plugin_data *p;
18368 -       
18369 +
18370         p = calloc(1, sizeof(*p));
18371 -       
18372 +
18373         p->basedir         = buffer_init();
18374         p->baseurl         = buffer_init();
18375         p->trigger_handler = buffer_init();
18376 -       
18377 +
18378         return p;
18379  }
18380  
18381  /* detroy the plugin data */
18382  FREE_FUNC(mod_cml_free) {
18383         plugin_data *p = p_d;
18384 -       
18385 +
18386         UNUSED(srv);
18387  
18388         if (!p) return HANDLER_GO_ON;
18389 -       
18390 +
18391         if (p->config_storage) {
18392                 size_t i;
18393                 for (i = 0; i < srv->config_context->used; i++) {
18394                         plugin_config *s = p->config_storage[i];
18395 -                       
18396 +
18397                         buffer_free(s->ext);
18398 -                       
18399 +
18400                         buffer_free(s->mc_namespace);
18401                         buffer_free(s->power_magnet);
18402                         array_free(s->mc_hosts);
18403 -                       
18404 +
18405  #if defined(HAVE_MEMCACHE_H)
18406                         if (s->mc) mc_free(s->mc);
18407  #endif
18408 -                       
18409 +
18410                         free(s);
18411                 }
18412                 free(p->config_storage);
18413         }
18414 -       
18415 +
18416         buffer_free(p->trigger_handler);
18417         buffer_free(p->basedir);
18418         buffer_free(p->baseurl);
18419 -       
18420 +
18421         free(p);
18422 -       
18423 +
18424         return HANDLER_GO_ON;
18425  }
18426  
18427 @@ -72,22 +71,22 @@
18428  SETDEFAULTS_FUNC(mod_cml_set_defaults) {
18429         plugin_data *p = p_d;
18430         size_t i = 0;
18431 -       
18432 -       config_values_t cv[] = { 
18433 +
18434 +       config_values_t cv[] = {
18435                 { "cml.extension",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
18436                 { "cml.memcache-hosts",         NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },        /* 1 */
18437                 { "cml.memcache-namespace",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
18438                 { "cml.power-magnet",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
18439                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
18440         };
18441 -       
18442 +
18443         if (!p) return HANDLER_ERROR;
18444 -       
18445 +
18446         p->config_storage = malloc(srv->config_context->used * sizeof(specific_config *));
18447 -       
18448 +
18449         for (i = 0; i < srv->config_context->used; i++) {
18450                 plugin_config *s;
18451 -               
18452 +
18453                 s = malloc(sizeof(plugin_config));
18454                 s->ext    = buffer_init();
18455                 s->mc_hosts       = array_init();
18456 @@ -96,87 +95,84 @@
18457  #if defined(HAVE_MEMCACHE_H)
18458                 s->mc = NULL;
18459  #endif
18460 -               
18461 +
18462                 cv[0].destination = s->ext;
18463                 cv[1].destination = s->mc_hosts;
18464                 cv[2].destination = s->mc_namespace;
18465                 cv[3].destination = s->power_magnet;
18466 -               
18467 +
18468                 p->config_storage[i] = s;
18469 -       
18470 +
18471                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
18472                         return HANDLER_ERROR;
18473                 }
18474 -               
18475 +
18476                 if (s->mc_hosts->used) {
18477  #if defined(HAVE_MEMCACHE_H)
18478                         size_t k;
18479                         s->mc = mc_new();
18480 -               
18481 +
18482                         for (k = 0; k < s->mc_hosts->used; k++) {
18483                                 data_string *ds = (data_string *)s->mc_hosts->data[k];
18484 -                               
18485 +
18486                                 if (0 != mc_server_add4(s->mc, ds->value->ptr)) {
18487 -                                       log_error_write(srv, __FILE__, __LINE__, "sb", 
18488 -                                                       "connection to host failed:", 
18489 +                                       log_error_write(srv, __FILE__, __LINE__, "sb",
18490 +                                                       "connection to host failed:",
18491                                                         ds->value);
18492 -                                       
18493 +
18494                                         return HANDLER_ERROR;
18495                                 }
18496                         }
18497  #else
18498 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
18499 +                       log_error_write(srv, __FILE__, __LINE__, "s",
18500                                         "memcache support is not compiled in but cml.memcache-hosts is set, aborting");
18501                         return HANDLER_ERROR;
18502  #endif
18503                 }
18504         }
18505 -       
18506 +
18507         return HANDLER_GO_ON;
18508  }
18509  
18510 -#define PATCH(x) \
18511 -       p->conf.x = s->x;
18512  static int mod_cml_patch_connection(server *srv, connection *con, plugin_data *p) {
18513         size_t i, j;
18514         plugin_config *s = p->config_storage[0];
18515 -       
18516 -       PATCH(ext);
18517 +
18518 +       PATCH_OPTION(ext);
18519  #if defined(HAVE_MEMCACHE_H)
18520 -       PATCH(mc);
18521 +       PATCH_OPTION(mc);
18522  #endif
18523 -       PATCH(mc_namespace);
18524 -       PATCH(power_magnet);
18525 -       
18526 +       PATCH_OPTION(mc_namespace);
18527 +       PATCH_OPTION(power_magnet);
18528 +
18529         /* skip the first, the global context */
18530         for (i = 1; i < srv->config_context->used; i++) {
18531                 data_config *dc = (data_config *)srv->config_context->data[i];
18532                 s = p->config_storage[i];
18533 -               
18534 +
18535                 /* condition didn't match */
18536                 if (!config_check_cond(srv, con, dc)) continue;
18537 -               
18538 +
18539                 /* merge config */
18540                 for (j = 0; j < dc->value->used; j++) {
18541                         data_unset *du = dc->value->data[j];
18542 -                       
18543 +
18544                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.extension"))) {
18545 -                               PATCH(ext);
18546 +                               PATCH_OPTION(ext);
18547                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-hosts"))) {
18548  #if defined(HAVE_MEMCACHE_H)
18549 -                               PATCH(mc);
18550 +                               PATCH_OPTION(mc);
18551  #endif
18552                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-namespace"))) {
18553 -                               PATCH(mc_namespace);
18554 +                               PATCH_OPTION(mc_namespace);
18555                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.power-magnet"))) {
18556 -                               PATCH(power_magnet);
18557 +                               PATCH_OPTION(power_magnet);
18558                         }
18559                 }
18560         }
18561 -       
18562 +
18563         return 0;
18564  }
18565 -#undef PATCH
18566  
18567  int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *cml_file) {
18568         buffer *b;
18569 @@ -187,57 +183,57 @@
18570         b = p->baseurl;
18571         buffer_copy_string_buffer(b, con->uri.path);
18572         for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
18573 -       
18574 +
18575         if (*c == '/') {
18576                 b->used = c - b->ptr + 2;
18577                 *(c+1) = '\0';
18578         }
18579 -       
18580 +
18581         b = p->basedir;
18582         buffer_copy_string_buffer(b, con->physical.path);
18583         for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
18584 -       
18585 +
18586         if (*c == '/') {
18587                 b->used = c - b->ptr + 2;
18588                 *(c+1) = '\0';
18589         }
18590 -       
18591 +
18592  
18593         /* prepare variables
18594          *   - cookie-based
18595          *   - get-param-based
18596          */
18597 -       
18598 +
18599         return cache_parse_lua(srv, con, p, cml_file);
18600 -       
18601 +
18602  }
18603  
18604  URIHANDLER_FUNC(mod_cml_power_magnet) {
18605         plugin_data *p = p_d;
18606 -       
18607 +
18608         mod_cml_patch_connection(srv, con, p);
18609 -       
18610 +
18611         buffer_reset(p->basedir);
18612         buffer_reset(p->baseurl);
18613         buffer_reset(p->trigger_handler);
18614  
18615         if (buffer_is_empty(p->conf.power_magnet)) return HANDLER_GO_ON;
18616 -       
18617 -       /* 
18618 +
18619 +       /*
18620          * power-magnet:
18621          * cml.power-magnet = server.docroot + "/rewrite.cml"
18622          *
18623          * is called on EACH request, take the original REQUEST_URI and modifies the
18624 -        * request header as neccesary. 
18625 +        * request header as neccesary.
18626          *
18627          * First use:
18628          * if file_exists("/maintainance.html") {
18629          *   output_include = ( "/maintainance.html" )
18630 -        *   return CACHE_HIT 
18631 +        *   return CACHE_HIT
18632          * }
18633          *
18634          * as we only want to rewrite HTML like requests we should cover it in a conditional
18635 -        * 
18636 +        *
18637          * */
18638  
18639         switch(cache_call_lua(srv, con, p, p->conf.power_magnet)) {
18640 @@ -266,20 +262,20 @@
18641  
18642  URIHANDLER_FUNC(mod_cml_is_handled) {
18643         plugin_data *p = p_d;
18644 -       
18645 +
18646         if (buffer_is_empty(con->physical.path)) return HANDLER_ERROR;
18647 -       
18648 +
18649         mod_cml_patch_connection(srv, con, p);
18650 -       
18651 +
18652         buffer_reset(p->basedir);
18653         buffer_reset(p->baseurl);
18654         buffer_reset(p->trigger_handler);
18655  
18656         if (buffer_is_empty(p->conf.ext)) return HANDLER_GO_ON;
18657 -       
18658 +
18659         if (!buffer_is_equal_right_len(con->physical.path, p->conf.ext, p->conf.ext->used - 1)) {
18660                 return HANDLER_GO_ON;
18661 -       } 
18662 +       }
18663  
18664         switch(cache_call_lua(srv, con, p, con->physical.path)) {
18665         case -1:
18666 @@ -311,15 +307,15 @@
18667  int mod_cml_plugin_init(plugin *p) {
18668         p->version     = LIGHTTPD_VERSION_ID;
18669         p->name        = buffer_init_string("cache");
18670 -       
18671 +
18672         p->init        = mod_cml_init;
18673         p->cleanup     = mod_cml_free;
18674         p->set_defaults  = mod_cml_set_defaults;
18675 -       
18676 +
18677         p->handle_subrequest_start = mod_cml_is_handled;
18678         p->handle_physical         = mod_cml_power_magnet;
18679 -       
18680 +
18681         p->data        = NULL;
18682 -       
18683 +
18684         return 0;
18685  }
18686 --- ../lighttpd-1.4.11/src/mod_cml.h    2006-01-30 13:51:35.000000000 +0200
18687 +++ lighttpd-1.4.12/src/mod_cml.h       2006-07-16 00:26:03.000000000 +0300
18688 @@ -16,10 +16,10 @@
18689  
18690  typedef struct {
18691         buffer *ext;
18692 -       
18693 +
18694         array  *mc_hosts;
18695         buffer *mc_namespace;
18696 -#if defined(HAVE_MEMCACHE_H) 
18697 +#if defined(HAVE_MEMCACHE_H)
18698         struct memcache *mc;
18699  #endif
18700         buffer *power_magnet;
18701 @@ -27,15 +27,15 @@
18702  
18703  typedef struct {
18704         PLUGIN_DATA;
18705 -       
18706 +
18707         buffer *basedir;
18708         buffer *baseurl;
18709 -       
18710 +
18711         buffer *trigger_handler;
18712 -       
18713 +
18714         plugin_config **config_storage;
18715 -       
18716 -       plugin_config conf; 
18717 +
18718 +       plugin_config conf;
18719  } plugin_data;
18720  
18721  int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn);
18722 --- ../lighttpd-1.4.11/src/mod_cml_funcs.c      2005-11-17 16:15:08.000000000 +0200
18723 +++ lighttpd-1.4.12/src/mod_cml_funcs.c 2006-07-16 00:26:04.000000000 +0300
18724 @@ -4,8 +4,7 @@
18725  #include <stdlib.h>
18726  #include <string.h>
18727  #include <errno.h>
18728 -#include <unistd.h>
18729 -#include <dirent.h>
18730 +
18731  #include <stdio.h>
18732  
18733  #include "buffer.h"
18734 @@ -13,6 +12,7 @@
18735  #include "log.h"
18736  #include "plugin.h"
18737  #include "response.h"
18738 +#include "sys-files.h"
18739  
18740  #include "mod_cml.h"
18741  #include "mod_cml_funcs.h"
18742 @@ -30,7 +30,7 @@
18743  #ifdef USE_OPENSSL
18744  #define IN const
18745  #else
18746 -#define IN 
18747 +#define IN
18748  #endif
18749  #define OUT
18750  
18751 @@ -42,29 +42,29 @@
18752         buffer b;
18753         char hex[33];
18754         int n = lua_gettop(L);
18755 -       
18756 +
18757         b.ptr = hex;
18758         b.used = 0;
18759         b.size = sizeof(hex);
18760 -       
18761 +
18762         if (n != 1) {
18763                 lua_pushstring(L, "md5: expected one argument");
18764                 lua_error(L);
18765         }
18766 -       
18767 +
18768         if (!lua_isstring(L, 1)) {
18769                 lua_pushstring(L, "md5: argument has to be a string");
18770                 lua_error(L);
18771         }
18772 -       
18773 +
18774         MD5_Init(&Md5Ctx);
18775         MD5_Update(&Md5Ctx, (unsigned char *)lua_tostring(L, 1), lua_strlen(L, 1));
18776         MD5_Final(HA1, &Md5Ctx);
18777 -       
18778 +
18779         buffer_copy_string_hex(&b, (char *)HA1, 16);
18780 -       
18781 +
18782         lua_pushstring(L, b.ptr);
18783 -       
18784 +
18785         return 1;
18786  }
18787  
18788 @@ -72,37 +72,37 @@
18789  int f_file_mtime(lua_State *L) {
18790         struct stat st;
18791         int n = lua_gettop(L);
18792 -       
18793 +
18794         if (n != 1) {
18795                 lua_pushstring(L, "file_mtime: expected one argument");
18796                 lua_error(L);
18797         }
18798 -       
18799 +
18800         if (!lua_isstring(L, 1)) {
18801                 lua_pushstring(L, "file_mtime: argument has to be a string");
18802                 lua_error(L);
18803         }
18804 -       
18805 +
18806         if (-1 == stat(lua_tostring(L, 1), &st)) {
18807                 lua_pushnil(L);
18808                 return 1;
18809         }
18810 -       
18811 +
18812         lua_pushnumber(L, st.st_mtime);
18813 -       
18814 +
18815         return 1;
18816  }
18817 -
18818 +#ifndef _WIN32
18819  int f_dir_files_iter(lua_State *L) {
18820         DIR *d;
18821         struct dirent *de;
18822 -       
18823 +
18824         d = lua_touserdata(L, lua_upvalueindex(1));
18825 -       
18826 +
18827         if (NULL == (de = readdir(d))) {
18828                 /* EOF */
18829                 closedir(d);
18830 -               
18831 +
18832                 return 0;
18833         } else {
18834                 lua_pushstring(L, de->d_name);
18835 @@ -113,75 +113,75 @@
18836  int f_dir_files(lua_State *L) {
18837         DIR *d;
18838         int n = lua_gettop(L);
18839 -       
18840 +
18841         if (n != 1) {
18842                 lua_pushstring(L, "dir_files: expected one argument");
18843                 lua_error(L);
18844         }
18845 -       
18846 +
18847         if (!lua_isstring(L, 1)) {
18848                 lua_pushstring(L, "dir_files: argument has to be a string");
18849                 lua_error(L);
18850         }
18851 -       
18852 -       /* check if there is a valid DIR handle on the stack */ 
18853 +
18854 +       /* check if there is a valid DIR handle on the stack */
18855         if (NULL == (d = opendir(lua_tostring(L, 1)))) {
18856                 lua_pushnil(L);
18857                 return 1;
18858         }
18859 -       
18860 +
18861         /* push d into registry */
18862         lua_pushlightuserdata(L, d);
18863         lua_pushcclosure(L, f_dir_files_iter, 1);
18864 -       
18865 +
18866         return 1;
18867  }
18868 -
18869 +#endif
18870  int f_file_isreg(lua_State *L) {
18871         struct stat st;
18872         int n = lua_gettop(L);
18873 -       
18874 +
18875         if (n != 1) {
18876                 lua_pushstring(L, "file_isreg: expected one argument");
18877                 lua_error(L);
18878         }
18879 -       
18880 +
18881         if (!lua_isstring(L, 1)) {
18882                 lua_pushstring(L, "file_isreg: argument has to be a string");
18883                 lua_error(L);
18884         }
18885 -       
18886 +
18887         if (-1 == stat(lua_tostring(L, 1), &st)) {
18888                 lua_pushnil(L);
18889                 return 1;
18890         }
18891 -       
18892 +
18893         lua_pushnumber(L, S_ISREG(st.st_mode));
18894 -       
18895 +
18896         return 1;
18897  }
18898  
18899  int f_file_isdir(lua_State *L) {
18900         struct stat st;
18901         int n = lua_gettop(L);
18902 -       
18903 +
18904         if (n != 1) {
18905                 lua_pushstring(L, "file_isreg: expected one argument");
18906                 lua_error(L);
18907         }
18908 -       
18909 +
18910         if (!lua_isstring(L, 1)) {
18911                 lua_pushstring(L, "file_isreg: argument has to be a string");
18912                 lua_error(L);
18913         }
18914 -       
18915 +
18916         if (-1 == stat(lua_tostring(L, 1), &st)) {
18917                 lua_pushnil(L);
18918                 return 1;
18919         }
18920 -       
18921 +
18922         lua_pushnumber(L, S_ISDIR(st.st_mode));
18923 -       
18924 +
18925         return 1;
18926  }
18927  
18928 @@ -192,33 +192,33 @@
18929         char *r;
18930         int n = lua_gettop(L);
18931         struct memcache *mc;
18932 -       
18933 +
18934         if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
18935                 lua_pushstring(L, "where is my userdata ?");
18936                 lua_error(L);
18937         }
18938 -       
18939 +
18940         mc = lua_touserdata(L, lua_upvalueindex(1));
18941 -       
18942 +
18943         if (n != 1) {
18944                 lua_pushstring(L, "expected one argument");
18945                 lua_error(L);
18946         }
18947 -       
18948 +
18949         if (!lua_isstring(L, 1)) {
18950                 lua_pushstring(L, "argument has to be a string");
18951                 lua_error(L);
18952         }
18953 -       
18954 -       if (NULL == (r = mc_aget(mc, 
18955 +
18956 +       if (NULL == (r = mc_aget(mc,
18957                                  lua_tostring(L, 1), lua_strlen(L, 1)))) {
18958 -                               
18959 +
18960                 lua_pushboolean(L, 0);
18961                 return 1;
18962         }
18963 -       
18964 +
18965         free(r);
18966 -       
18967 +
18968         lua_pushboolean(L, 1);
18969         return 1;
18970  }
18971 @@ -226,74 +226,74 @@
18972  int f_memcache_get_string(lua_State *L) {
18973         char *r;
18974         int n = lua_gettop(L);
18975 -       
18976 +
18977         struct memcache *mc;
18978 -       
18979 +
18980         if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
18981                 lua_pushstring(L, "where is my userdata ?");
18982                 lua_error(L);
18983         }
18984 -       
18985 +
18986         mc = lua_touserdata(L, lua_upvalueindex(1));
18987 -       
18988 -       
18989 +
18990 +
18991         if (n != 1) {
18992                 lua_pushstring(L, "expected one argument");
18993                 lua_error(L);
18994         }
18995 -       
18996 +
18997         if (!lua_isstring(L, 1)) {
18998                 lua_pushstring(L, "argument has to be a string");
18999                 lua_error(L);
19000         }
19001 -       
19002 -       if (NULL == (r = mc_aget(mc, 
19003 +
19004 +       if (NULL == (r = mc_aget(mc,
19005                                  lua_tostring(L, 1), lua_strlen(L, 1)))) {
19006                 lua_pushnil(L);
19007                 return 1;
19008         }
19009 -       
19010 +
19011         lua_pushstring(L, r);
19012 -       
19013 +
19014         free(r);
19015 -       
19016 +
19017         return 1;
19018  }
19019  
19020  int f_memcache_get_long(lua_State *L) {
19021         char *r;
19022         int n = lua_gettop(L);
19023 -       
19024 +
19025         struct memcache *mc;
19026 -       
19027 +
19028         if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
19029                 lua_pushstring(L, "where is my userdata ?");
19030                 lua_error(L);
19031         }
19032 -       
19033 +
19034         mc = lua_touserdata(L, lua_upvalueindex(1));
19035 -       
19036 -       
19037 +
19038 +
19039         if (n != 1) {
19040                 lua_pushstring(L, "expected one argument");
19041                 lua_error(L);
19042         }
19043 -       
19044 +
19045         if (!lua_isstring(L, 1)) {
19046                 lua_pushstring(L, "argument has to be a string");
19047                 lua_error(L);
19048         }
19049 -       
19050 -       if (NULL == (r = mc_aget(mc, 
19051 +
19052 +       if (NULL == (r = mc_aget(mc,
19053                                  lua_tostring(L, 1), lua_strlen(L, 1)))) {
19054                 lua_pushnil(L);
19055                 return 1;
19056         }
19057 -       
19058 +
19059         lua_pushnumber(L, strtol(r, NULL, 10));
19060 -       
19061 +
19062         free(r);
19063 -       
19064 +
19065         return 1;
19066  }
19067  #endif
19068 --- ../lighttpd-1.4.11/src/mod_cml_lua.c        2006-01-30 13:56:40.000000000 +0200
19069 +++ lighttpd-1.4.12/src/mod_cml_lua.c   2006-07-16 00:26:04.000000000 +0300
19070 @@ -23,7 +23,7 @@
19071  #ifdef USE_OPENSSL
19072  #define IN const
19073  #else
19074 -#define IN 
19075 +#define IN
19076  #endif
19077  #define OUT
19078  
19079 @@ -31,6 +31,7 @@
19080  
19081  #include <lua.h>
19082  #include <lualib.h>
19083 +#include <lauxlib.h>
19084  
19085  typedef struct {
19086         stream st;
19087 @@ -39,11 +40,11 @@
19088  
19089  static const char * load_file(lua_State *L, void *data, size_t *size) {
19090         readme *rm = data;
19091 -       
19092 +
19093         UNUSED(L);
19094 -       
19095 +
19096         if (rm->done) return 0;
19097 -       
19098 +
19099         *size = rm->st.size;
19100         rm->done = 1;
19101         return rm->st.start;
19102 @@ -51,47 +52,47 @@
19103  
19104  static int lua_to_c_get_string(lua_State *L, const char *varname, buffer *b) {
19105         int curelem;
19106 -       
19107 +
19108         lua_pushstring(L, varname);
19109 -       
19110 +
19111         curelem = lua_gettop(L);
19112         lua_gettable(L, LUA_GLOBALSINDEX);
19113 -       
19114 +
19115         /* it should be a table */
19116         if (!lua_isstring(L, curelem)) {
19117                 lua_settop(L, curelem - 1);
19118 -               
19119 +
19120                 return -1;
19121         }
19122 -       
19123 +
19124         buffer_copy_string(b, lua_tostring(L, curelem));
19125 -       
19126 +
19127         lua_pop(L, 1);
19128 -       
19129 +
19130         assert(curelem - 1 == lua_gettop(L));
19131 -       
19132 +
19133         return 0;
19134  }
19135  
19136  static int lua_to_c_is_table(lua_State *L, const char *varname) {
19137         int curelem;
19138 -       
19139 +
19140         lua_pushstring(L, varname);
19141 -       
19142 +
19143         curelem = lua_gettop(L);
19144         lua_gettable(L, LUA_GLOBALSINDEX);
19145 -       
19146 +
19147         /* it should be a table */
19148         if (!lua_istable(L, curelem)) {
19149                 lua_settop(L, curelem - 1);
19150 -               
19151 +
19152                 return 0;
19153         }
19154 -       
19155 +
19156         lua_settop(L, curelem - 1);
19157 -       
19158 +
19159         assert(curelem - 1 == lua_gettop(L));
19160 -       
19161 +
19162         return 1;
19163  }
19164  
19165 @@ -99,7 +100,7 @@
19166         lua_pushlstring(L, key, key_len);
19167         lua_pushlstring(L, val, val_len);
19168         lua_settable(L, tbl);
19169 -       
19170 +
19171         return 0;
19172  }
19173  
19174 @@ -108,21 +109,21 @@
19175         size_t is_key = 1;
19176         size_t i;
19177         char *key = NULL, *val = NULL;
19178 -       
19179 +
19180         key = qrystr->ptr;
19181 -       
19182 +
19183         /* we need the \0 */
19184         for (i = 0; i < qrystr->used; i++) {
19185                 switch(qrystr->ptr[i]) {
19186                 case '=':
19187                         if (is_key) {
19188                                 val = qrystr->ptr + i + 1;
19189 -                               
19190 +
19191                                 qrystr->ptr[i] = '\0';
19192 -                               
19193 +
19194                                 is_key = 0;
19195                         }
19196 -                       
19197 +
19198                         break;
19199                 case '&':
19200                 case '\0': /* fin symbol */
19201 @@ -131,19 +132,19 @@
19202  
19203                                 /* terminate the value */
19204                                 qrystr->ptr[i] = '\0';
19205 -                               
19206 -                               c_to_lua_push(L, tbl, 
19207 +
19208 +                               c_to_lua_push(L, tbl,
19209                                               key, strlen(key),
19210                                               val, strlen(val));
19211                         }
19212 -                       
19213 +
19214                         key = qrystr->ptr + i + 1;
19215                         val = NULL;
19216                         is_key = 1;
19217                         break;
19218                 }
19219         }
19220 -       
19221 +
19222         return 0;
19223  }
19224  #if 0
19225 @@ -151,21 +152,21 @@
19226         data_unset *d;
19227  
19228         UNUSED(srv);
19229 -       
19230 +
19231         if (NULL != (d = array_get_element(con->request.headers, "Cookie"))) {
19232                 data_string *ds = (data_string *)d;
19233                 size_t key = 0, value = 0;
19234                 size_t is_key = 1, is_sid = 0;
19235                 size_t i;
19236 -               
19237 +
19238                 /* found COOKIE */
19239                 if (!DATA_IS_STRING(d)) return -1;
19240                 if (ds->value->used == 0) return -1;
19241 -                       
19242 +
19243                 if (ds->value->ptr[0] == '\0' ||
19244                     ds->value->ptr[0] == '=' ||
19245                     ds->value->ptr[0] == ';') return -1;
19246 -               
19247 +
19248                 buffer_reset(p->session_id);
19249                 for (i = 0; i < ds->value->used; i++) {
19250                         switch(ds->value->ptr[i]) {
19251 @@ -176,16 +177,16 @@
19252                                                 is_sid = 1;
19253                                         }
19254                                         value = i + 1;
19255 -                               
19256 +
19257                                         is_key = 0;
19258                                 }
19259 -                               
19260 +
19261                                 break;
19262                         case ';':
19263                                 if (is_sid) {
19264                                         buffer_copy_string_len(p->session_id, ds->value->ptr + value, i - value);
19265                                 }
19266 -                               
19267 +
19268                                 is_sid = 0;
19269                                 key = i + 1;
19270                                 value = 0;
19271 @@ -204,48 +205,43 @@
19272                         }
19273                 }
19274         }
19275 -       
19276 +
19277         return 0;
19278  }
19279  #endif
19280  
19281  int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
19282 -       lua_State *L; 
19283 +       lua_State *L;
19284         readme rm;
19285         int ret = -1;
19286         buffer *b = buffer_init();
19287         int header_tbl = 0;
19288 -       
19289 +
19290         rm.done = 0;
19291         stream_open(&rm.st, fn);
19292 -       
19293 +
19294         /* push the lua file to the interpreter and see what happends */
19295 -       L = lua_open();
19296 -       
19297 -       luaopen_base(L);
19298 -       luaopen_table(L);
19299 -       luaopen_string(L);
19300 -       luaopen_math(L);
19301 -       luaopen_io(L);
19302 -       
19303 +       L = luaL_newstate();
19304 +       luaL_openlibs(L);
19305 +
19306         /* register functions */
19307         lua_register(L, "md5", f_crypto_md5);
19308         lua_register(L, "file_mtime", f_file_mtime);
19309         lua_register(L, "file_isreg", f_file_isreg);
19310         lua_register(L, "file_isdir", f_file_isreg);
19311         lua_register(L, "dir_files", f_dir_files);
19312 -       
19313 +
19314  #ifdef HAVE_MEMCACHE_H
19315         lua_pushliteral(L, "memcache_get_long");
19316         lua_pushlightuserdata(L, p->conf.mc);
19317         lua_pushcclosure(L, f_memcache_get_long, 1);
19318         lua_settable(L, LUA_GLOBALSINDEX);
19319 -       
19320 +
19321         lua_pushliteral(L, "memcache_get_string");
19322         lua_pushlightuserdata(L, p->conf.mc);
19323         lua_pushcclosure(L, f_memcache_get_string, 1);
19324         lua_settable(L, LUA_GLOBALSINDEX);
19325 -       
19326 +
19327         lua_pushliteral(L, "memcache_exists");
19328         lua_pushlightuserdata(L, p->conf.mc);
19329         lua_pushcclosure(L, f_memcache_exists, 1);
19330 @@ -255,11 +251,11 @@
19331         lua_pushliteral(L, "request");
19332         lua_newtable(L);
19333         lua_settable(L, LUA_GLOBALSINDEX);
19334 -       
19335 +
19336         lua_pushliteral(L, "request");
19337         header_tbl = lua_gettop(L);
19338         lua_gettable(L, LUA_GLOBALSINDEX);
19339 -       
19340 +
19341         c_to_lua_push(L, header_tbl, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
19342         c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
19343         c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
19344 @@ -267,84 +263,84 @@
19345         if (!buffer_is_empty(con->request.pathinfo)) {
19346                 c_to_lua_push(L, header_tbl, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
19347         }
19348 -       
19349 +
19350         c_to_lua_push(L, header_tbl, CONST_STR_LEN("CWD"), CONST_BUF_LEN(p->basedir));
19351         c_to_lua_push(L, header_tbl, CONST_STR_LEN("BASEURL"), CONST_BUF_LEN(p->baseurl));
19352 -       
19353 +
19354         /* register GET parameter */
19355         lua_pushliteral(L, "get");
19356         lua_newtable(L);
19357         lua_settable(L, LUA_GLOBALSINDEX);
19358 -       
19359 +
19360         lua_pushliteral(L, "get");
19361         header_tbl = lua_gettop(L);
19362         lua_gettable(L, LUA_GLOBALSINDEX);
19363 -       
19364 +
19365         buffer_copy_string_buffer(b, con->uri.query);
19366         cache_export_get_params(L, header_tbl, b);
19367         buffer_reset(b);
19368  
19369 -       /* 2 default constants */       
19370 +       /* 2 default constants */
19371         lua_pushliteral(L, "CACHE_HIT");
19372         lua_pushboolean(L, 0);
19373         lua_settable(L, LUA_GLOBALSINDEX);
19374 -       
19375 +
19376         lua_pushliteral(L, "CACHE_MISS");
19377         lua_pushboolean(L, 1);
19378         lua_settable(L, LUA_GLOBALSINDEX);
19379 -       
19380 +
19381         /* load lua program */
19382         if (lua_load(L, load_file, &rm, fn->ptr) || lua_pcall(L,0,1,0)) {
19383                 log_error_write(srv, __FILE__, __LINE__, "s",
19384                                 lua_tostring(L,-1));
19385 -               
19386 +
19387                 goto error;
19388         }
19389 -       
19390 +
19391         /* get return value */
19392         ret = (int)lua_tonumber(L, -1);
19393         lua_pop(L, 1);
19394 -       
19395 -       /* fetch the data from lua */ 
19396 +
19397 +       /* fetch the data from lua */
19398         lua_to_c_get_string(L, "trigger_handler", p->trigger_handler);
19399 -       
19400 +
19401         if (0 == lua_to_c_get_string(L, "output_contenttype", b)) {
19402                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(b));
19403         }
19404 -       
19405 +
19406         if (ret == 0) {
19407                 /* up to now it is a cache-hit, check if all files exist */
19408 -               
19409 +
19410                 int curelem;
19411                 time_t mtime = 0;
19412 -       
19413 +
19414                 if (!lua_to_c_is_table(L, "output_include")) {
19415                         log_error_write(srv, __FILE__, __LINE__, "s",
19416                                 "output_include is missing or not a table");
19417                         ret = -1;
19418 -               
19419 +
19420                         goto error;
19421                 }
19422 -               
19423 +
19424                 lua_pushstring(L, "output_include");
19425 -               
19426 +
19427                 curelem = lua_gettop(L);
19428                 lua_gettable(L, LUA_GLOBALSINDEX);
19429  
19430                 /* HOW-TO build a etag ?
19431 -                * as we don't just have one file we have to take the stat() 
19432 +                * as we don't just have one file we have to take the stat()
19433                  * from all base files, merge them and build the etag from
19434                  * it later.
19435 -                * 
19436 +                *
19437                  * The mtime of the content is the mtime of the freshest base file
19438 -                * 
19439 +                *
19440                  * */
19441 -               
19442 +
19443                 lua_pushnil(L);  /* first key */
19444                 while (lua_next(L, curelem) != 0) {
19445                         stat_cache_entry *sce = NULL;
19446                         /* key' is at index -2 and value' at index -1 */
19447 -                       
19448 +
19449                         if (lua_isstring(L, -1)) {
19450                                 const char *s = lua_tostring(L, -1);
19451  
19452 @@ -364,18 +360,18 @@
19453                                                 /* a file is missing, call the handler to generate it */
19454                                                 if (!buffer_is_empty(p->trigger_handler)) {
19455                                                         ret = 1; /* cache-miss */
19456 -                                                       
19457 +
19458                                                         log_error_write(srv, __FILE__, __LINE__, "s",
19459                                                                         "a file is missing, calling handler");
19460 -                                                       
19461 +
19462                                                         break;
19463                                                 } else {
19464                                                         /* handler not set -> 500 */
19465                                                         ret = -1;
19466 -                                                       
19467 +
19468                                                         log_error_write(srv, __FILE__, __LINE__, "s",
19469                                                                         "a file missing and no handler set");
19470 -                                                       
19471 +
19472                                                         break;
19473                                                 }
19474                                                 break;
19475 @@ -393,12 +389,12 @@
19476                                                 "not a string");
19477                                 break;
19478                         }
19479 -               
19480 +
19481                         lua_pop(L, 1);  /* removes value'; keeps key' for next iteration */
19482                 }
19483 -               
19484 +
19485                 lua_settop(L, curelem - 1);
19486 -               
19487 +
19488                 if (ret == 0) {
19489                         data_string *ds;
19490                         char timebuf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
19491 @@ -410,9 +406,9 @@
19492  
19493                         /* no Last-Modified specified */
19494                         if ((mtime) && (NULL == ds)) {
19495 -               
19496 +
19497                                 strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&mtime));
19498 -                               
19499 +
19500                                 response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), timebuf, sizeof(timebuf) - 1);
19501  
19502  
19503 @@ -428,9 +424,9 @@
19504                                 tbuf.used = 0;
19505                                 tbuf.ptr = NULL;
19506                         }
19507 -                       
19508 +
19509                         if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, &tbuf)) {
19510 -                               /* ok, the client already has our content, 
19511 +                               /* ok, the client already has our content,
19512                                  * no need to send it again */
19513  
19514                                 chunkqueue_reset(con->write_queue);
19515 @@ -440,24 +436,24 @@
19516                         chunkqueue_reset(con->write_queue);
19517                 }
19518         }
19519 -       
19520 +
19521         if (ret == 1 && !buffer_is_empty(p->trigger_handler)) {
19522                 /* cache-miss */
19523                 buffer_copy_string_buffer(con->uri.path, p->baseurl);
19524                 buffer_append_string_buffer(con->uri.path, p->trigger_handler);
19525 -       
19526 +
19527                 buffer_copy_string_buffer(con->physical.path, p->basedir);
19528                 buffer_append_string_buffer(con->physical.path, p->trigger_handler);
19529 -               
19530 +
19531                 chunkqueue_reset(con->write_queue);
19532         }
19533 -       
19534 +
19535  error:
19536         lua_close(L);
19537 -       
19538 +
19539         stream_close(&rm.st);
19540         buffer_free(b);
19541 -       
19542 +
19543         return ret /* cache-error */;
19544  }
19545  #else
19546 --- ../lighttpd-1.4.11/src/mod_compress.c       2005-11-18 13:49:14.000000000 +0200
19547 +++ lighttpd-1.4.12/src/mod_compress.c  2006-07-16 00:26:04.000000000 +0300
19548 @@ -2,7 +2,6 @@
19549  #include <sys/stat.h>
19550  
19551  #include <fcntl.h>
19552 -#include <unistd.h>
19553  #include <ctype.h>
19554  #include <stdlib.h>
19555  #include <string.h>
19556 @@ -14,6 +13,7 @@
19557  #include "buffer.h"
19558  #include "response.h"
19559  #include "stat_cache.h"
19560 +#include "http_chunk.h"
19561  
19562  #include "plugin.h"
19563  
19564 @@ -33,6 +33,7 @@
19565  #endif
19566  
19567  #include "sys-mmap.h"
19568 +#include "sys-files.h"
19569  
19570  /* request: accept-encoding */
19571  #define HTTP_ACCEPT_ENCODING_IDENTITY BV(0)
19572 @@ -55,97 +56,127 @@
19573         PLUGIN_DATA;
19574         buffer *ofn;
19575         buffer *b;
19576 -       
19577 +
19578         plugin_config **config_storage;
19579 -       plugin_config conf; 
19580 +       plugin_config conf;
19581  } plugin_data;
19582  
19583  INIT_FUNC(mod_compress_init) {
19584         plugin_data *p;
19585 -       
19586 +
19587         p = calloc(1, sizeof(*p));
19588 -       
19589 +
19590         p->ofn = buffer_init();
19591         p->b = buffer_init();
19592 -       
19593 +
19594         return p;
19595  }
19596  
19597  FREE_FUNC(mod_compress_free) {
19598         plugin_data *p = p_d;
19599 -       
19600 +
19601         UNUSED(srv);
19602  
19603         if (!p) return HANDLER_GO_ON;
19604 -       
19605 +
19606         buffer_free(p->ofn);
19607         buffer_free(p->b);
19608 -       
19609 +
19610         if (p->config_storage) {
19611                 size_t i;
19612                 for (i = 0; i < srv->config_context->used; i++) {
19613                         plugin_config *s = p->config_storage[i];
19614  
19615                         if (!s) continue;
19616 -                       
19617 +
19618                         array_free(s->compress);
19619                         buffer_free(s->compress_cache_dir);
19620 -                       
19621 +
19622                         free(s);
19623                 }
19624                 free(p->config_storage);
19625         }
19626 -       
19627 -       
19628 +
19629 +
19630         free(p);
19631 -       
19632 +
19633         return HANDLER_GO_ON;
19634  }
19635  
19636 +void mkdir_recursive(const char *dir) {
19637 +
19638 +       char dir_copy[256];
19639 +       char *p = dir_copy;
19640 +
19641 +       if (!dir || !dir[0])
19642 +               return;
19643 +
19644 +       strncpy(dir_copy, dir, sizeof(dir_copy) / sizeof(dir_copy[0]));
19645 +
19646 +       while ((p = strchr(p + 1, '/')) != NULL) {
19647 +
19648 +               *p = '\0';
19649 +               if ((mkdir(dir_copy, 0700) != 0) && (errno != EEXIST))
19650 +                       return;
19651 +
19652 +               *p++ = '/';
19653 +       }
19654 +
19655 +       mkdir(dir, 0700);
19656 +}
19657 +
19658  SETDEFAULTS_FUNC(mod_compress_setdefaults) {
19659         plugin_data *p = p_d;
19660         size_t i = 0;
19661 -       
19662 -       config_values_t cv[] = { 
19663 +
19664 +       config_values_t cv[] = {
19665                 { "compress.cache-dir",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
19666                 { "compress.filetype",              NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
19667                 { "compress.max-filesize",          NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
19668                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
19669         };
19670 -       
19671 +
19672         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
19673 -       
19674 +
19675         for (i = 0; i < srv->config_context->used; i++) {
19676                 plugin_config *s;
19677 -               
19678 +
19679                 s = calloc(1, sizeof(plugin_config));
19680                 s->compress_cache_dir = buffer_init();
19681                 s->compress = array_init();
19682                 s->compress_max_filesize = 0;
19683 -               
19684 +
19685                 cv[0].destination = s->compress_cache_dir;
19686                 cv[1].destination = s->compress;
19687                 cv[2].destination = &(s->compress_max_filesize);
19688 -               
19689 +
19690                 p->config_storage[i] = s;
19691 -       
19692 +
19693                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
19694                         return HANDLER_ERROR;
19695                 }
19696 -               
19697 +
19698                 if (!buffer_is_empty(s->compress_cache_dir)) {
19699                         struct stat st;
19700                         if (0 != stat(s->compress_cache_dir->ptr, &st)) {
19701 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir", 
19702 +
19703 +                               log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir, attempting to create",
19704                                                 s->compress_cache_dir, strerror(errno));
19705 -                               
19706 -                               return HANDLER_ERROR;
19707 +                               mkdir_recursive(s->compress_cache_dir->ptr);
19708 +
19709 +                               if (0 != stat(s->compress_cache_dir->ptr, &st)) {
19710 +
19711 +                                       log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir, create failed",
19712 +                                                                       s->compress_cache_dir, strerror(errno));
19713 +
19714 +                                       return HANDLER_ERROR;
19715 +                               }
19716                         }
19717                 }
19718         }
19719 -       
19720 +
19721         return HANDLER_GO_ON;
19722 -       
19723 +
19724  }
19725  
19726  #ifdef USE_ZLIB
19727 @@ -153,32 +184,32 @@
19728         unsigned char *c;
19729         unsigned long crc;
19730         z_stream z;
19731 -       
19732 +
19733         UNUSED(srv);
19734         UNUSED(con);
19735  
19736         z.zalloc = Z_NULL;
19737         z.zfree = Z_NULL;
19738         z.opaque = Z_NULL;
19739 -       
19740 -       if (Z_OK != deflateInit2(&z, 
19741 +
19742 +       if (Z_OK != deflateInit2(&z,
19743                                  Z_DEFAULT_COMPRESSION,
19744 -                                Z_DEFLATED, 
19745 +                                Z_DEFLATED,
19746                                  -MAX_WBITS,  /* supress zlib-header */
19747                                  8,
19748                                  Z_DEFAULT_STRATEGY)) {
19749                 return -1;
19750         }
19751 -               
19752 +
19753         z.next_in = (unsigned char *)start;
19754         z.avail_in = st_size;
19755         z.total_in = 0;
19756 -               
19757 -                       
19758 +
19759 +
19760         buffer_prepare_copy(p->b, (z.avail_in * 1.1) + 12 + 18);
19761 -               
19762 +
19763         /* write gzip header */
19764 -               
19765 +
19766         c = (unsigned char *)p->b->ptr;
19767         c[0] = 0x1f;
19768         c[1] = 0x8b;
19769 @@ -190,24 +221,24 @@
19770         c[7] = (mtime >> 24) & 0xff;
19771         c[8] = 0x00; /* extra flags */
19772         c[9] = 0x03; /* UNIX */
19773 -       
19774 +
19775         p->b->used = 10;
19776         z.next_out = (unsigned char *)p->b->ptr + p->b->used;
19777         z.avail_out = p->b->size - p->b->used - 8;
19778         z.total_out = 0;
19779 -       
19780 +
19781         if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
19782                 deflateEnd(&z);
19783                 return -1;
19784         }
19785 -       
19786 +
19787         /* trailer */
19788         p->b->used += z.total_out;
19789 -       
19790 +
19791         crc = generate_crc32c(start, st_size);
19792 -               
19793 +
19794         c = (unsigned char *)p->b->ptr + p->b->used;
19795 -               
19796 +
19797         c[0] = (crc >>  0) & 0xff;
19798         c[1] = (crc >>  8) & 0xff;
19799         c[2] = (crc >> 16) & 0xff;
19800 @@ -221,51 +252,51 @@
19801         if (Z_OK != deflateEnd(&z)) {
19802                 return -1;
19803         }
19804 -       
19805 +
19806         return 0;
19807  }
19808  
19809  static int deflate_file_to_buffer_deflate(server *srv, connection *con, plugin_data *p, unsigned char *start, off_t st_size) {
19810         z_stream z;
19811 -       
19812 +
19813         UNUSED(srv);
19814         UNUSED(con);
19815  
19816         z.zalloc = Z_NULL;
19817         z.zfree = Z_NULL;
19818         z.opaque = Z_NULL;
19819 -       
19820 -       if (Z_OK != deflateInit2(&z, 
19821 +
19822 +       if (Z_OK != deflateInit2(&z,
19823                                  Z_DEFAULT_COMPRESSION,
19824 -                                Z_DEFLATED, 
19825 +                                Z_DEFLATED,
19826                                  -MAX_WBITS,  /* supress zlib-header */
19827                                  8,
19828                                  Z_DEFAULT_STRATEGY)) {
19829                 return -1;
19830         }
19831 -               
19832 +
19833         z.next_in = start;
19834         z.avail_in = st_size;
19835         z.total_in = 0;
19836 -               
19837 +
19838         buffer_prepare_copy(p->b, (z.avail_in * 1.1) + 12);
19839 -       
19840 +
19841         z.next_out = (unsigned char *)p->b->ptr;
19842         z.avail_out = p->b->size;
19843         z.total_out = 0;
19844 -       
19845 +
19846         if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
19847                 deflateEnd(&z);
19848                 return -1;
19849         }
19850 -       
19851 +
19852         /* trailer */
19853         p->b->used += z.total_out;
19854 -       
19855 +
19856         if (Z_OK != deflateEnd(&z)) {
19857                 return -1;
19858         }
19859 -       
19860 +
19861         return 0;
19862  }
19863  
19864 @@ -274,48 +305,48 @@
19865  #ifdef USE_BZ2LIB
19866  static int deflate_file_to_buffer_bzip2(server *srv, connection *con, plugin_data *p, unsigned char *start, off_t st_size) {
19867         bz_stream bz;
19868 -       
19869 +
19870         UNUSED(srv);
19871         UNUSED(con);
19872  
19873         bz.bzalloc = NULL;
19874         bz.bzfree = NULL;
19875         bz.opaque = NULL;
19876 -       
19877 -       if (BZ_OK != BZ2_bzCompressInit(&bz, 
19878 +
19879 +       if (BZ_OK != BZ2_bzCompressInit(&bz,
19880                                         9, /* blocksize = 900k */
19881                                         0, /* no output */
19882                                         0)) { /* workFactor: default */
19883                 return -1;
19884         }
19885 -               
19886 +
19887         bz.next_in = (char *)start;
19888         bz.avail_in = st_size;
19889         bz.total_in_lo32 = 0;
19890         bz.total_in_hi32 = 0;
19891 -               
19892 +
19893         buffer_prepare_copy(p->b, (bz.avail_in * 1.1) + 12);
19894 -       
19895 +
19896         bz.next_out = p->b->ptr;
19897         bz.avail_out = p->b->size;
19898         bz.total_out_lo32 = 0;
19899         bz.total_out_hi32 = 0;
19900 -       
19901 +
19902         if (BZ_STREAM_END != BZ2_bzCompress(&bz, BZ_FINISH)) {
19903                 BZ2_bzCompressEnd(&bz);
19904                 return -1;
19905         }
19906 -       
19907 +
19908         /* file is too large for now */
19909         if (bz.total_out_hi32) return -1;
19910 -       
19911 +
19912         /* trailer */
19913         p->b->used = bz.total_out_lo32;
19914 -       
19915 +
19916         if (BZ_OK != BZ2_bzCompressEnd(&bz)) {
19917                 return -1;
19918         }
19919 -       
19920 +
19921         return 0;
19922  }
19923  #endif
19924 @@ -326,47 +357,50 @@
19925         void *start;
19926         const char *filename = fn->ptr;
19927         ssize_t r;
19928 -       
19929 +       stat_cache_entry *compressed_sce = NULL;
19930 +
19931 +       if (buffer_is_empty(p->conf.compress_cache_dir)) return -1;
19932 +
19933         /* overflow */
19934         if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
19935 -       
19936 -       /* don't mmap files > 128Mb 
19937 -        * 
19938 +
19939 +       /* don't mmap files > 128Mb
19940 +        *
19941          * we could use a sliding window, but currently there is no need for it
19942          */
19943 -       
19944 +
19945         if (sce->st.st_size > 128 * 1024 * 1024) return -1;
19946 -       
19947 +
19948         buffer_reset(p->ofn);
19949         buffer_copy_string_buffer(p->ofn, p->conf.compress_cache_dir);
19950 -       BUFFER_APPEND_SLASH(p->ofn);
19951 -       
19952 +       PATHNAME_APPEND_SLASH(p->ofn);
19953 +
19954         if (0 == strncmp(con->physical.path->ptr, con->physical.doc_root->ptr, con->physical.doc_root->used-1)) {
19955                 size_t offset = p->ofn->used - 1;
19956                 char *dir, *nextdir;
19957 -               
19958 +
19959                 buffer_append_string(p->ofn, con->physical.path->ptr + con->physical.doc_root->used - 1);
19960 -               
19961 +
19962                 buffer_copy_string_buffer(p->b, p->ofn);
19963 -               
19964 +
19965                 /* mkdir -p ... */
19966                 for (dir = p->b->ptr + offset; NULL != (nextdir = strchr(dir, '/')); dir = nextdir + 1) {
19967                         *nextdir = '\0';
19968 -                       
19969 +
19970                         if (-1 == mkdir(p->b->ptr, 0700)) {
19971                                 if (errno != EEXIST) {
19972                                         log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cache-directory", p->b, "failed", strerror(errno));
19973 -                                       
19974 +
19975                                         return -1;
19976                                 }
19977                         }
19978 -                       
19979 +
19980                         *nextdir = '/';
19981                 }
19982         } else {
19983                 buffer_append_string_buffer(p->ofn, con->uri.path);
19984         }
19985 -       
19986 +
19987         switch(type) {
19988         case HTTP_ACCEPT_ENCODING_GZIP:
19989                 buffer_append_string(p->ofn, "-gzip-");
19990 @@ -381,55 +415,64 @@
19991                 log_error_write(srv, __FILE__, __LINE__, "sd", "unknown compression type", type);
19992                 return -1;
19993         }
19994 -       
19995 +
19996         buffer_append_string_buffer(p->ofn, sce->etag);
19997 -       
19998 +
19999 +
20000 +       if (HANDLER_ERROR != stat_cache_get_entry(srv, con, p->ofn, &compressed_sce)) {
20001 +               /* file exists */
20002 +
20003 +               http_chunk_append_file(srv, con, p->ofn, 0, compressed_sce->st.st_size);
20004 +               con->file_finished = 1;
20005 +
20006 +               return 0;
20007 +       }
20008 +
20009         if (-1 == (ofd = open(p->ofn->ptr, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0600))) {
20010                 if (errno == EEXIST) {
20011                         /* cache-entry exists */
20012 -#if 0
20013 -                       log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache hit");
20014 -#endif
20015 -                       buffer_copy_string_buffer(con->physical.path, p->ofn);
20016 -                       
20017 -                       return 0;
20018 +
20019                 }
20020 -               
20021 -               log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cachefile", p->ofn, "failed", strerror(errno));
20022 -               
20023 +
20024 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
20025 +                               "creating cachefile", p->ofn,
20026 +                               "failed", strerror(errno));
20027 +
20028                 return -1;
20029         }
20030 -#if 0
20031 -       log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache miss");
20032 -#endif 
20033 +
20034         if (-1 == (ifd = open(filename, O_RDONLY | O_BINARY))) {
20035 -               log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-file", fn, "failed", strerror(errno));
20036 -               
20037 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
20038 +                               "opening plain-file", fn,
20039 +                               "failed", strerror(errno));
20040 +
20041                 close(ofd);
20042 -               
20043 +
20044                 return -1;
20045         }
20046 -       
20047 -       
20048 +
20049 +
20050         if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
20051 -               log_error_write(srv, __FILE__, __LINE__, "sbss", "mmaping", fn, "failed", strerror(errno));
20052 -               
20053 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
20054 +                               "mmaping", fn,
20055 +                               "failed", strerror(errno));
20056 +
20057                 close(ofd);
20058                 close(ifd);
20059                 return -1;
20060         }
20061 -       
20062 +
20063         switch(type) {
20064  #ifdef USE_ZLIB
20065 -       case HTTP_ACCEPT_ENCODING_GZIP: 
20066 +       case HTTP_ACCEPT_ENCODING_GZIP:
20067                 ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime);
20068                 break;
20069 -       case HTTP_ACCEPT_ENCODING_DEFLATE: 
20070 +       case HTTP_ACCEPT_ENCODING_DEFLATE:
20071                 ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size);
20072                 break;
20073  #endif
20074  #ifdef USE_BZ2LIB
20075 -       case HTTP_ACCEPT_ENCODING_BZIP2: 
20076 +       case HTTP_ACCEPT_ENCODING_BZIP2:
20077                 ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
20078                 break;
20079  #endif
20080 @@ -437,26 +480,27 @@
20081                 ret = -1;
20082                 break;
20083         }
20084 -       
20085 +
20086         if (-1 == (r = write(ofd, p->b->ptr, p->b->used))) {
20087 -               munmap(start, sce->st.st_size); 
20088 +               munmap(start, sce->st.st_size);
20089                 close(ofd);
20090                 close(ifd);
20091                 return -1;
20092         }
20093 -       
20094 +
20095         if ((size_t)r != p->b->used) {
20096 -               
20097 +
20098         }
20099 -               
20100 +
20101         munmap(start, sce->st.st_size);
20102         close(ofd);
20103         close(ifd);
20104 -       
20105 +
20106         if (ret != 0) return -1;
20107 -       
20108 -       buffer_copy_string_buffer(con->physical.path, p->ofn);
20109 -       
20110 +
20111 +       http_chunk_append_file(srv, con, p->ofn, 0, r);
20112 +       con->file_finished = 1;
20113 +
20114         return 0;
20115  }
20116  
20117 @@ -465,43 +509,44 @@
20118         int ret = -1;
20119         void *start;
20120         buffer *b;
20121 -       
20122 +
20123         /* overflow */
20124         if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
20125 -       
20126 +
20127         /* don't mmap files > 128M
20128 -        * 
20129 +        *
20130          * we could use a sliding window, but currently there is no need for it
20131          */
20132 -       
20133 +
20134         if (sce->st.st_size > 128 * 1024 * 1024) return -1;
20135 -       
20136 -       
20137 +
20138         if (-1 == (ifd = open(fn->ptr, O_RDONLY | O_BINARY))) {
20139                 log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-file", fn, "failed", strerror(errno));
20140 -               
20141 +
20142                 return -1;
20143         }
20144 -       
20145 -       
20146 -       if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
20147 +
20148 +       start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0);
20149 +
20150 +       close(ifd);
20151 +
20152 +       if (MAP_FAILED == start) {
20153                 log_error_write(srv, __FILE__, __LINE__, "sbss", "mmaping", fn, "failed", strerror(errno));
20154 -               
20155 -               close(ifd);
20156 +
20157                 return -1;
20158         }
20159 -       
20160 +
20161         switch(type) {
20162  #ifdef USE_ZLIB
20163 -       case HTTP_ACCEPT_ENCODING_GZIP: 
20164 +       case HTTP_ACCEPT_ENCODING_GZIP:
20165                 ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime);
20166                 break;
20167 -       case HTTP_ACCEPT_ENCODING_DEFLATE: 
20168 +       case HTTP_ACCEPT_ENCODING_DEFLATE:
20169                 ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size);
20170                 break;
20171  #endif
20172  #ifdef USE_BZ2LIB
20173 -       case HTTP_ACCEPT_ENCODING_BZIP2: 
20174 +       case HTTP_ACCEPT_ENCODING_BZIP2:
20175                 ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
20176                 break;
20177  #endif
20178 @@ -509,69 +554,64 @@
20179                 ret = -1;
20180                 break;
20181         }
20182 -               
20183 +
20184         munmap(start, sce->st.st_size);
20185 -       close(ifd);
20186 -       
20187 +
20188         if (ret != 0) return -1;
20189 -       
20190 +
20191         chunkqueue_reset(con->write_queue);
20192         b = chunkqueue_get_append_buffer(con->write_queue);
20193         buffer_copy_memory(b, p->b->ptr, p->b->used + 1);
20194 -       
20195 +
20196         buffer_reset(con->physical.path);
20197 -       
20198 +
20199         con->file_finished = 1;
20200         con->file_started  = 1;
20201 -       
20202 +
20203         return 0;
20204  }
20205  
20206 -
20207 -#define PATCH(x) \
20208 -       p->conf.x = s->x;
20209  static int mod_compress_patch_connection(server *srv, connection *con, plugin_data *p) {
20210         size_t i, j;
20211         plugin_config *s = p->config_storage[0];
20212  
20213 -       PATCH(compress_cache_dir);
20214 -       PATCH(compress);
20215 -       PATCH(compress_max_filesize);
20216 -       
20217 +       PATCH_OPTION(compress_cache_dir);
20218 +       PATCH_OPTION(compress);
20219 +       PATCH_OPTION(compress_max_filesize);
20220 +
20221         /* skip the first, the global context */
20222         for (i = 1; i < srv->config_context->used; i++) {
20223                 data_config *dc = (data_config *)srv->config_context->data[i];
20224                 s = p->config_storage[i];
20225 -               
20226 +
20227                 /* condition didn't match */
20228                 if (!config_check_cond(srv, con, dc)) continue;
20229 -               
20230 +
20231                 /* merge config */
20232                 for (j = 0; j < dc->value->used; j++) {
20233                         data_unset *du = dc->value->data[j];
20234 -                       
20235 +
20236                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.cache-dir"))) {
20237 -                               PATCH(compress_cache_dir);
20238 +                               PATCH_OPTION(compress_cache_dir);
20239                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.filetype"))) {
20240 -                               PATCH(compress);
20241 +                               PATCH_OPTION(compress);
20242                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.max-filesize"))) {
20243 -                               PATCH(compress_max_filesize);
20244 +                               PATCH_OPTION(compress_max_filesize);
20245                         }
20246                 }
20247         }
20248 -       
20249 +
20250         return 0;
20251  }
20252 -#undef PATCH
20253  
20254  PHYSICALPATH_FUNC(mod_compress_physical) {
20255         plugin_data *p = p_d;
20256         size_t m;
20257         off_t max_fsize;
20258         stat_cache_entry *sce = NULL;
20259 -       
20260 +
20261         /* only GET and POST can get compressed */
20262 -       if (con->request.http_method != HTTP_METHOD_GET && 
20263 +       if (con->request.http_method != HTTP_METHOD_GET &&
20264             con->request.http_method != HTTP_METHOD_POST) {
20265                 return HANDLER_GO_ON;
20266         }
20267 @@ -579,46 +619,49 @@
20268         if (buffer_is_empty(con->physical.path)) {
20269                 return HANDLER_GO_ON;
20270         }
20271 -       
20272 +
20273         mod_compress_patch_connection(srv, con, p);
20274 -       
20275 +
20276         max_fsize = p->conf.compress_max_filesize;
20277  
20278         stat_cache_get_entry(srv, con, con->physical.path, &sce);
20279  
20280         /* don't compress files that are too large as we need to much time to handle them */
20281         if (max_fsize && (sce->st.st_size >> 10) > max_fsize) return HANDLER_GO_ON;
20282 -               
20283 +
20284 +       /* compressing the file might lead to larger files instead */
20285 +       if (sce->st.st_size < 128) return HANDLER_GO_ON;
20286 +
20287         /* check if mimetype is in compress-config */
20288         for (m = 0; m < p->conf.compress->used; m++) {
20289                 data_string *compress_ds = (data_string *)p->conf.compress->data[m];
20290 -                       
20291 +
20292                 if (!compress_ds) {
20293                         log_error_write(srv, __FILE__, __LINE__, "sbb", "evil", con->physical.path, con->uri.path);
20294 -                       
20295 +
20296                         return HANDLER_GO_ON;
20297                 }
20298 -               
20299 +
20300                 if (buffer_is_equal(compress_ds->value, sce->content_type)) {
20301                         /* mimetype found */
20302                         data_string *ds;
20303 -                               
20304 +
20305                         /* the response might change according to Accept-Encoding */
20306                         response_header_insert(srv, con, CONST_STR_LEN("Vary"), CONST_STR_LEN("Accept-Encoding"));
20307 -                               
20308 +
20309                         if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Accept-Encoding"))) {
20310                                 int accept_encoding = 0;
20311                                 char *value = ds->value->ptr;
20312                                 int srv_encodings = 0;
20313                                 int matched_encodings = 0;
20314 -                               
20315 +
20316                                 /* get client side support encodings */
20317                                 if (NULL != strstr(value, "gzip")) accept_encoding |= HTTP_ACCEPT_ENCODING_GZIP;
20318                                 if (NULL != strstr(value, "deflate")) accept_encoding |= HTTP_ACCEPT_ENCODING_DEFLATE;
20319                                 if (NULL != strstr(value, "compress")) accept_encoding |= HTTP_ACCEPT_ENCODING_COMPRESS;
20320                                 if (NULL != strstr(value, "bzip2")) accept_encoding |= HTTP_ACCEPT_ENCODING_BZIP2;
20321                                 if (NULL != strstr(value, "identity")) accept_encoding |= HTTP_ACCEPT_ENCODING_IDENTITY;
20322 -                               
20323 +
20324                                 /* get server side supported ones */
20325  #ifdef USE_BZ2LIB
20326                                 srv_encodings |= HTTP_ACCEPT_ENCODING_BZIP2;
20327 @@ -627,18 +670,31 @@
20328                                 srv_encodings |= HTTP_ACCEPT_ENCODING_GZIP;
20329                                 srv_encodings |= HTTP_ACCEPT_ENCODING_DEFLATE;
20330  #endif
20331 -                               
20332 +
20333                                 /* find matching entries */
20334                                 matched_encodings = accept_encoding & srv_encodings;
20335 -                               
20336 +
20337                                 if (matched_encodings) {
20338                                         const char *dflt_gzip = "gzip";
20339                                         const char *dflt_deflate = "deflate";
20340                                         const char *dflt_bzip2 = "bzip2";
20341 -                                       
20342 +
20343                                         const char *compression_name = NULL;
20344                                         int compression_type = 0;
20345 -                                       
20346 +                                       buffer *mtime;
20347 +
20348 +                                       mtime = strftime_cache_get(srv, sce->st.st_mtime);
20349 +                                       etag_mutate(con->physical.etag, sce->etag);
20350 +
20351 +                                       response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
20352 +                                       response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
20353 +
20354 +                                       /* perhaps we don't even have to compress the file as the browser still has the
20355 +                                        * current version */
20356 +                                       if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
20357 +                                               return HANDLER_FINISHED;
20358 +                                       }
20359 +
20360                                         /* select best matching encoding */
20361                                         if (matched_encodings & HTTP_ACCEPT_ENCODING_BZIP2) {
20362                                                 compression_type = HTTP_ACCEPT_ENCODING_BZIP2;
20363 @@ -650,31 +706,21 @@
20364                                                 compression_type = HTTP_ACCEPT_ENCODING_DEFLATE;
20365                                                 compression_name = dflt_deflate;
20366                                         }
20367 -                                       
20368 -                                       /* deflate it */
20369 -                                       if (p->conf.compress_cache_dir->used) {
20370 -                                               if (0 == deflate_file_to_file(srv, con, p,
20371 -                                                                             con->physical.path, sce, compression_type)) {
20372 -                                                       buffer *mtime;
20373 -                                                       
20374 -                                                       response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
20375 -                                                       
20376 -                                                       mtime = strftime_cache_get(srv, sce->st.st_mtime);
20377 -                                                       response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
20378 -
20379 -                                                       etag_mutate(con->physical.etag, sce->etag);
20380 -                                                       response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
20381 -
20382 -                                                       response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
20383 -
20384 -                                                       return HANDLER_GO_ON;
20385 -                                               }
20386 -                                       } else if (0 == deflate_file_to_buffer(srv, con, p,
20387 -                                                                              con->physical.path, sce, compression_type)) {
20388 -                                                       
20389 -                                               response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
20390 -                                               response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
20391 -                                               
20392 +
20393 +                                       /* deflate it to file (cached) or to memory */
20394 +                                       if (0 == deflate_file_to_file(srv, con, p,
20395 +                                                       con->physical.path, sce, compression_type) ||
20396 +                                           0 == deflate_file_to_buffer(srv, con, p,
20397 +                                                       con->physical.path, sce, compression_type)) {
20398 +
20399 +                                               response_header_overwrite(srv, con,
20400 +                                                               CONST_STR_LEN("Content-Encoding"),
20401 +                                                               compression_name, strlen(compression_name));
20402 +
20403 +                                               response_header_overwrite(srv, con,
20404 +                                                               CONST_STR_LEN("Content-Type"),
20405 +                                                               CONST_BUF_LEN(sce->content_type));
20406 +
20407                                                 return HANDLER_FINISHED;
20408                                         }
20409                                         break;
20410 @@ -682,20 +728,20 @@
20411                         }
20412                 }
20413         }
20414 -       
20415 +
20416         return HANDLER_GO_ON;
20417  }
20418  
20419  int mod_compress_plugin_init(plugin *p) {
20420         p->version     = LIGHTTPD_VERSION_ID;
20421         p->name        = buffer_init_string("compress");
20422 -       
20423 +
20424         p->init        = mod_compress_init;
20425         p->set_defaults = mod_compress_setdefaults;
20426         p->handle_subrequest_start  = mod_compress_physical;
20427         p->cleanup     = mod_compress_free;
20428 -       
20429 +
20430         p->data        = NULL;
20431 -       
20432 +
20433         return 0;
20434  }
20435 --- ../lighttpd-1.4.11/src/mod_dirlisting.c     2006-01-13 00:00:45.000000000 +0200
20436 +++ lighttpd-1.4.12/src/mod_dirlisting.c        2006-07-16 00:26:04.000000000 +0300
20437 @@ -1,11 +1,9 @@
20438  #include <ctype.h>
20439  #include <stdlib.h>
20440  #include <string.h>
20441 -#include <dirent.h>
20442  #include <assert.h>
20443  #include <errno.h>
20444  #include <stdio.h>
20445 -#include <unistd.h>
20446  #include <time.h>
20447  
20448  #include "base.h"
20449 @@ -17,6 +15,9 @@
20450  #include "response.h"
20451  #include "stat_cache.h"
20452  #include "stream.h"
20453 +#include "etag.h"
20454 +
20455 +#include "sys-strings.h"
20456  
20457  /**
20458   * this is a dirlisting for a lighttpd plugin
20459 @@ -27,10 +28,13 @@
20460  #include <sys/syslimits.h>
20461  #endif
20462  
20463 -#ifdef HAVE_ATTR_ATTRIBUTES_H
20464 +#ifdef HAVE_XATTR
20465  #include <attr/attributes.h>
20466  #endif
20467  
20468 +#include "sys-files.h"
20469 +#include "sys-strings.h"
20470 +
20471  /* plugin config for all request/connections */
20472  
20473  typedef struct {
20474 @@ -54,7 +58,7 @@
20475         unsigned short hide_readme_file;
20476         unsigned short show_header;
20477         unsigned short hide_header_file;
20478 -       
20479 +
20480         excludes_buffer *excludes;
20481  
20482         buffer *external_css;
20483 @@ -63,13 +67,14 @@
20484  
20485  typedef struct {
20486         PLUGIN_DATA;
20487 -       
20488 +
20489         buffer *tmp_buf;
20490         buffer *content_charset;
20491 -       
20492 +       buffer *path;
20493 +
20494         plugin_config **config_storage;
20495 -       
20496 -       plugin_config conf; 
20497 +
20498 +       plugin_config conf;
20499  } plugin_data;
20500  
20501  excludes_buffer *excludes_buffer_init(void) {
20502 @@ -146,44 +151,46 @@
20503  /* init the plugin data */
20504  INIT_FUNC(mod_dirlisting_init) {
20505         plugin_data *p;
20506 -       
20507 +
20508         p = calloc(1, sizeof(*p));
20509  
20510         p->tmp_buf = buffer_init();
20511         p->content_charset = buffer_init();
20512 -       
20513 +       p->path = buffer_init();
20514 +
20515         return p;
20516  }
20517  
20518  /* detroy the plugin data */
20519  FREE_FUNC(mod_dirlisting_free) {
20520         plugin_data *p = p_d;
20521 -       
20522 +
20523         UNUSED(srv);
20524  
20525         if (!p) return HANDLER_GO_ON;
20526 -       
20527 +
20528         if (p->config_storage) {
20529                 size_t i;
20530                 for (i = 0; i < srv->config_context->used; i++) {
20531                         plugin_config *s = p->config_storage[i];
20532 -                       
20533 +
20534                         if (!s) continue;
20535 -                       
20536 +
20537                         excludes_buffer_free(s->excludes);
20538                         buffer_free(s->external_css);
20539                         buffer_free(s->encoding);
20540 -                       
20541 +
20542                         free(s);
20543                 }
20544                 free(p->config_storage);
20545         }
20546 -       
20547 +
20548         buffer_free(p->tmp_buf);
20549 +       buffer_free(p->path);
20550         buffer_free(p->content_charset);
20551 -       
20552 +
20553         free(p);
20554 -       
20555 +
20556         return HANDLER_GO_ON;
20557  }
20558  
20559 @@ -215,10 +222,10 @@
20560                         if (0 != excludes_buffer_append(s->excludes,
20561                                     ((data_string *)(da->value->data[j]))->value)) {
20562  #ifdef HAVE_PCRE_H
20563 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
20564 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
20565                                                 "pcre-compile failed for", ((data_string *)(da->value->data[j]))->value);
20566  #else
20567 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
20568 +                               log_error_write(srv, __FILE__, __LINE__, "s",
20569                                                 "pcre support is missing, please install libpcre and the headers");
20570  #endif
20571                         }
20572 @@ -233,8 +240,8 @@
20573  SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
20574         plugin_data *p = p_d;
20575         size_t i = 0;
20576 -       
20577 -       config_values_t cv[] = { 
20578 +
20579 +       config_values_t cv[] = {
20580                 { "dir-listing.exclude",          NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },   /* 0 */
20581                 { "dir-listing.activate",         NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
20582                 { "dir-listing.hide-dotfiles",    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
20583 @@ -245,18 +252,18 @@
20584                 { "dir-listing.show-header",      NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
20585                 { "dir-listing.hide-header-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
20586                 { "server.dir-listing",           NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
20587 -               
20588 +
20589                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
20590         };
20591 -       
20592 +
20593         if (!p) return HANDLER_ERROR;
20594 -       
20595 +
20596         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
20597 -       
20598 +
20599         for (i = 0; i < srv->config_context->used; i++) {
20600                 plugin_config *s;
20601                 array *ca;
20602 -               
20603 +
20604                 s = calloc(1, sizeof(plugin_config));
20605                 s->excludes = excludes_buffer_init();
20606                 s->dir_listing = 0;
20607 @@ -267,7 +274,7 @@
20608                 s->show_header = 0;
20609                 s->hide_header_file = 0;
20610                 s->encoding = buffer_init();
20611 -               
20612 +
20613                 cv[0].destination = s->excludes;
20614                 cv[1].destination = &(s->dir_listing);
20615                 cv[2].destination = &(s->hide_dot_files);
20616 @@ -292,60 +299,57 @@
20617         return HANDLER_GO_ON;
20618  }
20619  
20620 -#define PATCH(x) \
20621 -       p->conf.x = s->x;
20622  static int mod_dirlisting_patch_connection(server *srv, connection *con, plugin_data *p) {
20623         size_t i, j;
20624         plugin_config *s = p->config_storage[0];
20625  
20626 -       PATCH(dir_listing);
20627 -       PATCH(external_css);
20628 -       PATCH(hide_dot_files);
20629 -       PATCH(encoding);
20630 -       PATCH(show_readme);
20631 -       PATCH(hide_readme_file);
20632 -       PATCH(show_header);
20633 -       PATCH(hide_header_file);
20634 -       PATCH(excludes);
20635 -       
20636 +       PATCH_OPTION(dir_listing);
20637 +       PATCH_OPTION(external_css);
20638 +       PATCH_OPTION(hide_dot_files);
20639 +       PATCH_OPTION(encoding);
20640 +       PATCH_OPTION(show_readme);
20641 +       PATCH_OPTION(hide_readme_file);
20642 +       PATCH_OPTION(show_header);
20643 +       PATCH_OPTION(hide_header_file);
20644 +       PATCH_OPTION(excludes);
20645 +
20646         /* skip the first, the global context */
20647         for (i = 1; i < srv->config_context->used; i++) {
20648                 data_config *dc = (data_config *)srv->config_context->data[i];
20649                 s = p->config_storage[i];
20650 -               
20651 +
20652                 /* condition didn't match */
20653                 if (!config_check_cond(srv, con, dc)) continue;
20654 -               
20655 +
20656                 /* merge config */
20657                 for (j = 0; j < dc->value->used; j++) {
20658                         data_unset *du = dc->value->data[j];
20659 -                       
20660 +
20661                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.activate")) ||
20662                             buffer_is_equal_string(du->key, CONST_STR_LEN("server.dir-listing"))) {
20663 -                               PATCH(dir_listing);
20664 +                               PATCH_OPTION(dir_listing);
20665                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-dotfiles"))) {
20666 -                               PATCH(hide_dot_files);
20667 +                               PATCH_OPTION(hide_dot_files);
20668                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.external-css"))) {
20669 -                               PATCH(external_css);
20670 +                               PATCH_OPTION(external_css);
20671                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.encoding"))) {
20672 -                               PATCH(encoding);
20673 +                               PATCH_OPTION(encoding);
20674                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-readme"))) {
20675 -                               PATCH(show_readme);
20676 +                               PATCH_OPTION(show_readme);
20677                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-readme-file"))) {
20678 -                               PATCH(hide_readme_file);
20679 +                               PATCH_OPTION(hide_readme_file);
20680                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-header"))) {
20681 -                               PATCH(show_header);
20682 +                               PATCH_OPTION(show_header);
20683                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-header-file"))) {
20684 -                               PATCH(hide_header_file);
20685 +                               PATCH_OPTION(hide_header_file);
20686                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.excludes"))) {
20687 -                               PATCH(excludes);
20688 +                               PATCH_OPTION(excludes);
20689                         }
20690                 }
20691         }
20692 -       
20693 +
20694         return 0;
20695  }
20696 -#undef PATCH
20697  
20698  typedef struct {
20699         size_t  namelen;
20700 @@ -432,7 +436,7 @@
20701  
20702  static void http_list_directory_header(server *srv, connection *con, plugin_data *p, buffer *out) {
20703         UNUSED(srv);
20704 -       
20705 +
20706         BUFFER_APPEND_STRING_CONST(out,
20707                 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
20708                 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n"
20709 @@ -492,11 +496,11 @@
20710         if (p->conf.show_header) {
20711                 stream s;
20712                 /* if we have a HEADER file, display it in <pre class="header"></pre> */
20713 -               
20714 +
20715                 buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
20716 -               BUFFER_APPEND_SLASH(p->tmp_buf);
20717 +               PATHNAME_APPEND_SLASH(p->tmp_buf);
20718                 BUFFER_APPEND_STRING_CONST(p->tmp_buf, "HEADER.txt");
20719 -               
20720 +
20721                 if (-1 != stream_open(&s, p->tmp_buf)) {
20722                         BUFFER_APPEND_STRING_CONST(out, "<pre class=\"header\">");
20723                         buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
20724 @@ -531,21 +535,21 @@
20725  
20726  static void http_list_directory_footer(server *srv, connection *con, plugin_data *p, buffer *out) {
20727         UNUSED(srv);
20728 -       
20729 +
20730         BUFFER_APPEND_STRING_CONST(out,
20731                 "</tbody>\n"
20732                 "</table>\n"
20733                 "</div>\n"
20734         );
20735 -       
20736 +
20737         if (p->conf.show_readme) {
20738                 stream s;
20739                 /* if we have a README file, display it in <pre class="readme"></pre> */
20740 -               
20741 +
20742                 buffer_copy_string_buffer(p->tmp_buf,  con->physical.path);
20743 -               BUFFER_APPEND_SLASH(p->tmp_buf);
20744 +               PATHNAME_APPEND_SLASH(p->tmp_buf);
20745                 BUFFER_APPEND_STRING_CONST(p->tmp_buf, "README.txt");
20746 -               
20747 +
20748                 if (-1 != stream_open(&s, p->tmp_buf)) {
20749                         BUFFER_APPEND_STRING_CONST(out, "<pre class=\"readme\">");
20750                         buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
20751 @@ -553,7 +557,7 @@
20752                 }
20753                 stream_close(&s);
20754         }
20755 -       
20756 +
20757         BUFFER_APPEND_STRING_CONST(out,
20758                 "<div class=\"foot\">"
20759         );
20760 @@ -576,7 +580,6 @@
20761         buffer *out;
20762         struct dirent *dent;
20763         struct stat st;
20764 -       char *path, *path_file;
20765         size_t i;
20766         int hide_dotfiles = p->conf.hide_dot_files;
20767         dirls_list_t dirs, files, *list;
20768 @@ -586,6 +589,7 @@
20769         size_t k;
20770         const char *content_type;
20771         long name_max;
20772 +
20773  #ifdef HAVE_XATTR
20774         char attrval[128];
20775         int attrlen;
20776 @@ -594,10 +598,10 @@
20777         struct tm tm;
20778  #endif
20779  
20780 -       if (dir->used == 0) return -1;
20781 -       
20782 -       i = dir->used - 1;
20783 +       /* empty pathname, never ... */
20784 +       if (buffer_is_empty(dir)) return -1;
20785  
20786 +       /* max-length for the opendir */
20787  #ifdef HAVE_PATHCONF
20788         if (-1 == (name_max = pathconf(dir->ptr, _PC_NAME_MAX))) {
20789  #ifdef NAME_MAX
20790 @@ -606,22 +610,24 @@
20791                 name_max = 256; /* stupid default */
20792  #endif
20793         }
20794 -#elif defined __WIN32
20795 +#elif defined _WIN32
20796         name_max = FILENAME_MAX;
20797  #else
20798         name_max = NAME_MAX;
20799  #endif
20800 -       
20801 -       path = malloc(dir->used + name_max);
20802 -       assert(path);
20803 -       strcpy(path, dir->ptr);
20804 -       path_file = path + i;
20805  
20806 -       if (NULL == (dp = opendir(path))) {
20807 -               log_error_write(srv, __FILE__, __LINE__, "sbs", 
20808 +       buffer_copy_string_buffer(p->path, dir);
20809 +       PATHNAME_APPEND_SLASH(p->path);
20810 +
20811 +#ifdef _WIN32
20812 +       /* append *.* to the path */
20813 +       buffer_append_string(path, "*.*");
20814 +#endif
20815 +
20816 +       if (NULL == (dp = opendir(p->path->ptr))) {
20817 +               log_error_write(srv, __FILE__, __LINE__, "sbs",
20818                         "opendir failed:", dir, strerror(errno));
20819  
20820 -               free(path);
20821                 return -1;
20822         }
20823  
20824 @@ -633,7 +639,7 @@
20825         assert(files.ent);
20826         files.size = DIRLIST_BLOB_SIZE;
20827         files.used = 0;
20828 -       
20829 +
20830         while ((dent = readdir(dp)) != NULL) {
20831                 unsigned short exclude_match = 0;
20832  
20833 @@ -686,15 +692,21 @@
20834  #endif
20835  
20836                 i = strlen(dent->d_name);
20837 -               
20838 +
20839                 /* NOTE: the manual says, d_name is never more than NAME_MAX
20840                  *       so this should actually not be a buffer-overflow-risk
20841                  */
20842                 if (i > (size_t)name_max) continue;
20843 -               
20844 -               memcpy(path_file, dent->d_name, i + 1);
20845 -               if (stat(path, &st) != 0)
20846 +
20847 +               /* build the dirname */
20848 +               buffer_copy_string_buffer(p->path, dir);
20849 +               PATHNAME_APPEND_SLASH(p->path);
20850 +               buffer_append_string(p->path, dent->d_name);
20851 +
20852 +               if (stat(p->path->ptr, &st) != 0) {
20853 +                       fprintf(stderr, "%s.%d: %s, %s\r\n", __FILE__, __LINE__, p->path->ptr, strerror(errno));
20854                         continue;
20855 +               }
20856  
20857                 list = &files;
20858                 if (S_ISDIR(st.st_mode))
20859 @@ -740,7 +752,7 @@
20860  #else
20861                 strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime)));
20862  #endif
20863 -               
20864 +
20865                 BUFFER_APPEND_STRING_CONST(out, "<tr><td class=\"n\"><a href=\"");
20866                 buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART);
20867                 BUFFER_APPEND_STRING_CONST(out, "/\">");
20868 @@ -757,18 +769,22 @@
20869                 tmp = files.ent[i];
20870  
20871                 content_type = NULL;
20872 +
20873  #ifdef HAVE_XATTR
20874 -               
20875                 if (con->conf.use_xattr) {
20876 -                       memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1);
20877 +                       /* build the dirname */
20878 +                       buffer_copy_string_buffer(p->path, dir);
20879 +                       PATHNAME_APPEND_SLASH(p->path);
20880 +                       buffer_append_string_len(p->path, DIRLIST_ENT_NAME(tmp), tmp->namelen);
20881 +
20882                         attrlen = sizeof(attrval) - 1;
20883 -                       if (attr_get(path, "Content-Type", attrval, &attrlen, 0) == 0) {
20884 +                       if (attr_get(p->path->ptr, "Content-Type", attrval, &attrlen, 0) == 0) {
20885                                 attrval[attrlen] = '\0';
20886                                 content_type = attrval;
20887                         }
20888                 }
20889  #endif
20890 -               
20891 +
20892                 if (content_type == NULL) {
20893                         content_type = "application/octet-stream";
20894                         for (k = 0; k < con->conf.mimetypes->used; k++) {
20895 @@ -788,7 +804,7 @@
20896                                 }
20897                         }
20898                 }
20899 -                       
20900 +
20901  #ifdef HAVE_LOCALTIME_R
20902                 localtime_r(&(tmp->mtime), &tm);
20903                 strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm);
20904 @@ -814,7 +830,6 @@
20905  
20906         free(files.ent);
20907         free(dirs.ent);
20908 -       free(path);
20909  
20910         http_list_directory_footer(srv, con, p, out);
20911  
20912 @@ -837,36 +852,55 @@
20913  URIHANDLER_FUNC(mod_dirlisting_subrequest) {
20914         plugin_data *p = p_d;
20915         stat_cache_entry *sce = NULL;
20916 -       
20917 -       UNUSED(srv);
20918 -       
20919 -       if (con->physical.path->used == 0) return HANDLER_GO_ON;
20920 -       if (con->uri.path->used == 0) return HANDLER_GO_ON;
20921 +       buffer *mtime;
20922 +       data_string *ds;
20923 +
20924 +       if (con->uri.path->used < 2) return HANDLER_GO_ON;
20925         if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
20926 -       
20927 +       if (con->physical.path->used == 0) return HANDLER_GO_ON;
20928 +
20929         mod_dirlisting_patch_connection(srv, con, p);
20930  
20931         if (!p->conf.dir_listing) return HANDLER_GO_ON;
20932 -       
20933 +
20934 +       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
20935 +               /* just a second ago the file was still there */
20936 +               return HANDLER_GO_ON;
20937 +       }
20938 +
20939 +       if (!S_ISDIR(sce->st.st_mode)) return HANDLER_GO_ON;
20940 +
20941         if (con->conf.log_request_handling) {
20942                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling the request as Dir-Listing");
20943                 log_error_write(srv, __FILE__, __LINE__,  "sb", "URI          :", con->uri.path);
20944         }
20945 -       
20946 -       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
20947 -               fprintf(stderr, "%s.%d: %s\n", __FILE__, __LINE__, con->physical.path->ptr);
20948 -               SEGFAULT();
20949 +
20950 +       /* perhaps this a cachable request
20951 +        * - we use the etag of the directory
20952 +        * */
20953 +
20954 +       etag_mutate(con->physical.etag, sce->etag);
20955 +       response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
20956 +
20957 +       /* prepare header */
20958 +       if (NULL == (ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"))) {
20959 +               mtime = strftime_cache_get(srv, sce->st.st_mtime);
20960 +               response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
20961 +       } else {
20962 +               mtime = ds->value;
20963         }
20964 -       
20965 -       if (!S_ISDIR(sce->st.st_mode)) return HANDLER_GO_ON;
20966 -       
20967 +
20968 +       if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
20969 +               return HANDLER_FINISHED;
20970 +       }
20971 +
20972         if (http_list_directory(srv, con, p, con->physical.path)) {
20973                 /* dirlisting failed */
20974                 con->http_status = 403;
20975         }
20976 -       
20977 +
20978         buffer_reset(con->physical.path);
20979 -       
20980 +
20981         /* not found */
20982         return HANDLER_FINISHED;
20983  }
20984 @@ -876,13 +910,13 @@
20985  int mod_dirlisting_plugin_init(plugin *p) {
20986         p->version     = LIGHTTPD_VERSION_ID;
20987         p->name        = buffer_init_string("dirlisting");
20988 -       
20989 +
20990         p->init        = mod_dirlisting_init;
20991         p->handle_subrequest_start  = mod_dirlisting_subrequest;
20992         p->set_defaults  = mod_dirlisting_set_defaults;
20993         p->cleanup     = mod_dirlisting_free;
20994 -       
20995 +
20996         p->data        = NULL;
20997 -       
20998 +
20999         return 0;
21000  }
21001 --- ../lighttpd-1.4.11/src/mod_evasive.c        2006-01-04 15:24:51.000000000 +0200
21002 +++ lighttpd-1.4.12/src/mod_evasive.c   2006-07-16 00:26:04.000000000 +0300
21003 @@ -31,100 +31,97 @@
21004  
21005  typedef struct {
21006         PLUGIN_DATA;
21007 -       
21008 +
21009         plugin_config **config_storage;
21010 -       
21011 -       plugin_config conf; 
21012 +
21013 +       plugin_config conf;
21014  } plugin_data;
21015  
21016  INIT_FUNC(mod_evasive_init) {
21017         plugin_data *p;
21018 -       
21019 +
21020         p = calloc(1, sizeof(*p));
21021 -       
21022 +
21023         return p;
21024  }
21025  
21026  FREE_FUNC(mod_evasive_free) {
21027         plugin_data *p = p_d;
21028 -       
21029 +
21030         UNUSED(srv);
21031  
21032         if (!p) return HANDLER_GO_ON;
21033 -       
21034 +
21035         if (p->config_storage) {
21036                 size_t i;
21037                 for (i = 0; i < srv->config_context->used; i++) {
21038                         plugin_config *s = p->config_storage[i];
21039 -                                               
21040 +
21041                         free(s);
21042                 }
21043                 free(p->config_storage);
21044         }
21045 -       
21046 +
21047         free(p);
21048 -       
21049 +
21050         return HANDLER_GO_ON;
21051  }
21052  
21053  SETDEFAULTS_FUNC(mod_evasive_set_defaults) {
21054         plugin_data *p = p_d;
21055         size_t i = 0;
21056 -       
21057 -       config_values_t cv[] = { 
21058 +
21059 +       config_values_t cv[] = {
21060                 { "evasive.max-conns-per-ip",    NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
21061                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
21062         };
21063 -       
21064 +
21065         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
21066 -       
21067 +
21068         for (i = 0; i < srv->config_context->used; i++) {
21069                 plugin_config *s;
21070 -               
21071 +
21072                 s = calloc(1, sizeof(plugin_config));
21073                 s->max_conns       = 0;
21074 -               
21075 +
21076                 cv[0].destination = &(s->max_conns);
21077 -               
21078 +
21079                 p->config_storage[i] = s;
21080 -       
21081 +
21082                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
21083                         return HANDLER_ERROR;
21084                 }
21085         }
21086 -       
21087 +
21088         return HANDLER_GO_ON;
21089  }
21090  
21091 -#define PATCH(x) \
21092 -       p->conf.x = s->x;
21093  static int mod_evasive_patch_connection(server *srv, connection *con, plugin_data *p) {
21094         size_t i, j;
21095         plugin_config *s = p->config_storage[0];
21096  
21097 -       PATCH(max_conns);
21098 -       
21099 +       PATCH_OPTION(max_conns);
21100 +
21101         /* skip the first, the global context */
21102         for (i = 1; i < srv->config_context->used; i++) {
21103                 data_config *dc = (data_config *)srv->config_context->data[i];
21104                 s = p->config_storage[i];
21105 -               
21106 +
21107                 /* condition didn't match */
21108                 if (!config_check_cond(srv, con, dc)) continue;
21109 -               
21110 +
21111                 /* merge config */
21112                 for (j = 0; j < dc->value->used; j++) {
21113                         data_unset *du = dc->value->data[j];
21114 -                       
21115 +
21116                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("evasive.max-conns-per-ip"))) {
21117 -                               PATCH(max_conns);
21118 +                               PATCH_OPTION(max_conns);
21119                         }
21120                 }
21121         }
21122 -       
21123 +
21124         return 0;
21125  }
21126 -#undef PATCH
21127  
21128  URIHANDLER_FUNC(mod_evasive_uri_handler) {
21129         plugin_data *p = p_d;
21130 @@ -132,10 +129,10 @@
21131         size_t j;
21132  
21133         if (con->uri.path->used == 0) return HANDLER_GO_ON;
21134 -       
21135 +
21136         mod_evasive_patch_connection(srv, con, p);
21137 -       
21138 -       /* no limit set, nothing to block */    
21139 +
21140 +       /* no limit set, nothing to block */
21141         if (p->conf.max_conns == 0) return HANDLER_GO_ON;
21142  
21143         for (j = 0; j < srv->conns->used; j++) {
21144 @@ -147,7 +144,7 @@
21145                 if (c->dst_addr.ipv4.sin_addr.s_addr == con->dst_addr.ipv4.sin_addr.s_addr &&
21146                     c->state > CON_STATE_REQUEST_END) {
21147                         conns_by_ip++;
21148 -       
21149 +
21150                         if (conns_by_ip > p->conf.max_conns) {
21151                                 log_error_write(srv, __FILE__, __LINE__, "ss",
21152                                         inet_ntop_cache_get_ip(srv, &(con->dst_addr)),
21153 @@ -158,7 +155,7 @@
21154                         }
21155                 }
21156         }
21157 -       
21158 +
21159         return HANDLER_GO_ON;
21160  }
21161  
21162 @@ -166,13 +163,13 @@
21163  int mod_evasive_plugin_init(plugin *p) {
21164         p->version     = LIGHTTPD_VERSION_ID;
21165         p->name        = buffer_init_string("evasive");
21166 -       
21167 +
21168         p->init        = mod_evasive_init;
21169         p->set_defaults = mod_evasive_set_defaults;
21170         p->handle_uri_clean  = mod_evasive_uri_handler;
21171         p->cleanup     = mod_evasive_free;
21172 -       
21173 +
21174         p->data        = NULL;
21175 -       
21176 +
21177         return 0;
21178  }
21179 --- ../lighttpd-1.4.11/src/mod_evhost.c 2005-08-17 10:42:03.000000000 +0300
21180 +++ lighttpd-1.4.12/src/mod_evhost.c    2006-07-16 00:26:03.000000000 +0300
21181 @@ -7,10 +7,12 @@
21182  #include "response.h"
21183  #include "stat_cache.h"
21184  
21185 +#include "sys-files.h"
21186 +
21187  typedef struct {
21188         /* unparsed pieces */
21189         buffer *path_pieces_raw;
21190 -       
21191 +
21192         /* pieces for path creation */
21193         size_t len;
21194         buffer **path_pieces;
21195 @@ -21,14 +23,14 @@
21196         buffer *tmp_buf;
21197  
21198         plugin_config **config_storage;
21199 -       plugin_config conf; 
21200 +       plugin_config conf;
21201  } plugin_data;
21202  
21203  INIT_FUNC(mod_evhost_init) {
21204         plugin_data *p;
21205 -       
21206 +
21207         p = calloc(1, sizeof(*p));
21208 -       
21209 +
21210         p->tmp_buf = buffer_init();
21211  
21212         return p;
21213 @@ -36,34 +38,34 @@
21214  
21215  FREE_FUNC(mod_evhost_free) {
21216         plugin_data *p = p_d;
21217 -       
21218 +
21219         UNUSED(srv);
21220  
21221         if (!p) return HANDLER_GO_ON;
21222 -       
21223 +
21224         if (p->config_storage) {
21225                 size_t i;
21226                 for (i = 0; i < srv->config_context->used; i++) {
21227                         plugin_config *s = p->config_storage[i];
21228  
21229                         if (!s) continue;
21230 -                       
21231 +
21232                         if(s->path_pieces) {
21233                                 size_t j;
21234                                 for (j = 0; j < s->len; j++) {
21235                                         buffer_free(s->path_pieces[j]);
21236                                 }
21237 -                               
21238 +
21239                                 free(s->path_pieces);
21240                         }
21241 -                       
21242 +
21243                         buffer_free(s->path_pieces_raw);
21244 -                       
21245 +
21246                         free(s);
21247                 }
21248                 free(p->config_storage);
21249         }
21250 -       
21251 +
21252         buffer_free(p->tmp_buf);
21253  
21254         free(p);
21255 @@ -73,30 +75,30 @@
21256  
21257  static void mod_evhost_parse_pattern(plugin_config *s) {
21258         char *ptr = s->path_pieces_raw->ptr,*pos;
21259 -       
21260 +
21261         s->path_pieces = NULL;
21262 -       
21263 +
21264         for(pos=ptr;*ptr;ptr++) {
21265                 if(*ptr == '%') {
21266                         s->path_pieces = realloc(s->path_pieces,(s->len+2) * sizeof(*s->path_pieces));
21267                         s->path_pieces[s->len] = buffer_init();
21268                         s->path_pieces[s->len+1] = buffer_init();
21269 -                       
21270 +
21271                         buffer_copy_string_len(s->path_pieces[s->len],pos,ptr-pos);
21272                         pos = ptr + 2;
21273 -                       
21274 +
21275                         buffer_copy_string_len(s->path_pieces[s->len+1],ptr++,2);
21276 -                       
21277 +
21278                         s->len += 2;
21279                 }
21280         }
21281 -       
21282 +
21283         if(*pos != '\0') {
21284                 s->path_pieces = realloc(s->path_pieces,(s->len+1) * sizeof(*s->path_pieces));
21285                 s->path_pieces[s->len] = buffer_init();
21286 -               
21287 +
21288                 buffer_append_memory(s->path_pieces[s->len],pos,ptr-pos);
21289 -               
21290 +
21291                 s->len += 1;
21292         }
21293  }
21294 @@ -104,9 +106,9 @@
21295  SETDEFAULTS_FUNC(mod_evhost_set_defaults) {
21296         plugin_data *p = p_d;
21297         size_t i;
21298 -       
21299 +
21300         /**
21301 -        * 
21302 +        *
21303          * #
21304          * # define a pattern for the host url finding
21305          * # %% => % sign
21306 @@ -117,39 +119,39 @@
21307          * # %4 => subdomain 2 name
21308          * #
21309          * evhost.path-pattern = "/home/ckruse/dev/www/%3/htdocs/"
21310 -        * 
21311 +        *
21312          */
21313 -       
21314 -       config_values_t cv[] = { 
21315 +
21316 +       config_values_t cv[] = {
21317                 { "evhost.path-pattern",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
21318                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
21319         };
21320 -       
21321 +
21322         if (!p) return HANDLER_ERROR;
21323 -       
21324 +
21325         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
21326 -       
21327 +
21328         for (i = 0; i < srv->config_context->used; i++) {
21329                 plugin_config *s;
21330 -               
21331 +
21332                 s = calloc(1, sizeof(plugin_config));
21333                 s->path_pieces_raw = buffer_init();
21334                 s->path_pieces     = NULL;
21335                 s->len             = 0;
21336 -       
21337 +
21338                 cv[0].destination = s->path_pieces_raw;
21339 -               
21340 +
21341                 p->config_storage[i] = s;
21342 -               
21343 +
21344                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value,  cv)) {
21345                         return HANDLER_ERROR;
21346                 }
21347 -               
21348 +
21349                 if (s->path_pieces_raw->used != 0) {
21350                         mod_evhost_parse_pattern(s);
21351                 }
21352         }
21353 -       
21354 +
21355         return HANDLER_GO_ON;
21356  }
21357  
21358 @@ -158,7 +160,7 @@
21359   * - %0 - full hostname (authority w/o port)
21360   * - %1 - tld
21361   * - %2 - domain.tld
21362 - * - %3 - 
21363 + * - %3 -
21364   */
21365  
21366  static int mod_evhost_parse_host(connection *con,array *host) {
21367 @@ -168,7 +170,7 @@
21368         int first = 1;
21369         data_string *ds;
21370         int i;
21371 -       
21372 +
21373         /* first, find the domain + tld */
21374         for(;ptr > con->uri.authority->ptr;ptr--) {
21375                 if(*ptr == '.') {
21376 @@ -179,18 +181,18 @@
21377                         first = 1;
21378                 }
21379         }
21380 -       
21381 +
21382         ds = data_string_init();
21383         buffer_copy_string(ds->key,"%0");
21384 -       
21385 +
21386         /* if we stopped at a dot, skip the dot */
21387         if (*ptr == '.') ptr++;
21388         buffer_copy_string_len(ds->value, ptr, colon-ptr);
21389 -       
21390 +
21391         array_insert_unique(host,(data_unset *)ds);
21392 -       
21393 +
21394         /* if the : is not the start of the authority, go on parsing the hostname */
21395 -       
21396 +
21397         if (colon != con->uri.authority->ptr) {
21398                 for(ptr = colon - 1, i = 1; ptr > con->uri.authority->ptr; ptr--) {
21399                         if(*ptr == '.') {
21400 @@ -200,59 +202,55 @@
21401                                         buffer_copy_string(ds->key,"%");
21402                                         buffer_append_long(ds->key, i++);
21403                                         buffer_copy_string_len(ds->value,ptr+1,colon-ptr-1);
21404 -                                       
21405 +
21406                                         array_insert_unique(host,(data_unset *)ds);
21407                                 }
21408                                 colon = ptr;
21409                         }
21410                 }
21411 -               
21412 +
21413                 /* if the . is not the first charactor of the hostname */
21414                 if (colon != ptr) {
21415                         ds = data_string_init();
21416                         buffer_copy_string(ds->key,"%");
21417                         buffer_append_long(ds->key, i++);
21418                         buffer_copy_string_len(ds->value,ptr,colon-ptr);
21419 -                       
21420 +
21421                         array_insert_unique(host,(data_unset *)ds);
21422                 }
21423         }
21424 -       
21425 +
21426         return 0;
21427  }
21428  
21429 -#define PATCH(x) \
21430 -       p->conf.x = s->x;
21431  static int mod_evhost_patch_connection(server *srv, connection *con, plugin_data *p) {
21432         size_t i, j;
21433         plugin_config *s = p->config_storage[0];
21434 -       
21435 -       PATCH(path_pieces);
21436 -       PATCH(len);
21437 -       
21438 +
21439 +       PATCH_OPTION(path_pieces);
21440 +       PATCH_OPTION(len);
21441 +
21442         /* skip the first, the global context */
21443         for (i = 1; i < srv->config_context->used; i++) {
21444                 data_config *dc = (data_config *)srv->config_context->data[i];
21445                 s = p->config_storage[i];
21446 -               
21447 +
21448                 /* condition didn't match */
21449                 if (!config_check_cond(srv, con, dc)) continue;
21450 -               
21451 +
21452                 /* merge config */
21453                 for (j = 0; j < dc->value->used; j++) {
21454                         data_unset *du = dc->value->data[j];
21455 -                       
21456 +
21457                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("evhost.path-pattern"))) {
21458 -                               PATCH(path_pieces);
21459 -                               PATCH(len);
21460 +                               PATCH_OPTION(path_pieces);
21461 +                               PATCH_OPTION(len);
21462                         }
21463                 }
21464         }
21465 -       
21466 +
21467         return 0;
21468  }
21469 -#undef PATCH
21470 -
21471  
21472  static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d) {
21473         plugin_data *p = p_d;
21474 @@ -261,29 +259,29 @@
21475         register char *ptr;
21476         int not_good = 0;
21477         stat_cache_entry *sce = NULL;
21478 -       
21479 +
21480         /* not authority set */
21481         if (con->uri.authority->used == 0) return HANDLER_GO_ON;
21482 -       
21483 +
21484         mod_evhost_patch_connection(srv, con, p);
21485 -       
21486 +
21487         /* missing even default(global) conf */
21488         if (0 == p->conf.len) {
21489                 return HANDLER_GO_ON;
21490         }
21491  
21492         parsed_host = array_init();
21493 -       
21494 +
21495         mod_evhost_parse_host(con, parsed_host);
21496 -       
21497 +
21498         /* build document-root */
21499         buffer_reset(p->tmp_buf);
21500 -       
21501 +
21502         for (i = 0; i < p->conf.len; i++) {
21503                 ptr = p->conf.path_pieces[i]->ptr;
21504                 if (*ptr == '%') {
21505                         data_string *ds;
21506 -                       
21507 +
21508                         if (*(ptr+1) == '%') {
21509                                 /* %% */
21510                                 BUFFER_APPEND_STRING_CONST(p->tmp_buf,"%");
21511 @@ -298,11 +296,11 @@
21512                         buffer_append_string_buffer(p->tmp_buf,p->conf.path_pieces[i]);
21513                 }
21514         }
21515 -       
21516 -       BUFFER_APPEND_SLASH(p->tmp_buf);
21517 -       
21518 +
21519 +       PATHNAME_APPEND_SLASH(p->tmp_buf);
21520 +
21521         array_free(parsed_host);
21522 -       
21523 +
21524         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
21525                 log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
21526                 not_good = 1;
21527 @@ -310,11 +308,11 @@
21528                 log_error_write(srv, __FILE__, __LINE__, "sb", "not a directory:", p->tmp_buf);
21529                 not_good = 1;
21530         }
21531 -       
21532 +
21533         if (!not_good) {
21534                 buffer_copy_string_buffer(con->physical.doc_root, p->tmp_buf);
21535         }
21536 -       
21537 +
21538         return HANDLER_GO_ON;
21539  }
21540  
21541 @@ -325,9 +323,9 @@
21542         p->set_defaults            = mod_evhost_set_defaults;
21543         p->handle_docroot          = mod_evhost_uri_handler;
21544         p->cleanup                 = mod_evhost_free;
21545 -       
21546 +
21547         p->data                    = NULL;
21548 -       
21549 +
21550         return 0;
21551  }
21552  
21553 --- ../lighttpd-1.4.11/src/mod_expire.c 2005-11-03 09:52:13.000000000 +0200
21554 +++ lighttpd-1.4.12/src/mod_expire.c    2006-07-16 00:26:04.000000000 +0300
21555 @@ -12,8 +12,8 @@
21556  #include "stat_cache.h"
21557  
21558  /**
21559 - * this is a expire module for a lighttpd 
21560 - * 
21561 + * this is a expire module for a lighttpd
21562 + *
21563   * set 'Expires:' HTTP Headers on demand
21564   */
21565  
21566 @@ -27,51 +27,51 @@
21567  
21568  typedef struct {
21569         PLUGIN_DATA;
21570 -       
21571 +
21572         buffer *expire_tstmp;
21573 -       
21574 +
21575         plugin_config **config_storage;
21576 -       
21577 -       plugin_config conf; 
21578 +
21579 +       plugin_config conf;
21580  } plugin_data;
21581  
21582  /* init the plugin data */
21583  INIT_FUNC(mod_expire_init) {
21584         plugin_data *p;
21585 -       
21586 +
21587         p = calloc(1, sizeof(*p));
21588 -       
21589 +
21590         p->expire_tstmp = buffer_init();
21591 -       
21592 +
21593         buffer_prepare_copy(p->expire_tstmp, 255);
21594 -       
21595 +
21596         return p;
21597  }
21598  
21599  /* detroy the plugin data */
21600  FREE_FUNC(mod_expire_free) {
21601         plugin_data *p = p_d;
21602 -       
21603 +
21604         UNUSED(srv);
21605  
21606         if (!p) return HANDLER_GO_ON;
21607 -       
21608 +
21609         buffer_free(p->expire_tstmp);
21610 -       
21611 +
21612         if (p->config_storage) {
21613                 size_t i;
21614                 for (i = 0; i < srv->config_context->used; i++) {
21615                         plugin_config *s = p->config_storage[i];
21616 -                       
21617 +
21618                         array_free(s->expire_url);
21619 -                       
21620 +
21621                         free(s);
21622                 }
21623                 free(p->config_storage);
21624         }
21625 -       
21626 +
21627         free(p);
21628 -       
21629 +
21630         return HANDLER_GO_ON;
21631  }
21632  
21633 @@ -79,25 +79,25 @@
21634         char *ts;
21635         int type = -1;
21636         int retts = 0;
21637 -               
21638 +
21639         UNUSED(p);
21640  
21641 -       /* 
21642 +       /*
21643          * parse
21644 -        * 
21645 +        *
21646          * '(access|modification) [plus] {<num> <type>}*'
21647 -        * 
21648 +        *
21649          * e.g. 'access 1 years'
21650          */
21651 -       
21652 +
21653         if (expire->used == 0) {
21654 -               log_error_write(srv, __FILE__, __LINE__, "s", 
21655 +               log_error_write(srv, __FILE__, __LINE__, "s",
21656                                 "empty:");
21657                 return -1;
21658         }
21659 -       
21660 +
21661         ts = expire->ptr;
21662 -       
21663 +
21664         if (0 == strncmp(ts, "access ", 7)) {
21665                 type  = 0;
21666                 ts   += 7;
21667 @@ -110,39 +110,39 @@
21668                                 "invalid <base>:", ts);
21669                 return -1;
21670         }
21671 -       
21672 +
21673         if (0 == strncmp(ts, "plus ", 5)) {
21674                 /* skip the optional plus */
21675                 ts   += 5;
21676         }
21677 -       
21678 +
21679         /* the rest is just <number> (years|months|days|hours|minutes|seconds) */
21680         while (1) {
21681                 char *space, *err;
21682                 int num;
21683 -               
21684 +
21685                 if (NULL == (space = strchr(ts, ' '))) {
21686 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
21687 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
21688                                         "missing space after <num>:", ts);
21689                         return -1;
21690                 }
21691 -               
21692 +
21693                 num = strtol(ts, &err, 10);
21694                 if (*err != ' ') {
21695 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
21696 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
21697                                         "missing <type> after <num>:", ts);
21698                         return -1;
21699                 }
21700 -               
21701 +
21702                 ts = space + 1;
21703 -               
21704 +
21705                 if (NULL != (space = strchr(ts, ' '))) {
21706                         int slen;
21707                         /* */
21708 -                       
21709 +
21710                         slen = space - ts;
21711 -                       
21712 -                       if (slen == 5 && 
21713 +
21714 +                       if (slen == 5 &&
21715                             0 == strncmp(ts, "years", slen)) {
21716                                 num *= 60 * 60 * 24 * 30 * 12;
21717                         } else if (slen == 6 &&
21718 @@ -161,13 +161,13 @@
21719                                    0 == strncmp(ts, "seconds", slen)) {
21720                                 num *= 1;
21721                         } else {
21722 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
21723 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
21724                                                 "unknown type:", ts);
21725                                 return -1;
21726                         }
21727 -                       
21728 +
21729                         retts += num;
21730 -                       
21731 +
21732                         ts = space + 1;
21733                 } else {
21734                         if (0 == strcmp(ts, "years")) {
21735 @@ -183,19 +183,19 @@
21736                         } else if (0 == strcmp(ts, "seconds")) {
21737                                 num *= 1;
21738                         } else {
21739 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
21740 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
21741                                                 "unknown type:", ts);
21742                                 return -1;
21743                         }
21744 -                       
21745 +
21746                         retts += num;
21747 -                       
21748 +
21749                         break;
21750                 }
21751         }
21752 -       
21753 +
21754         if (offset != NULL) *offset = retts;
21755 -       
21756 +
21757         return type;
21758  }
21759  
21760 @@ -205,102 +205,99 @@
21761  SETDEFAULTS_FUNC(mod_expire_set_defaults) {
21762         plugin_data *p = p_d;
21763         size_t i = 0, k;
21764 -       
21765 -       config_values_t cv[] = { 
21766 +
21767 +       config_values_t cv[] = {
21768                 { "expire.url",                 NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
21769                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
21770         };
21771 -       
21772 +
21773         if (!p) return HANDLER_ERROR;
21774 -       
21775 +
21776         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
21777 -       
21778 +
21779         for (i = 0; i < srv->config_context->used; i++) {
21780                 plugin_config *s;
21781 -               
21782 +
21783                 s = calloc(1, sizeof(plugin_config));
21784                 s->expire_url    = array_init();
21785 -               
21786 +
21787                 cv[0].destination = s->expire_url;
21788 -               
21789 +
21790                 p->config_storage[i] = s;
21791 -       
21792 +
21793                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
21794                         return HANDLER_ERROR;
21795                 }
21796 -       
21797 +
21798                 for (k = 0; k < s->expire_url->used; k++) {
21799                         data_string *ds = (data_string *)s->expire_url->data[k];
21800 -                       
21801 +
21802                         /* parse lines */
21803                         if (-1 == mod_expire_get_offset(srv, p, ds->value, NULL)) {
21804 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
21805 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
21806                                                 "parsing expire.url failed:", ds->value);
21807                                 return HANDLER_ERROR;
21808                         }
21809                 }
21810         }
21811 -       
21812 -       
21813 +
21814 +
21815         return HANDLER_GO_ON;
21816  }
21817  
21818 -#define PATCH(x) \
21819 -       p->conf.x = s->x;
21820  static int mod_expire_patch_connection(server *srv, connection *con, plugin_data *p) {
21821         size_t i, j;
21822         plugin_config *s = p->config_storage[0];
21823 -       
21824 -       PATCH(expire_url);
21825 -       
21826 +
21827 +       PATCH_OPTION(expire_url);
21828 +
21829         /* skip the first, the global context */
21830         for (i = 1; i < srv->config_context->used; i++) {
21831                 data_config *dc = (data_config *)srv->config_context->data[i];
21832                 s = p->config_storage[i];
21833 -               
21834 +
21835                 /* condition didn't match */
21836                 if (!config_check_cond(srv, con, dc)) continue;
21837 -               
21838 +
21839                 /* merge config */
21840                 for (j = 0; j < dc->value->used; j++) {
21841                         data_unset *du = dc->value->data[j];
21842 -                       
21843 +
21844                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("expire.url"))) {
21845 -                               PATCH(expire_url);
21846 +                               PATCH_OPTION(expire_url);
21847                         }
21848                 }
21849         }
21850 -       
21851 +
21852         return 0;
21853  }
21854 -#undef PATCH
21855  
21856  URIHANDLER_FUNC(mod_expire_path_handler) {
21857         plugin_data *p = p_d;
21858         int s_len;
21859         size_t k;
21860 -       
21861 +
21862         if (con->uri.path->used == 0) return HANDLER_GO_ON;
21863 -       
21864 +
21865         mod_expire_patch_connection(srv, con, p);
21866 -       
21867 +
21868         s_len = con->uri.path->used - 1;
21869 -       
21870 +
21871         for (k = 0; k < p->conf.expire_url->used; k++) {
21872                 data_string *ds = (data_string *)p->conf.expire_url->data[k];
21873                 int ct_len = ds->key->used - 1;
21874 -               
21875 +
21876                 if (ct_len > s_len) continue;
21877                 if (ds->key->used == 0) continue;
21878 -               
21879 +
21880                 if (0 == strncmp(con->uri.path->ptr, ds->key->ptr, ct_len)) {
21881                         int ts;
21882                         time_t t;
21883                         size_t len;
21884                         stat_cache_entry *sce = NULL;
21885 -               
21886 +
21887                         stat_cache_get_entry(srv, con, con->physical.path, &sce);
21888 -                       
21889 +
21890                         switch(mod_expire_get_offset(srv, p, ds->value, &ts)) {
21891                         case 0:
21892                                 /* access */
21893 @@ -308,38 +305,38 @@
21894                                 break;
21895                         case 1:
21896                                 /* modification */
21897 -                               
21898 +
21899                                 t = (ts + sce->st.st_mtime);
21900                                 break;
21901                         default:
21902                                 /* -1 is handled at parse-time */
21903                                 break;
21904                         }
21905 -                       
21906 -                       
21907 -                       if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1, 
21908 +
21909 +
21910 +                       if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1,
21911                                            "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(t))))) {
21912                                 /* could not set expire header, out of mem */
21913 -                               
21914 +
21915                                 return HANDLER_GO_ON;
21916 -                               
21917 +
21918                         }
21919 -                           
21920 +
21921                         p->expire_tstmp->used = len + 1;
21922 -               
21923 -                       /* HTTP/1.0 */  
21924 +
21925 +                       /* HTTP/1.0 */
21926                         response_header_overwrite(srv, con, CONST_STR_LEN("Expires"), CONST_BUF_LEN(p->expire_tstmp));
21927  
21928 -                       /* HTTP/1.1 */  
21929 +                       /* HTTP/1.1 */
21930                         buffer_copy_string(p->expire_tstmp, "max-age=");
21931                         buffer_append_long(p->expire_tstmp, ts);
21932 -                       
21933 +
21934                         response_header_overwrite(srv, con, CONST_STR_LEN("Cache-Control"), CONST_BUF_LEN(p->expire_tstmp));
21935 -                       
21936 +
21937                         return HANDLER_GO_ON;
21938                 }
21939         }
21940 -       
21941 +
21942         /* not found */
21943         return HANDLER_GO_ON;
21944  }
21945 @@ -349,13 +346,13 @@
21946  int mod_expire_plugin_init(plugin *p) {
21947         p->version     = LIGHTTPD_VERSION_ID;
21948         p->name        = buffer_init_string("expire");
21949 -       
21950 +
21951         p->init        = mod_expire_init;
21952         p->handle_subrequest_start = mod_expire_path_handler;
21953         p->set_defaults  = mod_expire_set_defaults;
21954         p->cleanup     = mod_expire_free;
21955 -       
21956 +
21957         p->data        = NULL;
21958 -       
21959 +
21960         return 0;
21961  }
21962 --- ../lighttpd-1.4.11/src/mod_fastcgi.c        2006-03-09 13:18:39.000000000 +0200
21963 +++ lighttpd-1.4.12/src/mod_fastcgi.c   2006-07-19 20:02:55.000000000 +0300
21964 @@ -1,5 +1,4 @@
21965  #include <sys/types.h>
21966 -#include <unistd.h>
21967  #include <errno.h>
21968  #include <fcntl.h>
21969  #include <string.h>
21970 @@ -18,13 +17,14 @@
21971  #include "connections.h"
21972  #include "response.h"
21973  #include "joblist.h"
21974 +#include "status_counter.h"
21975  
21976  #include "plugin.h"
21977  
21978  #include "inet_ntop_cache.h"
21979  #include "stat_cache.h"
21980  
21981 -#include <fastcgi.h>
21982 +#include "fastcgi.h"
21983  #include <stdio.h>
21984  
21985  #ifdef HAVE_SYS_FILIO_H
21986 @@ -32,7 +32,11 @@
21987  #endif
21988  
21989  #include "sys-socket.h"
21990 +#include "sys-files.h"
21991 +#include "sys-strings.h"
21992 +#include "sys-process.h"
21993  
21994 +#include "http_resp.h"
21995  
21996  #ifndef UNIX_PATH_MAX
21997  # define UNIX_PATH_MAX 108
21998 @@ -45,14 +49,13 @@
21999  #include <sys/wait.h>
22000  #endif
22001  
22002 -
22003  /*
22004 - * 
22005 + *
22006   * TODO:
22007 - * 
22008 + *
22009   * - add timeout for a connect to a non-fastcgi process
22010   *   (use state_timestamp + state)
22011 - * 
22012 + *
22013   */
22014  
22015  typedef struct fcgi_proc {
22016 @@ -61,7 +64,7 @@
22017         unsigned port;  /* config.port + pno */
22018  
22019         buffer *connection_name; /* either tcp:<host>:<port> or unix:<socket> for debuggin purposes */
22020 -       
22021 +
22022         pid_t pid;   /* PID of the spawned process (0 if not spawned locally) */
22023  
22024  
22025 @@ -70,20 +73,20 @@
22026         time_t last_used; /* see idle_timeout */
22027         size_t requests;  /* see max_requests */
22028         struct fcgi_proc *prev, *next; /* see first */
22029 -       
22030 +
22031         time_t disabled_until; /* this proc is disabled until, use something else until than */
22032 -       
22033 +
22034         int is_local;
22035  
22036 -       enum { 
22037 +       enum {
22038                 PROC_STATE_UNSET,    /* init-phase */
22039                 PROC_STATE_RUNNING,  /* alive */
22040 -               PROC_STATE_OVERLOADED, /* listen-queue is full, 
22041 +               PROC_STATE_OVERLOADED, /* listen-queue is full,
22042                                           don't send something to this proc for the next 2 seconds */
22043                 PROC_STATE_DIED_WAIT_FOR_PID, /* */
22044                 PROC_STATE_DIED,     /* marked as dead, should be restarted */
22045                 PROC_STATE_KILLED    /* was killed as we don't have the load anymore */
22046 -       } state; 
22047 +       } state;
22048  } fcgi_proc;
22049  
22050  typedef struct {
22051 @@ -94,20 +97,20 @@
22052          * sorted by lowest load
22053          *
22054          * whenever a job is done move it up in the list
22055 -        * until it is sorted, move it down as soon as the 
22056 +        * until it is sorted, move it down as soon as the
22057          * job is started
22058          */
22059 -       fcgi_proc *first; 
22060 -       fcgi_proc *unused_procs; 
22061 +       fcgi_proc *first;
22062 +       fcgi_proc *unused_procs;
22063  
22064 -       /* 
22065 +       /*
22066          * spawn at least min_procs, at max_procs.
22067          *
22068 -        * as soon as the load of the first entry 
22069 +        * as soon as the load of the first entry
22070          * is max_load_per_proc we spawn a new one
22071 -        * and add it to the first entry and give it 
22072 +        * and add it to the first entry and give it
22073          * the load
22074 -        * 
22075 +        *
22076          */
22077  
22078         unsigned short min_procs;
22079 @@ -119,44 +122,44 @@
22080  
22081         /*
22082          * kick the process from the list if it was not
22083 -        * used for idle_timeout until min_procs is 
22084 +        * used for idle_timeout until min_procs is
22085          * reached. this helps to get the processlist
22086          * small again we had a small peak load.
22087          *
22088          */
22089 -       
22090 +
22091         unsigned short idle_timeout;
22092 -       
22093 +
22094         /*
22095          * time after a disabled remote connection is tried to be re-enabled
22096 -        * 
22097 -        * 
22098 +        *
22099 +        *
22100          */
22101 -       
22102 +
22103         unsigned short disable_time;
22104  
22105         /*
22106          * same fastcgi processes get a little bit larger
22107 -        * than wanted. max_requests_per_proc kills a 
22108 +        * than wanted. max_requests_per_proc kills a
22109          * process after a number of handled requests.
22110          *
22111          */
22112         size_t max_requests_per_proc;
22113 -       
22114 +
22115  
22116         /* config */
22117  
22118 -       /* 
22119 -        * host:port 
22120 +       /*
22121 +        * host:port
22122          *
22123 -        * if host is one of the local IP adresses the 
22124 +        * if host is one of the local IP adresses the
22125          * whole connection is local
22126          *
22127          * if tcp/ip should be used host AND port have
22128 -        * to be specified 
22129 -        * 
22130 -        */ 
22131 -       buffer *host; 
22132 +        * to be specified
22133 +        *
22134 +        */
22135 +       buffer *host;
22136         unsigned short port;
22137  
22138         /*
22139 @@ -169,7 +172,7 @@
22140          */
22141         buffer *unixsocket;
22142  
22143 -       /* if socket is local we can start the fastcgi 
22144 +       /* if socket is local we can start the fastcgi
22145          * process ourself
22146          *
22147          * bin-path is the path to the binary
22148 @@ -177,19 +180,19 @@
22149          * check min_procs and max_procs for the number
22150          * of process to start-up
22151          */
22152 -       buffer *bin_path; 
22153 -       
22154 -       /* bin-path is set bin-environment is taken to 
22155 +       buffer *bin_path;
22156 +
22157 +       /* bin-path is set bin-environment is taken to
22158          * create the environement before starting the
22159          * FastCGI process
22160 -        * 
22161 +        *
22162          */
22163         array *bin_env;
22164 -       
22165 +
22166         array *bin_env_copy;
22167 -       
22168 +
22169         /*
22170 -        * docroot-translation between URL->phys and the 
22171 +        * docroot-translation between URL->phys and the
22172          * remote host
22173          *
22174          * reasons:
22175 @@ -208,7 +211,7 @@
22176         unsigned short mode;
22177  
22178         /*
22179 -        * check_local tell you if the phys file is stat()ed 
22180 +        * check_local tell you if the phys file is stat()ed
22181          * or not. FastCGI doesn't care if the service is
22182          * remote. If the web-server side doesn't contain
22183          * the fastcgi-files we should not stat() for them
22184 @@ -218,11 +221,11 @@
22185  
22186         /*
22187          * append PATH_INFO to SCRIPT_FILENAME
22188 -        * 
22189 +        *
22190          * php needs this if cgi.fix_pathinfo is provied
22191 -        * 
22192 +        *
22193          */
22194 -       
22195 +
22196         unsigned short break_scriptfilename_for_php;
22197  
22198         /*
22199 @@ -231,12 +234,12 @@
22200          *
22201          */
22202         unsigned short allow_xsendfile;
22203 -               
22204 +
22205         ssize_t load; /* replace by host->load */
22206  
22207         size_t max_id; /* corresponds most of the time to
22208         num_procs.
22209 -       
22210 +
22211         only if a process is killed max_id waits for the process itself
22212         to die and decrements its afterwards */
22213  
22214 @@ -245,17 +248,17 @@
22215  
22216  /*
22217   * one extension can have multiple hosts assigned
22218 - * one host can spawn additional processes on the same 
22219 + * one host can spawn additional processes on the same
22220   *   socket (if we control it)
22221   *
22222   * ext -> host -> procs
22223   *    1:n     1:n
22224   *
22225 - * if the fastcgi process is remote that whole goes down 
22226 + * if the fastcgi process is remote that whole goes down
22227   * to
22228   *
22229   * ext -> host -> procs
22230 - *    1:n     1:1 
22231 + *    1:n     1:1
22232   *
22233   * in case of PHP and FCGI_CHILDREN we have again a procs
22234   * but we don't control it directly.
22235 @@ -268,7 +271,7 @@
22236         int note_is_sent;
22237  
22238         fcgi_extension_host **hosts;
22239 -       
22240 +
22241         size_t used;
22242         size_t size;
22243  } fcgi_extension;
22244 @@ -282,10 +285,10 @@
22245  
22246  
22247  typedef struct {
22248 -       fcgi_exts *exts; 
22249 +       fcgi_exts *exts;
22250  
22251         array *ext_mapping;
22252 -       
22253 +
22254         int debug;
22255  } plugin_config;
22256  
22257 @@ -297,7 +300,7 @@
22258  
22259  typedef struct {
22260         char **ptr;
22261 -       
22262 +
22263         size_t size;
22264         size_t used;
22265  } char_array;
22266 @@ -306,55 +309,54 @@
22267  typedef struct {
22268         PLUGIN_DATA;
22269         buffer_uint fcgi_request_id;
22270 -       
22271 +
22272         buffer *fcgi_env;
22273 -       
22274 +
22275         buffer *path;
22276 -       buffer *parse_response;
22277  
22278         buffer *statuskey;
22279 -       
22280 +
22281 +       http_resp *resp;
22282 +
22283         plugin_config **config_storage;
22284 -       
22285 +
22286         plugin_config conf; /* this is only used as long as no handler_ctx is setup */
22287  } plugin_data;
22288  
22289  /* connection specific data */
22290 -typedef enum { 
22291 +typedef enum {
22292         FCGI_STATE_UNSET,
22293 -       FCGI_STATE_INIT, 
22294 -       FCGI_STATE_CONNECT_DELAYED, 
22295 -       FCGI_STATE_PREPARE_WRITE, 
22296 -       FCGI_STATE_WRITE, 
22297 -       FCGI_STATE_READ 
22298 +       FCGI_STATE_INIT,
22299 +       FCGI_STATE_CONNECT_DELAYED,
22300 +       FCGI_STATE_PREPARE_WRITE,
22301 +       FCGI_STATE_WRITE,
22302 +       FCGI_STATE_READ
22303  } fcgi_connection_state_t;
22304  
22305  typedef struct {
22306         fcgi_proc *proc;
22307         fcgi_extension_host *host;
22308         fcgi_extension *ext;
22309 -       
22310 +
22311         fcgi_connection_state_t state;
22312         time_t   state_timestamp;
22313 -       
22314 +
22315         int      reconnects; /* number of reconnect attempts */
22316 -       
22317 -       chunkqueue *rb; /* read queue */
22318 +
22319 +       chunkqueue *rb; /* the raw fcgi read-queue */
22320 +       chunkqueue *http_rb; /* the decoded read-queue for http-parsing */
22321         chunkqueue *wb; /* write queue */
22322 -       
22323 -       buffer   *response_header;
22324 -       
22325 +
22326         size_t    request_id;
22327 -       int       fd;        /* fd to the fastcgi process */
22328 -       int       fde_ndx;   /* index into the fd-event buffer */
22329 +       iosocket *sock;
22330  
22331         pid_t     pid;
22332         int       got_proc;
22333  
22334         int       send_content_body;
22335 -       
22336 +
22337         plugin_config conf;
22338 -       
22339 +
22340         connection *remote_conn;  /* dumb pointer */
22341         plugin_data *plugin_data; /* dumb pointer */
22342  } handler_ctx;
22343 @@ -363,49 +365,6 @@
22344  /* ok, we need a prototype */
22345  static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents);
22346  
22347 -data_integer *status_counter_get_counter(server *srv, const char *s, size_t len) {
22348 -       data_integer *di;
22349 -
22350 -       if (NULL == (di = (data_integer *)array_get_element(srv->status, s))) {
22351 -               /* not found, create it */
22352 -
22353 -               if (NULL == (di = (data_integer *)array_get_unused_element(srv->status, TYPE_INTEGER))) {
22354 -                       di = data_integer_init();
22355 -               }
22356 -               buffer_copy_string_len(di->key, s, len);
22357 -               di->value = 0;
22358 -
22359 -               array_insert_unique(srv->status, (data_unset *)di);
22360 -       }
22361 -       return di;
22362 -}
22363 -
22364 -/* dummies of the statistic framework functions 
22365 - * they will be moved to a statistics.c later */
22366 -int status_counter_inc(server *srv, const char *s, size_t len) {
22367 -       data_integer *di = status_counter_get_counter(srv, s, len);
22368 -
22369 -       di->value++;
22370 -
22371 -       return 0;
22372 -}
22373 -
22374 -int status_counter_dec(server *srv, const char *s, size_t len) {
22375 -       data_integer *di = status_counter_get_counter(srv, s, len);
22376 -
22377 -       if (di->value > 0) di->value--;
22378 -
22379 -       return 0;
22380 -}
22381 -
22382 -int status_counter_set(server *srv, const char *s, size_t len, int val) {
22383 -       data_integer *di = status_counter_get_counter(srv, s, len);
22384 -
22385 -       di->value = val;
22386 -
22387 -       return 0;
22388 -}
22389 -
22390  int fastcgi_status_copy_procname(buffer *b, fcgi_extension_host *host, fcgi_proc *proc) {
22391         buffer_copy_string(b, "fastcgi.backend.");
22392         buffer_append_string_buffer(b, host->id);
22393 @@ -421,7 +380,7 @@
22394  #define CLEAN(x) \
22395         fastcgi_status_copy_procname(b, host, proc); \
22396         buffer_append_string(b, x); \
22397 -       status_counter_set(srv, CONST_BUF_LEN(b), 0);
22398 +       status_counter_set(CONST_BUF_LEN(b), 0);
22399  
22400         CLEAN(".disabled");
22401         CLEAN(".died");
22402 @@ -429,42 +388,39 @@
22403         CLEAN(".connected");
22404         CLEAN(".load");
22405  
22406 -#undef CLEAN   
22407 +#undef CLEAN
22408  
22409  #define CLEAN(x) \
22410         fastcgi_status_copy_procname(b, host, NULL); \
22411         buffer_append_string(b, x); \
22412 -       status_counter_set(srv, CONST_BUF_LEN(b), 0);
22413 +       status_counter_set(CONST_BUF_LEN(b), 0);
22414  
22415         CLEAN(".load");
22416  
22417 -#undef CLEAN   
22418 +#undef CLEAN
22419  
22420         return 0;
22421  }
22422  
22423  static handler_ctx * handler_ctx_init() {
22424         handler_ctx * hctx;
22425 -       
22426 +
22427         hctx = calloc(1, sizeof(*hctx));
22428         assert(hctx);
22429 -       
22430 -       hctx->fde_ndx = -1;
22431 -       
22432 -       hctx->response_header = buffer_init();
22433 -       
22434 +
22435         hctx->request_id = 0;
22436         hctx->state = FCGI_STATE_INIT;
22437         hctx->proc = NULL;
22438 -       
22439 -       hctx->fd = -1;
22440 -       
22441 +
22442 +       hctx->sock = iosocket_init();
22443 +
22444         hctx->reconnects = 0;
22445         hctx->send_content_body = 1;
22446  
22447         hctx->rb = chunkqueue_init();
22448 +       hctx->http_rb = chunkqueue_init();
22449         hctx->wb = chunkqueue_init();
22450 -       
22451 +
22452         return hctx;
22453  }
22454  
22455 @@ -473,12 +429,13 @@
22456                 hctx->host->load--;
22457                 hctx->host = NULL;
22458         }
22459 -       
22460 -       buffer_free(hctx->response_header);
22461  
22462         chunkqueue_free(hctx->rb);
22463 +       chunkqueue_free(hctx->http_rb);
22464         chunkqueue_free(hctx->wb);
22465  
22466 +       iosocket_free(hctx->sock);
22467 +
22468         free(hctx);
22469  }
22470  
22471 @@ -488,21 +445,21 @@
22472         f = calloc(1, sizeof(*f));
22473         f->unixsocket = buffer_init();
22474         f->connection_name = buffer_init();
22475 -       
22476 +
22477         f->prev = NULL;
22478         f->next = NULL;
22479 -       
22480 +
22481         return f;
22482  }
22483  
22484  void fastcgi_process_free(fcgi_proc *f) {
22485         if (!f) return;
22486 -       
22487 +
22488         fastcgi_process_free(f->next);
22489 -       
22490 +
22491         buffer_free(f->unixsocket);
22492         buffer_free(f->connection_name);
22493 -       
22494 +
22495         free(f);
22496  }
22497  
22498 @@ -519,13 +476,13 @@
22499         f->bin_env = array_init();
22500         f->bin_env_copy = array_init();
22501         f->strip_request_uri = buffer_init();
22502 -       
22503 +
22504         return f;
22505  }
22506  
22507  void fastcgi_host_free(fcgi_extension_host *h) {
22508         if (!h) return;
22509 -       
22510 +
22511         buffer_free(h->id);
22512         buffer_free(h->host);
22513         buffer_free(h->unixsocket);
22514 @@ -534,49 +491,49 @@
22515         buffer_free(h->strip_request_uri);
22516         array_free(h->bin_env);
22517         array_free(h->bin_env_copy);
22518 -       
22519 +
22520         fastcgi_process_free(h->first);
22521         fastcgi_process_free(h->unused_procs);
22522 -       
22523 +
22524         free(h);
22525 -       
22526 +
22527  }
22528  
22529  fcgi_exts *fastcgi_extensions_init() {
22530         fcgi_exts *f;
22531  
22532         f = calloc(1, sizeof(*f));
22533 -       
22534 +
22535         return f;
22536  }
22537  
22538  void fastcgi_extensions_free(fcgi_exts *f) {
22539         size_t i;
22540 -       
22541 +
22542         if (!f) return;
22543 -       
22544 +
22545         for (i = 0; i < f->used; i++) {
22546                 fcgi_extension *fe;
22547                 size_t j;
22548 -               
22549 +
22550                 fe = f->exts[i];
22551 -               
22552 +
22553                 for (j = 0; j < fe->used; j++) {
22554                         fcgi_extension_host *h;
22555 -                       
22556 +
22557                         h = fe->hosts[j];
22558 -                       
22559 +
22560                         fastcgi_host_free(h);
22561                 }
22562 -               
22563 +
22564                 buffer_free(fe->key);
22565                 free(fe->hosts);
22566 -               
22567 +
22568                 free(fe);
22569         }
22570 -       
22571 +
22572         free(f->exts);
22573 -       
22574 +
22575         free(f);
22576  }
22577  
22578 @@ -625,24 +582,25 @@
22579                 assert(fe->hosts);
22580         }
22581  
22582 -       fe->hosts[fe->used++] = fh; 
22583 +       fe->hosts[fe->used++] = fh;
22584  
22585         return 0;
22586 -       
22587 +
22588  }
22589  
22590  INIT_FUNC(mod_fastcgi_init) {
22591         plugin_data *p;
22592 -       
22593 +
22594         p = calloc(1, sizeof(*p));
22595 -       
22596 +
22597         p->fcgi_env = buffer_init();
22598 -       
22599 +
22600         p->path = buffer_init();
22601 -       p->parse_response = buffer_init();
22602 +
22603 +       p->resp = http_response_init();
22604  
22605         p->statuskey = buffer_init();
22606 -       
22607 +
22608         return p;
22609  }
22610  
22611 @@ -650,81 +608,82 @@
22612  FREE_FUNC(mod_fastcgi_free) {
22613         plugin_data *p = p_d;
22614         buffer_uint *r = &(p->fcgi_request_id);
22615 -       
22616 +
22617         UNUSED(srv);
22618  
22619         if (r->ptr) free(r->ptr);
22620 -       
22621 +
22622         buffer_free(p->fcgi_env);
22623         buffer_free(p->path);
22624 -       buffer_free(p->parse_response);
22625         buffer_free(p->statuskey);
22626 -       
22627 +
22628 +       http_response_free(p->resp);
22629 +
22630         if (p->config_storage) {
22631                 size_t i, j, n;
22632                 for (i = 0; i < srv->config_context->used; i++) {
22633                         plugin_config *s = p->config_storage[i];
22634                         fcgi_exts *exts;
22635 -                       
22636 +
22637                         if (!s) continue;
22638 -                       
22639 +
22640                         exts = s->exts;
22641  
22642                         for (j = 0; j < exts->used; j++) {
22643                                 fcgi_extension *ex;
22644 -                               
22645 +
22646                                 ex = exts->exts[j];
22647 -                               
22648 +
22649                                 for (n = 0; n < ex->used; n++) {
22650                                         fcgi_proc *proc;
22651                                         fcgi_extension_host *host;
22652 -                                       
22653 +
22654                                         host = ex->hosts[n];
22655 -                                       
22656 +
22657                                         for (proc = host->first; proc; proc = proc->next) {
22658                                                 if (proc->pid != 0) kill(proc->pid, SIGTERM);
22659 -                                               
22660 -                                               if (proc->is_local && 
22661 +
22662 +                                               if (proc->is_local &&
22663                                                     !buffer_is_empty(proc->unixsocket)) {
22664                                                         unlink(proc->unixsocket->ptr);
22665                                                 }
22666                                         }
22667 -                                       
22668 +
22669                                         for (proc = host->unused_procs; proc; proc = proc->next) {
22670                                                 if (proc->pid != 0) kill(proc->pid, SIGTERM);
22671 -                                               
22672 -                                               if (proc->is_local && 
22673 +
22674 +                                               if (proc->is_local &&
22675                                                     !buffer_is_empty(proc->unixsocket)) {
22676                                                         unlink(proc->unixsocket->ptr);
22677                                                 }
22678                                         }
22679                                 }
22680                         }
22681 -                       
22682 +
22683                         fastcgi_extensions_free(s->exts);
22684                         array_free(s->ext_mapping);
22685 -                       
22686 +
22687                         free(s);
22688                 }
22689                 free(p->config_storage);
22690         }
22691 -       
22692 +
22693         free(p);
22694 -       
22695 +
22696         return HANDLER_GO_ON;
22697  }
22698  
22699  static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
22700         char *dst;
22701 -       
22702 +
22703         if (!key || !val) return -1;
22704 -       
22705 +
22706         dst = malloc(key_len + val_len + 3);
22707         memcpy(dst, key, key_len);
22708         dst[key_len] = '=';
22709         /* add the \0 from the value */
22710         memcpy(dst + key_len + 1, val, val_len + 1);
22711 -       
22712 +
22713         if (env->size == 0) {
22714                 env->size = 16;
22715                 env->ptr = malloc(env->size * sizeof(*env->ptr));
22716 @@ -732,9 +691,9 @@
22717                 env->size += 16;
22718                 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
22719         }
22720 -       
22721 +
22722         env->ptr[env->used++] = dst;
22723 -       
22724 +
22725         return 0;
22726  }
22727  
22728 @@ -753,15 +712,15 @@
22729                         if (env->size == 0) {
22730                                 env->size = 16;
22731                                 env->ptr = malloc(env->size * sizeof(*env->ptr));
22732 -                       } else if (env->size == env->used) { 
22733 +                       } else if (env->size == env->used) {
22734                                 env->size += 16;
22735                                 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
22736                         }
22737 -                       
22738 +
22739                         b->ptr[i] = '\0';
22740  
22741                         env->ptr[env->used++] = start;
22742 -                       
22743 +
22744                         start = b->ptr + i + 1;
22745                         break;
22746                 default:
22747 @@ -794,7 +753,7 @@
22748         return 0;
22749  }
22750  
22751 -static int fcgi_spawn_connection(server *srv, 
22752 +static int fcgi_spawn_connection(server *srv,
22753                                  plugin_data *p,
22754                                  fcgi_extension_host *host,
22755                                  fcgi_proc *proc) {
22756 @@ -806,31 +765,27 @@
22757  #endif
22758         struct sockaddr_in fcgi_addr_in;
22759         struct sockaddr *fcgi_addr;
22760 -       
22761 +
22762         socklen_t servlen;
22763 -       
22764 +
22765  #ifndef HAVE_FORK
22766         return -1;
22767  #endif
22768 -       
22769 +
22770         if (p->conf.debug) {
22771                 log_error_write(srv, __FILE__, __LINE__, "sdb",
22772                                 "new proc, socket:", proc->port, proc->unixsocket);
22773         }
22774 -               
22775 +
22776         if (!buffer_is_empty(proc->unixsocket)) {
22777                 memset(&fcgi_addr, 0, sizeof(fcgi_addr));
22778 -               
22779 +
22780  #ifdef HAVE_SYS_UN_H
22781                 fcgi_addr_un.sun_family = AF_UNIX;
22782                 strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
22783 -               
22784 -#ifdef SUN_LEN
22785 +
22786                 servlen = SUN_LEN(&fcgi_addr_un);
22787 -#else
22788 -               /* stevens says: */
22789 -               servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
22790 -#endif
22791 +
22792                 socket_type = AF_UNIX;
22793                 fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
22794  
22795 @@ -844,108 +799,108 @@
22796  #endif
22797         } else {
22798                 fcgi_addr_in.sin_family = AF_INET;
22799 -               
22800 +
22801                 if (buffer_is_empty(host->host)) {
22802                         fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
22803                 } else {
22804                         struct hostent *he;
22805 -                       
22806 +
22807                         /* set a usefull default */
22808                         fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
22809 -                       
22810 -                       
22811 +
22812 +
22813                         if (NULL == (he = gethostbyname(host->host->ptr))) {
22814 -                               log_error_write(srv, __FILE__, __LINE__, 
22815 -                                               "sdb", "gethostbyname failed: ", 
22816 +                               log_error_write(srv, __FILE__, __LINE__,
22817 +                                               "sdb", "gethostbyname failed: ",
22818                                                 h_errno, host->host);
22819                                 return -1;
22820                         }
22821 -                       
22822 +
22823                         if (he->h_addrtype != AF_INET) {
22824                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
22825                                 return -1;
22826                         }
22827 -                       
22828 +
22829                         if (he->h_length != sizeof(struct in_addr)) {
22830                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
22831                                 return -1;
22832                         }
22833 -                       
22834 +
22835                         memcpy(&(fcgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
22836 -                       
22837 +
22838                 }
22839                 fcgi_addr_in.sin_port = htons(proc->port);
22840                 servlen = sizeof(fcgi_addr_in);
22841 -               
22842 +
22843                 socket_type = AF_INET;
22844                 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
22845 -               
22846 +
22847                 buffer_copy_string(proc->connection_name, "tcp:");
22848                 buffer_append_string_buffer(proc->connection_name, host->host);
22849                 buffer_append_string(proc->connection_name, ":");
22850                 buffer_append_long(proc->connection_name, proc->port);
22851         }
22852 -       
22853 +
22854         if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
22855 -               log_error_write(srv, __FILE__, __LINE__, "ss", 
22856 +               log_error_write(srv, __FILE__, __LINE__, "ss",
22857                                 "failed:", strerror(errno));
22858                 return -1;
22859         }
22860 -       
22861 +
22862         if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
22863                 /* server is not up, spawn in  */
22864                 pid_t child;
22865                 int val;
22866 -               
22867 -               if (errno != ENOENT && 
22868 +
22869 +               if (errno != ENOENT &&
22870                     !buffer_is_empty(proc->unixsocket)) {
22871                         unlink(proc->unixsocket->ptr);
22872                 }
22873 -               
22874 +
22875                 close(fcgi_fd);
22876 -               
22877 +
22878                 /* reopen socket */
22879                 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
22880 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
22881 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
22882                                 "socket failed:", strerror(errno));
22883                         return -1;
22884                 }
22885 -               
22886 +
22887                 val = 1;
22888                 if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
22889 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
22890 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
22891                                         "socketsockopt failed:", strerror(errno));
22892                         return -1;
22893                 }
22894 -               
22895 +
22896                 /* create socket */
22897                 if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
22898 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
22899 -                               "bind failed for:", 
22900 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
22901 +                               "bind failed for:",
22902                                 proc->connection_name,
22903                                 strerror(errno));
22904                         return -1;
22905                 }
22906 -               
22907 +
22908                 if (-1 == listen(fcgi_fd, 1024)) {
22909 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
22910 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
22911                                 "listen failed:", strerror(errno));
22912                         return -1;
22913                 }
22914 -               
22915 -#ifdef HAVE_FORK       
22916 +
22917 +#ifndef _WIN32
22918                 switch ((child = fork())) {
22919                 case 0: {
22920                         size_t i = 0;
22921                         char *c;
22922                         char_array env;
22923                         char_array arg;
22924 -                       
22925 +
22926                         /* create environment */
22927                         env.ptr = NULL;
22928                         env.size = 0;
22929                         env.used = 0;
22930 -                       
22931 +
22932                         arg.ptr = NULL;
22933                         arg.size = 0;
22934                         arg.used = 0;
22935 @@ -955,18 +910,18 @@
22936                                 dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
22937                                 close(fcgi_fd);
22938                         }
22939 -                       
22940 +
22941                         /* we don't need the client socket */
22942                         for (i = 3; i < 256; i++) {
22943                                 close(i);
22944                         }
22945 -                       
22946 +
22947                         /* build clean environment */
22948                         if (host->bin_env_copy->used) {
22949                                 for (i = 0; i < host->bin_env_copy->used; i++) {
22950                                         data_string *ds = (data_string *)host->bin_env_copy->data[i];
22951                                         char *ge;
22952 -                                       
22953 +
22954                                         if (NULL != (ge = getenv(ds->value->ptr))) {
22955                                                 env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge));
22956                                         }
22957 @@ -974,39 +929,39 @@
22958                         } else {
22959                                 for (i = 0; environ[i]; i++) {
22960                                         char *eq;
22961 -                                       
22962 +
22963                                         if (NULL != (eq = strchr(environ[i], '='))) {
22964                                                 env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));
22965                                         }
22966                                 }
22967                         }
22968 -                       
22969 +
22970                         /* create environment */
22971                         for (i = 0; i < host->bin_env->used; i++) {
22972                                 data_string *ds = (data_string *)host->bin_env->data[i];
22973 -                               
22974 +
22975                                 env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
22976                         }
22977 -                       
22978 +
22979                         for (i = 0; i < env.used; i++) {
22980                                 /* search for PHP_FCGI_CHILDREN */
22981                                 if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break;
22982                         }
22983 -                       
22984 +
22985                         /* not found, add a default */
22986                         if (i == env.used) {
22987                                 env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1"));
22988                         }
22989 -                       
22990 +
22991                         env.ptr[env.used] = NULL;
22992  
22993                         parse_binpath(&arg, host->bin_path);
22994 -                       
22995 +
22996                         /* chdir into the base of the bin-path,
22997                          * search for the last / */
22998                         if (NULL != (c = strrchr(arg.ptr[0], '/'))) {
22999                                 *c = '\0';
23000 -                       
23001 +
23002                                 /* change to the physical directory */
23003                                 if (-1 == chdir(arg.ptr[0])) {
23004                                         *c = '/';
23005 @@ -1018,12 +973,12 @@
23006  
23007                         /* exec the cgi */
23008                         execve(arg.ptr[0], arg.ptr, env.ptr);
23009 -                       
23010 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
23011 +
23012 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
23013                                         "execve failed for:", host->bin_path, strerror(errno));
23014 -                       
23015 +
23016                         exit(errno);
23017 -                       
23018 +
23019                         break;
23020                 }
23021                 case -1:
23022 @@ -1031,17 +986,17 @@
23023                         break;
23024                 default:
23025                         /* father */
23026 -                       
23027 +
23028                         /* wait */
23029                         select(0, NULL, NULL, NULL, &tv);
23030 -                       
23031 +
23032                         switch (waitpid(child, &status, WNOHANG)) {
23033                         case 0:
23034                                 /* child still running after timeout, good */
23035                                 break;
23036                         case -1:
23037                                 /* no PID found ? should never happen */
23038 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
23039 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
23040                                                 "pid not found:", strerror(errno));
23041                                 return -1;
23042                         default:
23043 @@ -1049,10 +1004,10 @@
23044                                                 "the fastcgi-backend", host->bin_path, "failed to start:");
23045                                 /* the child should not terminate at all */
23046                                 if (WIFEXITED(status)) {
23047 -                                       log_error_write(srv, __FILE__, __LINE__, "sdb", 
23048 -                                                       "child exited with status", 
23049 +                                       log_error_write(srv, __FILE__, __LINE__, "sdb",
23050 +                                                       "child exited with status",
23051                                                         WEXITSTATUS(status), host->bin_path);
23052 -                                       log_error_write(srv, __FILE__, __LINE__, "s", 
23053 +                                       log_error_write(srv, __FILE__, __LINE__, "s",
23054                                                         "if you try do run PHP as FastCGI backend make sure you use the FastCGI enabled version.\n"
23055                                                         "You can find out if it is the right one by executing 'php -v' and it should display '(cgi-fcgi)' "
23056                                                         "in the output, NOT (cgi) NOR (cli)\n"
23057 @@ -1060,8 +1015,8 @@
23058                                         log_error_write(srv, __FILE__, __LINE__, "s",
23059                                                         "If this is PHP on Gentoo add fastcgi to the USE flags");
23060                                 } else if (WIFSIGNALED(status)) {
23061 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
23062 -                                                       "terminated by signal:", 
23063 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
23064 +                                                       "terminated by signal:",
23065                                                         WTERMSIG(status));
23066  
23067                                         if (WTERMSIG(status) == 11) {
23068 @@ -1071,8 +1026,8 @@
23069                                                                 "If this is PHP try to remove the byte-code caches for now and try again.");
23070                                         }
23071                                 } else {
23072 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
23073 -                                                       "child died somehow:", 
23074 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
23075 +                                                       "child died somehow:",
23076                                                         status);
23077                                 }
23078                                 return -1;
23079 @@ -1082,26 +1037,26 @@
23080                         proc->pid = child;
23081                         proc->last_used = srv->cur_ts;
23082                         proc->is_local = 1;
23083 -                                               
23084 +
23085                         break;
23086                 }
23087  #endif
23088         } else {
23089                 proc->is_local = 0;
23090                 proc->pid = 0;
23091 -               
23092 +
23093                 if (p->conf.debug) {
23094                         log_error_write(srv, __FILE__, __LINE__, "sb",
23095                                         "(debug) socket is already used, won't spawn:",
23096                                         proc->connection_name);
23097                 }
23098         }
23099 -       
23100 +
23101         proc->state = PROC_STATE_RUNNING;
23102         host->active_procs++;
23103 -       
23104 +
23105         close(fcgi_fd);
23106 -       
23107 +
23108         return 0;
23109  }
23110  
23111 @@ -1111,93 +1066,93 @@
23112         data_unset *du;
23113         size_t i = 0;
23114         buffer *fcgi_mode = buffer_init();
23115 -       
23116 -       config_values_t cv[] = { 
23117 +
23118 +       config_values_t cv[] = {
23119                 { "fastcgi.server",              NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
23120                 { "fastcgi.debug",               NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
23121                 { "fastcgi.map-extensions",      NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
23122                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
23123         };
23124 -       
23125 +
23126         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
23127 -       
23128 +
23129         for (i = 0; i < srv->config_context->used; i++) {
23130                 plugin_config *s;
23131                 array *ca;
23132 -               
23133 +
23134                 s = malloc(sizeof(plugin_config));
23135                 s->exts          = fastcgi_extensions_init();
23136                 s->debug         = 0;
23137                 s->ext_mapping   = array_init();
23138 -               
23139 +
23140                 cv[0].destination = s->exts;
23141                 cv[1].destination = &(s->debug);
23142                 cv[2].destination = s->ext_mapping;
23143 -               
23144 +
23145                 p->config_storage[i] = s;
23146                 ca = ((data_config *)srv->config_context->data[i])->value;
23147 -       
23148 +
23149                 if (0 != config_insert_values_global(srv, ca, cv)) {
23150                         return HANDLER_ERROR;
23151                 }
23152 -               
23153 -               /* 
23154 +
23155 +               /*
23156                  * <key> = ( ... )
23157                  */
23158 -               
23159 +
23160                 if (NULL != (du = array_get_element(ca, "fastcgi.server"))) {
23161                         size_t j;
23162                         data_array *da = (data_array *)du;
23163 -                       
23164 +
23165                         if (du->type != TYPE_ARRAY) {
23166 -                               log_error_write(srv, __FILE__, __LINE__, "sss", 
23167 +                               log_error_write(srv, __FILE__, __LINE__, "sss",
23168                                                 "unexpected type for key: ", "fastcgi.server", "array of strings");
23169 -                               
23170 +
23171                                 return HANDLER_ERROR;
23172                         }
23173 -                       
23174 -                       
23175 -                       /* 
23176 -                        * fastcgi.server = ( "<ext>" => ( ... ), 
23177 +
23178 +
23179 +                       /*
23180 +                        * fastcgi.server = ( "<ext>" => ( ... ),
23181                          *                    "<ext>" => ( ... ) )
23182                          */
23183 -                       
23184 +
23185                         for (j = 0; j < da->value->used; j++) {
23186                                 size_t n;
23187                                 data_array *da_ext = (data_array *)da->value->data[j];
23188 -                               
23189 +
23190                                 if (da->value->data[j]->type != TYPE_ARRAY) {
23191 -                                       log_error_write(srv, __FILE__, __LINE__, "sssbs", 
23192 -                                                       "unexpected type for key: ", "fastcgi.server", 
23193 +                                       log_error_write(srv, __FILE__, __LINE__, "sssbs",
23194 +                                                       "unexpected type for key: ", "fastcgi.server",
23195                                                         "[", da->value->data[j]->key, "](string)");
23196 -                                       
23197 +
23198                                         return HANDLER_ERROR;
23199                                 }
23200 -                               
23201 -                               /* 
23202 -                                * da_ext->key == name of the extension 
23203 +
23204 +                               /*
23205 +                                * da_ext->key == name of the extension
23206                                  */
23207 -                               
23208 -                               /* 
23209 -                                * fastcgi.server = ( "<ext>" => 
23210 -                                *                     ( "<host>" => ( ... ), 
23211 +
23212 +                               /*
23213 +                                * fastcgi.server = ( "<ext>" =>
23214 +                                *                     ( "<host>" => ( ... ),
23215                                  *                       "<host>" => ( ... )
23216 -                                *                     ), 
23217 +                                *                     ),
23218                                  *                    "<ext>" => ... )
23219                                  */
23220 -                                       
23221 +
23222                                 for (n = 0; n < da_ext->value->used; n++) {
23223                                         data_array *da_host = (data_array *)da_ext->value->data[n];
23224 -                                       
23225 +
23226                                         fcgi_extension_host *host;
23227 -                                       
23228 -                                       config_values_t fcv[] = { 
23229 +
23230 +                                       config_values_t fcv[] = {
23231                                                 { "host",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
23232                                                 { "docroot",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
23233                                                 { "mode",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
23234                                                 { "socket",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
23235                                                 { "bin-path",          NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 4 */
23236 -                                               
23237 +
23238                                                 { "check-local",       NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 5 */
23239                                                 { "port",              NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 6 */
23240                                                 { "min-procs-not-working",         NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 7 this is broken for now */
23241 @@ -1205,28 +1160,28 @@
23242                                                 { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 9 */
23243                                                 { "idle-timeout",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 10 */
23244                                                 { "disable-time",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 11 */
23245 -                                               
23246 +
23247                                                 { "bin-environment",   NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },        /* 12 */
23248                                                 { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },     /* 13 */
23249 -                                               
23250 +
23251                                                 { "broken-scriptfilename", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },  /* 14 */
23252                                                 { "allow-x-send-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 15 */
23253                                                 { "strip-request-uri",  NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 16 */
23254 -                                               
23255 +
23256                                                 { NULL,                NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
23257                                         };
23258 -                                       
23259 +
23260                                         if (da_host->type != TYPE_ARRAY) {
23261 -                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS", 
23262 -                                                               "unexpected type for key:", 
23263 -                                                               "fastcgi.server", 
23264 +                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS",
23265 +                                                               "unexpected type for key:",
23266 +                                                               "fastcgi.server",
23267                                                                 "[", da_host->key, "](string)");
23268 -                                               
23269 +
23270                                                 return HANDLER_ERROR;
23271                                         }
23272 -                                       
23273 +
23274                                         host = fastcgi_host_init();
23275 -                                       
23276 +
23277                                         buffer_copy_string_buffer(host->id, da_host->key);
23278  
23279                                         host->check_local  = 1;
23280 @@ -1238,13 +1193,13 @@
23281                                         host->disable_time = 60;
23282                                         host->break_scriptfilename_for_php = 0;
23283                                         host->allow_xsendfile = 0; /* handle X-LIGHTTPD-send-file */
23284 -                                       
23285 +
23286                                         fcv[0].destination = host->host;
23287                                         fcv[1].destination = host->docroot;
23288                                         fcv[2].destination = fcgi_mode;
23289                                         fcv[3].destination = host->unixsocket;
23290                                         fcv[4].destination = host->bin_path;
23291 -                                       
23292 +
23293                                         fcv[5].destination = &(host->check_local);
23294                                         fcv[6].destination = &(host->port);
23295                                         fcv[7].destination = &(host->min_procs);
23296 @@ -1252,35 +1207,35 @@
23297                                         fcv[9].destination = &(host->max_load_per_proc);
23298                                         fcv[10].destination = &(host->idle_timeout);
23299                                         fcv[11].destination = &(host->disable_time);
23300 -                                       
23301 +
23302                                         fcv[12].destination = host->bin_env;
23303                                         fcv[13].destination = host->bin_env_copy;
23304                                         fcv[14].destination = &(host->break_scriptfilename_for_php);
23305                                         fcv[15].destination = &(host->allow_xsendfile);
23306                                         fcv[16].destination = host->strip_request_uri;
23307 -                                       
23308 +
23309                                         if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
23310                                                 return HANDLER_ERROR;
23311                                         }
23312 -                                                       
23313 -                                       if ((!buffer_is_empty(host->host) || host->port) && 
23314 +
23315 +                                       if ((!buffer_is_empty(host->host) || host->port) &&
23316                                             !buffer_is_empty(host->unixsocket)) {
23317 -                                               log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", 
23318 +                                               log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23319                                                                 "either host/port or socket have to be set in:",
23320 -                                                               da->key, "= (", 
23321 +                                                               da->key, "= (",
23322                                                                 da_ext->key, " => (",
23323                                                                 da_host->key, " ( ...");
23324  
23325                                                 return HANDLER_ERROR;
23326                                         }
23327 -                                       
23328 +
23329                                         if (!buffer_is_empty(host->unixsocket)) {
23330                                                 /* unix domain socket */
23331 -                                               
23332 +
23333                                                 if (host->unixsocket->used > UNIX_PATH_MAX - 2) {
23334 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", 
23335 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23336                                                                         "unixsocket is too long in:",
23337 -                                                                       da->key, "= (", 
23338 +                                                                       da->key, "= (",
23339                                                                         da_ext->key, " => (",
23340                                                                         da_host->key, " ( ...");
23341  
23342 @@ -1288,37 +1243,37 @@
23343                                                 }
23344                                         } else {
23345                                                 /* tcp/ip */
23346 -                                               
23347 -                                               if (buffer_is_empty(host->host) && 
23348 +
23349 +                                               if (buffer_is_empty(host->host) &&
23350                                                     buffer_is_empty(host->bin_path)) {
23351 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", 
23352 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23353                                                                         "host or binpath have to be set in:",
23354 -                                                                       da->key, "= (", 
23355 +                                                                       da->key, "= (",
23356                                                                         da_ext->key, " => (",
23357                                                                         da_host->key, " ( ...");
23358 -                                                       
23359 +
23360                                                         return HANDLER_ERROR;
23361                                                 } else if (host->port == 0) {
23362 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", 
23363 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23364                                                                         "port has to be set in:",
23365 -                                                                       da->key, "= (", 
23366 +                                                                       da->key, "= (",
23367                                                                         da_ext->key, " => (",
23368                                                                         da_host->key, " ( ...");
23369  
23370                                                         return HANDLER_ERROR;
23371                                                 }
23372                                         }
23373 -                                               
23374 -                                       if (!buffer_is_empty(host->bin_path)) { 
23375 +
23376 +                                       if (!buffer_is_empty(host->bin_path)) {
23377                                                 /* a local socket + self spawning */
23378                                                 size_t pno;
23379  
23380                                                 /* HACK:  just to make sure the adaptive spawing is disabled */
23381                                                 host->min_procs = host->max_procs;
23382 -                                               
23383 +
23384                                                 if (host->min_procs > host->max_procs) host->max_procs = host->min_procs;
23385                                                 if (host->max_load_per_proc < 1) host->max_load_per_proc = 0;
23386 -                                               
23387 +
23388                                                 if (s->debug) {
23389                                                         log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
23390                                                                         "--- fastcgi spawning local",
23391 @@ -1328,7 +1283,7 @@
23392                                                                         "\n\tmin-procs:", host->min_procs,
23393                                                                         "\n\tmax-procs:", host->max_procs);
23394                                                 }
23395 -                                               
23396 +
23397                                                 for (pno = 0; pno < host->min_procs; pno++) {
23398                                                         fcgi_proc *proc;
23399  
23400 @@ -1343,7 +1298,7 @@
23401                                                                 buffer_append_string(proc->unixsocket, "-");
23402                                                                 buffer_append_long(proc->unixsocket, pno);
23403                                                         }
23404 -                                                       
23405 +
23406                                                         if (s->debug) {
23407                                                                 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
23408                                                                                 "--- fastcgi spawning",
23409 @@ -1351,7 +1306,7 @@
23410                                                                                 "\n\tsocket", host->unixsocket,
23411                                                                                 "\n\tcurrent:", pno, "/", host->min_procs);
23412                                                         }
23413 -                                                       
23414 +
23415                                                         if (fcgi_spawn_connection(srv, p, host, proc)) {
23416                                                                 log_error_write(srv, __FILE__, __LINE__, "s",
23417                                                                                 "[ERROR]: spawning fcgi failed.");
23418 @@ -1359,35 +1314,35 @@
23419                                                         }
23420  
23421                                                         fastcgi_status_init(srv, p->statuskey, host, proc);
23422 -                                                       
23423 +
23424                                                         proc->next = host->first;
23425                                                         if (host->first)        host->first->prev = proc;
23426 -                                                       
23427 +
23428                                                         host->first = proc;
23429                                                 }
23430                                         } else {
23431                                                 fcgi_proc *proc;
23432 -                                               
23433 +
23434                                                 proc = fastcgi_process_init();
23435                                                 proc->id = host->num_procs++;
23436                                                 host->max_id++;
23437                                                 host->active_procs++;
23438                                                 proc->state = PROC_STATE_RUNNING;
23439 -                                               
23440 +
23441                                                 if (buffer_is_empty(host->unixsocket)) {
23442                                                         proc->port = host->port;
23443                                                 } else {
23444                                                         buffer_copy_string_buffer(proc->unixsocket, host->unixsocket);
23445                                                 }
23446 -                                               
23447 +
23448                                                 fastcgi_status_init(srv, p->statuskey, host, proc);
23449  
23450                                                 host->first = proc;
23451 -                                               
23452 +
23453                                                 host->min_procs = 1;
23454                                                 host->max_procs = 1;
23455                                         }
23456 -                                       
23457 +
23458                                         if (!buffer_is_empty(fcgi_mode)) {
23459                                                 if (strcmp(fcgi_mode->ptr, "responder") == 0) {
23460                                                         host->mode = FCGI_RESPONDER;
23461 @@ -1411,16 +1366,16 @@
23462                         }
23463                 }
23464         }
23465 -       
23466 +
23467         buffer_free(fcgi_mode);
23468 -       
23469 +
23470         return HANDLER_GO_ON;
23471  }
23472  
23473  static int fcgi_set_state(server *srv, handler_ctx *hctx, fcgi_connection_state_t state) {
23474         hctx->state = state;
23475         hctx->state_timestamp = srv->cur_ts;
23476 -       
23477 +
23478         return 0;
23479  }
23480  
23481 @@ -1429,13 +1384,13 @@
23482         size_t m = 0;
23483         size_t i;
23484         buffer_uint *r = &(p->fcgi_request_id);
23485 -       
23486 +
23487         UNUSED(srv);
23488  
23489         for (i = 0; i < r->used; i++) {
23490                 if (r->ptr[i] > m) m = r->ptr[i];
23491         }
23492 -       
23493 +
23494         if (r->size == 0) {
23495                 r->size = 16;
23496                 r->ptr = malloc(sizeof(*r->ptr) * r->size);
23497 @@ -1443,54 +1398,55 @@
23498                 r->size += 16;
23499                 r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
23500         }
23501 -       
23502 +
23503         r->ptr[r->used++] = ++m;
23504 -       
23505 +
23506         return m;
23507  }
23508  
23509  static int fcgi_requestid_del(server *srv, plugin_data *p, size_t request_id) {
23510         size_t i;
23511         buffer_uint *r = &(p->fcgi_request_id);
23512 -       
23513 +
23514         UNUSED(srv);
23515  
23516         for (i = 0; i < r->used; i++) {
23517                 if (r->ptr[i] == request_id) break;
23518         }
23519 -       
23520 +
23521         if (i != r->used) {
23522                 /* found */
23523 -               
23524 +
23525                 if (i != r->used - 1) {
23526                         r->ptr[i] = r->ptr[r->used - 1];
23527                 }
23528                 r->used--;
23529         }
23530 -       
23531 +
23532         return 0;
23533  }
23534  void fcgi_connection_close(server *srv, handler_ctx *hctx) {
23535         plugin_data *p;
23536         connection  *con;
23537 -       
23538 +
23539         if (NULL == hctx) return;
23540 -       
23541 +
23542         p    = hctx->plugin_data;
23543         con  = hctx->remote_conn;
23544 -       
23545 +
23546         if (con->mode != p->id) {
23547 -               WP();
23548                 return;
23549         }
23550 -       
23551 -       if (hctx->fd != -1) {
23552 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
23553 -               fdevent_unregister(srv->ev, hctx->fd);
23554 -               close(hctx->fd);
23555 +
23556 +       if (hctx->sock->fd != -1) {
23557 +               fdevent_event_del(srv->ev, hctx->sock);
23558 +               fdevent_unregister(srv->ev, hctx->sock);
23559 +               closesocket(hctx->sock->fd);
23560 +               hctx->sock->fd = -1;
23561 +
23562                 srv->cur_fds--;
23563         }
23564 -       
23565 +
23566         if (hctx->request_id != 0) {
23567                 fcgi_requestid_del(srv, p, hctx->request_id);
23568         }
23569 @@ -1499,111 +1455,111 @@
23570                 if (hctx->got_proc) {
23571                         /* after the connect the process gets a load */
23572                         hctx->proc->load--;
23573 -                       
23574 -                       status_counter_dec(srv, CONST_STR_LEN("fastcgi.active-requests"));
23575 +
23576 +                       status_counter_dec(CONST_STR_LEN("fastcgi.active-requests"));
23577  
23578                         fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
23579                         buffer_append_string(p->statuskey, ".load");
23580  
23581 -                       status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load);
23582 +                       status_counter_set(CONST_BUF_LEN(p->statuskey), hctx->proc->load);
23583  
23584                         if (p->conf.debug) {
23585                                 log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
23586 -                                               "released proc:", 
23587 -                                               "pid:", hctx->proc->pid, 
23588 -                                               "socket:", hctx->proc->connection_name, 
23589 +                                               "released proc:",
23590 +                                               "pid:", hctx->proc->pid,
23591 +                                               "socket:", hctx->proc->connection_name,
23592                                                 "load:", hctx->proc->load);
23593                         }
23594                 }
23595         }
23596  
23597 -       
23598 +
23599         handler_ctx_free(hctx);
23600 -       con->plugin_ctx[p->id] = NULL;  
23601 +       con->plugin_ctx[p->id] = NULL;
23602  }
23603  
23604  static int fcgi_reconnect(server *srv, handler_ctx *hctx) {
23605         plugin_data *p    = hctx->plugin_data;
23606 -       
23607 -       /* child died 
23608 -        * 
23609 -        * 1. 
23610 -        * 
23611 +
23612 +       /* child died
23613 +        *
23614 +        * 1.
23615 +        *
23616          * connect was ok, connection was accepted
23617          * but the php accept loop checks after the accept if it should die or not.
23618 -        * 
23619 -        * if yes we can only detect it at a write() 
23620 -        * 
23621 +        *
23622 +        * if yes we can only detect it at a write()
23623 +        *
23624          * next step is resetting this attemp and setup a connection again
23625 -        * 
23626 +        *
23627          * if we have more then 5 reconnects for the same request, die
23628 -        * 
23629 -        * 2. 
23630 -        * 
23631 +        *
23632 +        * 2.
23633 +        *
23634          * we have a connection but the child died by some other reason
23635 -        * 
23636 +        *
23637          */
23638  
23639 -       if (hctx->fd != -1) {
23640 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
23641 -               fdevent_unregister(srv->ev, hctx->fd);
23642 -               close(hctx->fd);
23643 +       if (hctx->sock->fd != -1) {
23644 +               fdevent_event_del(srv->ev, hctx->sock);
23645 +               fdevent_unregister(srv->ev, hctx->sock);
23646 +               close(hctx->sock->fd);
23647                 srv->cur_fds--;
23648 -               hctx->fd = -1;
23649 +               hctx->sock->fd = -1;
23650         }
23651 -       
23652 +
23653         fcgi_requestid_del(srv, p, hctx->request_id);
23654 -       
23655 +
23656         fcgi_set_state(srv, hctx, FCGI_STATE_INIT);
23657 -       
23658 +
23659         hctx->request_id = 0;
23660         hctx->reconnects++;
23661 -       
23662 +
23663         if (p->conf.debug > 2) {
23664                 if (hctx->proc) {
23665                         log_error_write(srv, __FILE__, __LINE__, "sdb",
23666 -                                       "release proc for reconnect:", 
23667 +                                       "release proc for reconnect:",
23668                                         hctx->proc->pid, hctx->proc->connection_name);
23669                 } else {
23670                         log_error_write(srv, __FILE__, __LINE__, "sb",
23671 -                                       "release proc for reconnect:", 
23672 +                                       "release proc for reconnect:",
23673                                         hctx->host->unixsocket);
23674                 }
23675         }
23676  
23677 -       if (hctx->proc && hctx->got_proc) {     
23678 +       if (hctx->proc && hctx->got_proc) {
23679                 hctx->proc->load--;
23680         }
23681  
23682         /* perhaps another host gives us more luck */
23683         hctx->host->load--;
23684         hctx->host = NULL;
23685 -       
23686 +
23687         return 0;
23688  }
23689  
23690  
23691  static handler_t fcgi_connection_reset(server *srv, connection *con, void *p_d) {
23692         plugin_data *p = p_d;
23693 -       
23694 +
23695         fcgi_connection_close(srv, con->plugin_ctx[p->id]);
23696 -       
23697 +
23698         return HANDLER_GO_ON;
23699  }
23700  
23701  
23702  static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
23703         size_t len;
23704 -       
23705 +
23706         if (!key || !val) return -1;
23707 -       
23708 +
23709         len = key_len + val_len;
23710 -       
23711 +
23712         len += key_len > 127 ? 4 : 1;
23713         len += val_len > 127 ? 4 : 1;
23714 -       
23715 +
23716         buffer_prepare_append(env, len);
23717 -       
23718 +
23719         if (key_len > 127) {
23720                 env->ptr[env->used++] = ((key_len >> 24) & 0xff) | 0x80;
23721                 env->ptr[env->used++] = (key_len >> 16) & 0xff;
23722 @@ -1612,7 +1568,7 @@
23723         } else {
23724                 env->ptr[env->used++] = (key_len >> 0) & 0xff;
23725         }
23726 -       
23727 +
23728         if (val_len > 127) {
23729                 env->ptr[env->used++] = ((val_len >> 24) & 0xff) | 0x80;
23730                 env->ptr[env->used++] = (val_len >> 16) & 0xff;
23731 @@ -1621,12 +1577,12 @@
23732         } else {
23733                 env->ptr[env->used++] = (val_len >> 0) & 0xff;
23734         }
23735 -       
23736 +
23737         memcpy(env->ptr + env->used, key, key_len);
23738         env->used += key_len;
23739         memcpy(env->ptr + env->used, val, val_len);
23740         env->used += val_len;
23741 -       
23742 +
23743         return 0;
23744  }
23745  
23746 @@ -1639,11 +1595,11 @@
23747         header->contentLengthB1 = (contentLength >> 8) & 0xff;
23748         header->paddingLength = paddingLength;
23749         header->reserved = 0;
23750 -       
23751 +
23752         return 0;
23753  }
23754  /**
23755 - * 
23756 + *
23757   * returns
23758   *   -1 error
23759   *    0 connected
23760 @@ -1665,26 +1621,23 @@
23761         struct sockaddr_un fcgi_addr_un;
23762  #endif
23763         socklen_t servlen;
23764 -       
23765 +
23766         fcgi_extension_host *host = hctx->host;
23767         fcgi_proc *proc   = hctx->proc;
23768 -       int fcgi_fd       = hctx->fd;
23769 -       
23770 +       int fcgi_fd       = hctx->sock->fd;
23771 +
23772         memset(&fcgi_addr, 0, sizeof(fcgi_addr));
23773 -       
23774 +
23775         if (!buffer_is_empty(proc->unixsocket)) {
23776  #ifdef HAVE_SYS_UN_H
23777                 /* use the unix domain socket */
23778                 fcgi_addr_un.sun_family = AF_UNIX;
23779                 strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
23780 -#ifdef SUN_LEN
23781 +
23782                 servlen = SUN_LEN(&fcgi_addr_un);
23783 -#else
23784 -               /* stevens says: */
23785 -               servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
23786 -#endif
23787 +
23788                 fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
23789 -       
23790 +
23791                 if (buffer_is_empty(proc->connection_name)) {
23792                         /* on remote spawing we have to set the connection-name now */
23793                         buffer_copy_string(proc->connection_name, "unix:");
23794 @@ -1695,16 +1648,18 @@
23795  #endif
23796         } else {
23797                 fcgi_addr_in.sin_family = AF_INET;
23798 +
23799                 if (0 == inet_aton(host->host->ptr, &(fcgi_addr_in.sin_addr))) {
23800 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
23801 -                                       "converting IP-adress failed for", host->host, 
23802 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
23803 +                                       "converting IP-adress failed for", host->host,
23804                                         "\nBe sure to specify an IP address here");
23805 -                       
23806 +
23807                         return -1;
23808                 }
23809 +
23810                 fcgi_addr_in.sin_port = htons(proc->port);
23811                 servlen = sizeof(fcgi_addr_in);
23812 -               
23813 +
23814                 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
23815  
23816                 if (buffer_is_empty(proc->connection_name)) {
23817 @@ -1715,20 +1670,20 @@
23818                         buffer_append_long(proc->connection_name, proc->port);
23819                 }
23820         }
23821 -       
23822 +
23823         if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
23824 -               if (errno == EINPROGRESS || 
23825 +               if (errno == EINPROGRESS ||
23826                     errno == EALREADY ||
23827                     errno == EINTR) {
23828                         if (hctx->conf.debug > 2) {
23829 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
23830 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
23831                                         "connect delayed, will continue later:", proc->connection_name);
23832                         }
23833 -                       
23834 +
23835                         return CONNECTION_DELAYED;
23836                 } else if (errno == EAGAIN) {
23837                         if (hctx->conf.debug) {
23838 -                               log_error_write(srv, __FILE__, __LINE__, "sbsd", 
23839 +                               log_error_write(srv, __FILE__, __LINE__, "sbsd",
23840                                         "This means that the you have more incoming requests than your fastcgi-backend can handle in parallel. "
23841                                         "Perhaps it helps to spawn more fastcgi backend or php-children, if not decrease server.max-connections."
23842                                         "The load for this fastcgi backend", proc->connection_name, "is", proc->load);
23843 @@ -1736,8 +1691,8 @@
23844  
23845                         return CONNECTION_OVERLOADED;
23846                 } else {
23847 -                       log_error_write(srv, __FILE__, __LINE__, "sssb", 
23848 -                                       "connect failed:", 
23849 +                       log_error_write(srv, __FILE__, __LINE__, "sssb",
23850 +                                       "connect failed:",
23851                                         strerror(errno), "on",
23852                                         proc->connection_name);
23853  
23854 @@ -1747,7 +1702,7 @@
23855  
23856         hctx->reconnects = 0;
23857         if (hctx->conf.debug > 1) {
23858 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
23859 +               log_error_write(srv, __FILE__, __LINE__, "sd",
23860                                 "connect succeeded: ", fcgi_fd);
23861         }
23862  
23863 @@ -1756,21 +1711,21 @@
23864  
23865  static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
23866         size_t i;
23867 -       
23868 +
23869         for (i = 0; i < con->request.headers->used; i++) {
23870                 data_string *ds;
23871 -               
23872 +
23873                 ds = (data_string *)con->request.headers->data[i];
23874 -               
23875 +
23876                 if (ds->value->used && ds->key->used) {
23877                         size_t j;
23878                         buffer_reset(srv->tmp_buf);
23879 -                       
23880 +
23881                         if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
23882                                 BUFFER_COPY_STRING_CONST(srv->tmp_buf, "HTTP_");
23883                                 srv->tmp_buf->used--;
23884                         }
23885 -                       
23886 +
23887                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
23888                         for (j = 0; j < ds->key->used - 1; j++) {
23889                                 char c = '_';
23890 @@ -1784,20 +1739,20 @@
23891                                 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
23892                         }
23893                         srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
23894 -                       
23895 +
23896                         fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
23897                 }
23898         }
23899 -       
23900 +
23901         for (i = 0; i < con->environment->used; i++) {
23902                 data_string *ds;
23903 -               
23904 +
23905                 ds = (data_string *)con->environment->data[i];
23906 -               
23907 +
23908                 if (ds->value->used && ds->key->used) {
23909                         size_t j;
23910                         buffer_reset(srv->tmp_buf);
23911 -                       
23912 +
23913                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
23914                         for (j = 0; j < ds->key->used - 1; j++) {
23915                                 char c = '_';
23916 @@ -1811,11 +1766,11 @@
23917                                 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
23918                         }
23919                         srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
23920 -                       
23921 +
23922                         fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
23923                 }
23924         }
23925 -       
23926 +
23927         return 0;
23928  }
23929  
23930 @@ -1824,24 +1779,24 @@
23931         FCGI_BeginRequestRecord beginRecord;
23932         FCGI_Header header;
23933         buffer *b;
23934 -       
23935 +
23936         char buf[32];
23937         const char *s;
23938  #ifdef HAVE_IPV6
23939         char b2[INET6_ADDRSTRLEN + 1];
23940  #endif
23941 -       
23942 +
23943         plugin_data *p    = hctx->plugin_data;
23944         fcgi_extension_host *host= hctx->host;
23945  
23946         connection *con   = hctx->remote_conn;
23947         server_socket *srv_sock = con->srv_socket;
23948 -       
23949 +
23950         sock_addr our_addr;
23951         socklen_t our_addr_len;
23952 -       
23953 +
23954         /* send FCGI_BEGIN_REQUEST */
23955 -       
23956 +
23957         fcgi_header(&(beginRecord.header), FCGI_BEGIN_REQUEST, request_id, sizeof(beginRecord.body), 0);
23958         beginRecord.body.roleB0 = host->mode;
23959         beginRecord.body.roleB1 = 0;
23960 @@ -1849,21 +1804,21 @@
23961         memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved));
23962  
23963         b = chunkqueue_get_append_buffer(hctx->wb);
23964 -       
23965 +
23966         buffer_copy_memory(b, (const char *)&beginRecord, sizeof(beginRecord));
23967 -       
23968 +
23969         /* send FCGI_PARAMS */
23970         buffer_prepare_copy(p->fcgi_env, 1024);
23971  
23972  
23973         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
23974 -       
23975 +
23976         if (con->server_name->used) {
23977                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
23978         } else {
23979  #ifdef HAVE_IPV6
23980 -               s = inet_ntop(srv_sock->addr.plain.sa_family, 
23981 -                             srv_sock->addr.plain.sa_family == AF_INET6 ? 
23982 +               s = inet_ntop(srv_sock->addr.plain.sa_family,
23983 +                             srv_sock->addr.plain.sa_family == AF_INET6 ?
23984                               (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
23985                               (const void *) &(srv_sock->addr.ipv4.sin_addr),
23986                               b2, sizeof(b2)-1);
23987 @@ -1872,50 +1827,50 @@
23988  #endif
23989                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
23990         }
23991 -       
23992 +
23993         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
23994 -       
23995 -       ltostr(buf, 
23996 +
23997 +       ltostr(buf,
23998  #ifdef HAVE_IPV6
23999                ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
24000  #else
24001                ntohs(srv_sock->addr.ipv4.sin_port)
24002  #endif
24003                );
24004 -       
24005 +
24006         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
24007 -       
24008 +
24009         /* get the server-side of the connection to the client */
24010         our_addr_len = sizeof(our_addr);
24011 -       
24012 -       if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
24013 +
24014 +       if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
24015                 s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
24016         } else {
24017                 s = inet_ntop_cache_get_ip(srv, &(our_addr));
24018         }
24019         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
24020 -       
24021 -       ltostr(buf, 
24022 +
24023 +       ltostr(buf,
24024  #ifdef HAVE_IPV6
24025                ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
24026  #else
24027                ntohs(con->dst_addr.ipv4.sin_port)
24028  #endif
24029                );
24030 -       
24031 +
24032         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
24033 -       
24034 +
24035         s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
24036         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
24037 -       
24038 +
24039         if (!buffer_is_empty(con->authed_user)) {
24040                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_USER"),
24041                              CONST_BUF_LEN(con->authed_user));
24042         }
24043 -       
24044 +
24045         if (con->request.content_length > 0 && host->mode != FCGI_AUTHORIZER) {
24046                 /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
24047 -               
24048 +
24049                 /* request.content_length < SSIZE_MAX, see request.c */
24050                 ltostr(buf, con->request.content_length);
24051                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
24052 @@ -1930,12 +1885,12 @@
24053                  */
24054  
24055                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
24056 -               
24057 +
24058                 if (!buffer_is_empty(con->request.pathinfo)) {
24059                         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
24060 -                       
24061 +
24062                         /* PATH_TRANSLATED is only defined if PATH_INFO is set */
24063 -                       
24064 +
24065                         if (!buffer_is_empty(host->docroot)) {
24066                                 buffer_copy_string_buffer(p->path, host->docroot);
24067                         } else {
24068 @@ -1957,27 +1912,27 @@
24069          */
24070  
24071         if (!buffer_is_empty(host->docroot)) {
24072 -               /* 
24073 -                * rewrite SCRIPT_FILENAME 
24074 -                * 
24075 +               /*
24076 +                * rewrite SCRIPT_FILENAME
24077 +                *
24078                  */
24079 -               
24080 +
24081                 buffer_copy_string_buffer(p->path, host->docroot);
24082                 buffer_append_string_buffer(p->path, con->uri.path);
24083 -               
24084 +
24085                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
24086                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot));
24087         } else {
24088                 buffer_copy_string_buffer(p->path, con->physical.path);
24089 -               
24090 -               /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself 
24091 -                * 
24092 +
24093 +               /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself
24094 +                *
24095                  * see src/sapi/cgi_main.c, init_request_info()
24096                  */
24097                 if (host->break_scriptfilename_for_php) {
24098                         buffer_append_string_buffer(p->path, con->request.pathinfo);
24099                 }
24100 -               
24101 +
24102                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
24103                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
24104         }
24105 @@ -1987,7 +1942,7 @@
24106                 /**
24107                  * /app1/index/list
24108                  *
24109 -                * stripping /app1 or /app1/ should lead to 
24110 +                * stripping /app1 or /app1/ should lead to
24111                  *
24112                  * /index/list
24113                  *
24114 @@ -2001,7 +1956,7 @@
24115                     0 == strncmp(con->request.orig_uri->ptr, host->strip_request_uri->ptr, host->strip_request_uri->used - 1)) {
24116                         /* the left is the same */
24117  
24118 -                       fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), 
24119 +                       fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"),
24120                                         con->request.orig_uri->ptr + (host->strip_request_uri->used - 2),
24121                                         con->request.orig_uri->used - (host->strip_request_uri->used - 2));
24122                 } else {
24123 @@ -2018,26 +1973,26 @@
24124         } else {
24125                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
24126         }
24127 -       
24128 +
24129         s = get_http_method_name(con->request.http_method);
24130         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
24131         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
24132         s = get_http_version_name(con->request.http_version);
24133         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
24134 -       
24135 +
24136  #ifdef USE_OPENSSL
24137         if (srv_sock->is_ssl) {
24138                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
24139         }
24140  #endif
24141 -       
24142 -       
24143 +
24144 +
24145         fcgi_env_add_request_headers(srv, con, p);
24146 -       
24147 +
24148         fcgi_header(&(header), FCGI_PARAMS, request_id, p->fcgi_env->used, 0);
24149         buffer_append_memory(b, (const char *)&header, sizeof(header));
24150         buffer_append_memory(b, (const char *)p->fcgi_env->ptr, p->fcgi_env->used);
24151 -       
24152 +
24153         fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0);
24154         buffer_append_memory(b, (const char *)&header, sizeof(header));
24155  
24156 @@ -2057,7 +2012,7 @@
24157  
24158                         /* we announce toWrite octects
24159                          * now take all the request_content chunk that we need to fill this request
24160 -                        * */   
24161 +                        * */
24162  
24163                         b = chunkqueue_get_append_buffer(hctx->wb);
24164                         fcgi_header(&(header), FCGI_STDIN, request_id, weWant, 0);
24165 @@ -2080,16 +2035,16 @@
24166                                         if (weHave > weWant - written) weHave = weWant - written;
24167  
24168                                         if (p->conf.debug > 10) {
24169 -                                               fprintf(stderr, "%s.%d: sending %lld bytes from (%lld / %lld) %s\n", 
24170 -                                                               __FILE__, __LINE__, 
24171 -                                                               weHave, 
24172 -                                                               req_c->offset, 
24173 -                                                               req_c->file.length, 
24174 +                                               fprintf(stderr, "%s.%d: sending %lld bytes from (%lld / %lld) %s\n",
24175 +                                                               __FILE__, __LINE__,
24176 +                                                               weHave,
24177 +                                                               req_c->offset,
24178 +                                                               req_c->file.length,
24179                                                                 req_c->file.name->ptr);
24180                                         }
24181  
24182                                         assert(weHave != 0);
24183 -                                       
24184 +
24185                                         chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave);
24186  
24187                                         req_c->offset += weHave;
24188 @@ -2104,7 +2059,7 @@
24189                                          * - we reference the tempfile from the request-content-queue several times
24190                                          *   if the req_c is larger than FCGI_MAX_LENGTH
24191                                          * - we can't simply cleanup the request-content-queue as soon as possible
24192 -                                        *   as it would remove the tempfiles 
24193 +                                        *   as it would remove the tempfiles
24194                                          * - the idea is to 'steal' the tempfiles and attach the is_temp flag to the last
24195                                          *   referencing chunk of the fastcgi-write-queue
24196                                          *
24197 @@ -2141,7 +2096,7 @@
24198                                         req_c->offset += weHave;
24199                                         req_cq->bytes_out += weHave;
24200                                         written += weHave;
24201 -                                       
24202 +
24203                                         hctx->wb->bytes_in += weHave;
24204  
24205                                         if (req_c->offset == req_c->mem->used - 1) {
24206 @@ -2155,12 +2110,12 @@
24207                                         break;
24208                                 }
24209                         }
24210 -                       
24211 +
24212                         b->used++; /* add virtual \0 */
24213                         offset += weWant;
24214                 }
24215         }
24216 -       
24217 +
24218         b = chunkqueue_get_append_buffer(hctx->wb);
24219         /* terminate STDIN */
24220         fcgi_header(&(header), FCGI_STDIN, request_id, 0, 0);
24221 @@ -2175,118 +2130,19 @@
24222                 if ((i+1) % 16 == 0) {
24223                         size_t j;
24224                         for (j = i-15; j <= i; j++) {
24225 -                               fprintf(stderr, "%c", 
24226 +                               fprintf(stderr, "%c",
24227                                         isprint((unsigned char)hctx->write_buffer->ptr[j]) ? hctx->write_buffer->ptr[j] : '.');
24228                         }
24229                         fprintf(stderr, "\n");
24230                 }
24231         }
24232  #endif
24233 -       
24234 -       return 0;
24235 -}
24236  
24237 -static int fcgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
24238 -       char *s, *ns;
24239 -       
24240 -       handler_ctx *hctx = con->plugin_ctx[p->id];
24241 -       fcgi_extension_host *host= hctx->host;
24242 -       
24243 -       UNUSED(srv);
24244 -
24245 -       buffer_copy_string_buffer(p->parse_response, in);
24246 -       
24247 -       /* search for \n */
24248 -       for (s = p->parse_response->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1) {
24249 -               char *key, *value;
24250 -               int key_len;
24251 -               data_string *ds;
24252 -               
24253 -               /* a good day. Someone has read the specs and is sending a \r\n to us */
24254 -               
24255 -               if (ns > p->parse_response->ptr &&
24256 -                   *(ns-1) == '\r') {
24257 -                       *(ns-1) = '\0';
24258 -               }
24259 -               
24260 -               ns[0] = '\0';
24261 -               
24262 -               key = s;
24263 -               if (NULL == (value = strchr(s, ':'))) {
24264 -                       /* we expect: "<key>: <value>\n" */
24265 -                       continue;
24266 -               }
24267 -               
24268 -               key_len = value - key;
24269 -               
24270 -               value++;
24271 -               /* strip WS */
24272 -               while (*value == ' ' || *value == '\t') value++;
24273 -               
24274 -               if (host->mode != FCGI_AUTHORIZER ||
24275 -                   !(con->http_status == 0 ||
24276 -                     con->http_status == 200)) {
24277 -                       /* authorizers shouldn't affect the response headers sent back to the client */
24278 -                       
24279 -                       /* don't forward Status: */
24280 -                       if (0 != strncasecmp(key, "Status", key_len)) {
24281 -                               if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
24282 -                                       ds = data_response_init();
24283 -                               }
24284 -                               buffer_copy_string_len(ds->key, key, key_len);
24285 -                               buffer_copy_string(ds->value, value);
24286 -                               
24287 -                               array_insert_unique(con->response.headers, (data_unset *)ds);
24288 -                       }
24289 -               }
24290 -               
24291 -               switch(key_len) {
24292 -               case 4:
24293 -                       if (0 == strncasecmp(key, "Date", key_len)) {
24294 -                               con->parsed_response |= HTTP_DATE;
24295 -                       }
24296 -                       break;
24297 -               case 6:
24298 -                       if (0 == strncasecmp(key, "Status", key_len)) {
24299 -                               con->http_status = strtol(value, NULL, 10);
24300 -                               con->parsed_response |= HTTP_STATUS;
24301 -                       }
24302 -                       break;
24303 -               case 8:
24304 -                       if (0 == strncasecmp(key, "Location", key_len)) {
24305 -                               con->parsed_response |= HTTP_LOCATION;
24306 -                       }
24307 -                       break;
24308 -               case 10:
24309 -                       if (0 == strncasecmp(key, "Connection", key_len)) {
24310 -                               con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
24311 -                               con->parsed_response |= HTTP_CONNECTION;
24312 -                       }
24313 -                       break;
24314 -               case 14:
24315 -                       if (0 == strncasecmp(key, "Content-Length", key_len)) {
24316 -                               con->response.content_length = strtol(value, NULL, 10);
24317 -                               con->parsed_response |= HTTP_CONTENT_LENGTH;
24318 -                               
24319 -                               if (con->response.content_length < 0) con->response.content_length = 0;
24320 -                       }
24321 -                       break;
24322 -               default:
24323 -                       break;
24324 -               }
24325 -       }
24326 -       
24327 -       /* CGI/1.1 rev 03 - 7.2.1.2 */
24328 -       if ((con->parsed_response & HTTP_LOCATION) &&
24329 -           !(con->parsed_response & HTTP_STATUS)) {
24330 -               con->http_status = 302;
24331 -       }
24332 -       
24333         return 0;
24334  }
24335  
24336  typedef struct {
24337 -       buffer  *b; 
24338 +       buffer  *b;
24339         size_t   len;
24340         int      type;
24341         int      padding;
24342 @@ -2327,9 +2183,9 @@
24343                 return -1;
24344         }
24345  
24346 -       /* we have at least a header, now check how much me have to fetch */ 
24347 +       /* we have at least a header, now check how much me have to fetch */
24348         header = (FCGI_Header *)(packet->b->ptr);
24349 -                       
24350 +
24351         packet->len = (header->contentLengthB0 | (header->contentLengthB1 << 8)) + header->paddingLength;
24352         packet->request_id = (header->requestIdB0 | (header->requestIdB1 << 8));
24353         packet->type = header->type;
24354 @@ -2348,7 +2204,7 @@
24355                         size_t weHave = c->mem->used - c->offset - offset - 1;
24356  
24357                         if (weHave > weWant) weHave = weWant;
24358 -                                               
24359 +
24360                         buffer_append_string_len(packet->b, c->mem->ptr + c->offset + offset, weHave);
24361  
24362                         /* we only skipped the first 8 bytes as they are the fcgi header */
24363 @@ -2380,65 +2236,42 @@
24364         }
24365  
24366         chunkqueue_remove_finished_chunks(hctx->rb);
24367 -       
24368 +
24369         return 0;
24370  }
24371  
24372  static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
24373         int fin = 0;
24374 -       int toread;
24375 -       ssize_t r;
24376 -       
24377 +
24378         plugin_data *p    = hctx->plugin_data;
24379         connection *con   = hctx->remote_conn;
24380 -       int fcgi_fd       = hctx->fd;
24381         fcgi_extension_host *host= hctx->host;
24382         fcgi_proc *proc   = hctx->proc;
24383 -       
24384 -       /* 
24385 -        * check how much we have to read 
24386 -        */
24387 -       if (ioctl(hctx->fd, FIONREAD, &toread)) {
24388 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
24389 -                               "unexpected end-of-file (perhaps the fastcgi process died):",
24390 -                               fcgi_fd);
24391 -               return -1;
24392 -       }
24393 -       
24394 -       /* init read-buffer */
24395 -       
24396 -       if (toread > 0) {
24397 -               buffer *b;
24398 -
24399 -               b = chunkqueue_get_append_buffer(hctx->rb);
24400 -               buffer_prepare_copy(b, toread + 1);
24401 -
24402 -               /* append to read-buffer */
24403 -               if (-1 == (r = read(hctx->fd, b->ptr, toread))) {
24404 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
24405 -                                       "unexpected end-of-file (perhaps the fastcgi process died):",
24406 -                                       fcgi_fd, strerror(errno));
24407 -                       return -1;
24408 -               }
24409 -               
24410 -               /* this should be catched by the b > 0 above */
24411 -               assert(r);
24412 +       handler_t ret;
24413  
24414 -               b->used = r + 1; /* one extra for the fake \0 */
24415 -               b->ptr[b->used - 1] = '\0';
24416 -       } else {
24417 -               log_error_write(srv, __FILE__, __LINE__, "ssdsb", 
24418 -                               "unexpected end-of-file (perhaps the fastcgi process died):",
24419 -                               "pid:", proc->pid,
24420 -                               "socket:", proc->connection_name);
24421 -               
24422 +       /* in case we read nothing, check the return code
24423 +        * if we got something, be happy :)
24424 +        *
24425 +        * Ok, to be honest:
24426 +        * - it is fine to receive a EAGAIN on a second read() call
24427 +        * - it might be fine they we get a con-close on a second read() call */
24428 +       switch(srv->network_backend_read(srv, con, hctx->sock, hctx->rb)) {
24429 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
24430 +               /* a EAGAIN after we read exactly the chunk-size */
24431 +
24432 +               ERROR("%s", "oops, got a EAGAIN even if we just got call for the event, wired");
24433 +               return -1;
24434 +       case NETWORK_STATUS_SUCCESS:
24435 +               break;
24436 +       default:
24437 +               ERROR("reading from fastcgi socket failed (fd=%d)", hctx->sock->fd);
24438                 return -1;
24439         }
24440  
24441         /*
24442          * parse the fastcgi packets and forward the content to the write-queue
24443          *
24444 -        */     
24445 +        */
24446         while (fin == 0) {
24447                 fastcgi_response_packet packet;
24448  
24449 @@ -2454,92 +2287,136 @@
24450  
24451                         /* is the header already finished */
24452                         if (0 == con->file_started) {
24453 -                               char *c;
24454 -                               size_t blen;
24455 -                               data_string *ds;
24456 -                                       
24457 -                               /* search for header terminator 
24458 -                                * 
24459 -                                * if we start with \r\n check if last packet terminated with \r\n
24460 -                                * if we start with \n check if last packet terminated with \n
24461 -                                * search for \r\n\r\n
24462 -                                * search for \n\n
24463 -                                */
24464 -
24465 -                               if (hctx->response_header->used == 0) {
24466 -                                       buffer_copy_string_buffer(hctx->response_header, packet.b);
24467 -                               } else {
24468 -                                       buffer_append_string_buffer(hctx->response_header, packet.b);
24469 -                               }
24470 -
24471 -                               if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\r\n\r\n")))) {
24472 -                                       blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 4;
24473 -                                       hctx->response_header->used = (c - hctx->response_header->ptr) + 3;
24474 -                                       c += 4; /* point the the start of the response */
24475 -                               } else if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\n\n")))) {
24476 -                                       blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 2;
24477 -                                       hctx->response_header->used = c - hctx->response_header->ptr + 2;
24478 -                                       c += 2; /* point the the start of the response */
24479 -                               } else {
24480 -                                       /* no luck, no header found */
24481 +                               int have_content_length = 0;
24482 +                               int need_more = 0;
24483 +                               size_t i;
24484 +
24485 +                               /* append the current packet to the chunk queue */
24486 +                               chunkqueue_append_buffer(hctx->http_rb, packet.b);
24487 +                               http_response_reset(p->resp);
24488 +
24489 +                               switch(http_response_parse_cq(hctx->http_rb, p->resp)) {
24490 +                               case PARSE_ERROR:
24491 +                                       /* parsing the response header failed */
24492 +
24493 +                                       con->http_status = 502; /* Bad Gateway */
24494 +
24495 +                                       return 1;
24496 +                               case PARSE_NEED_MORE:
24497 +                                       need_more = 1;
24498 +                                       break; /* leave the loop */
24499 +                               case PARSE_SUCCESS:
24500                                         break;
24501 +                               default:
24502 +                                       /* should not happen */
24503 +                                       SEGFAULT();
24504                                 }
24505  
24506 -                               /* parse the response header */
24507 -                               fcgi_response_parse(srv, con, p, hctx->response_header);
24508 +                               if (need_more) break;
24509  
24510 -                               con->file_started = 1;
24511 +                               chunkqueue_remove_finished_chunks(hctx->http_rb);
24512 +
24513 +                               con->http_status = p->resp->status;
24514 +                               hctx->send_content_body = 1;
24515  
24516 -                               if (host->mode == FCGI_AUTHORIZER &&
24517 -                                   (con->http_status == 0 ||
24518 -                                    con->http_status == 200)) {
24519 -                                       /* a authorizer with approved the static request, ignore the content here */
24520 -                                       hctx->send_content_body = 0;
24521 -                               }
24522 -
24523 -                               if (host->allow_xsendfile &&
24524 -                                   NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-LIGHTTPD-send-file"))) {
24525 -                                       stat_cache_entry *sce;
24526 -
24527 -                                       if (HANDLER_ERROR != stat_cache_get_entry(srv, con, ds->value, &sce)) {
24528 -                                               /* found */
24529 -
24530 -                                               http_chunk_append_file(srv, con, ds->value, 0, sce->st.st_size);
24531 -                                               hctx->send_content_body = 0; /* ignore the content */
24532 -                                               joblist_append(srv, con);
24533 +                               /* handle the header fields */
24534 +                               if (host->mode == FCGI_AUTHORIZER) {
24535 +                                       /* auth mode is a bit different */
24536 +
24537 +                                       if (con->http_status == 0 ||
24538 +                                           con->http_status == 200) {
24539 +                                               /* a authorizer with approved the static request, ignore the content here */
24540 +                                               hctx->send_content_body = 0;
24541                                         }
24542                                 }
24543  
24544 +                               /* copy the http-headers */
24545 +                               for (i = 0; i < p->resp->headers->used; i++) {
24546 +                                       const char *ign[] = { "Status", NULL };
24547 +                                       size_t j;
24548 +                                       data_string *ds;
24549 +
24550 +                                       data_string *header = (data_string *)p->resp->headers->data[i];
24551 +
24552 +                                       /* ignore all headers in AUTHORIZER mode */
24553 +                                       if (host->mode == FCGI_AUTHORIZER) continue;
24554 +
24555 +                                       /* some headers are ignored by default */
24556 +                                       for (j = 0; ign[j]; j++) {
24557 +                                               if (0 == strcasecmp(ign[j], header->key->ptr)) break;
24558 +                                       }
24559 +                                       if (ign[j]) continue;
24560 +
24561 +                                       if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
24562 +                                               /* CGI/1.1 rev 03 - 7.2.1.2 */
24563 +                                               con->http_status = 302;
24564 +                                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
24565 +                                               have_content_length = 1;
24566 +                                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-Sendfile")) || 
24567 +                                                  0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-LIGHTTPD-send-file"))) {
24568 +                                               
24569 +                                               stat_cache_entry *sce;
24570                                                 
24571 -                               if (hctx->send_content_body && blen > 1) {                                              
24572 -                                       /* enable chunked-transfer-encoding */
24573 +                                               if (host->allow_xsendfile &&
24574 +                                                   HANDLER_ERROR != stat_cache_get_entry(srv, con, header->value, &sce)) {
24575 +                                                       http_chunk_append_file(srv, con, header->value, 0, sce->st.st_size);
24576 +                                                       hctx->send_content_body = 0; /* ignore the content */
24577 +                                       
24578 +                                                       joblist_append(srv, con);
24579 +                                               }
24580 +
24581 +                                               continue; /* ignore header */
24582 +                                       }
24583 +                                       
24584 +                                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
24585 +                                               ds = data_response_init();
24586 +                                       }
24587 +                                       buffer_copy_string_buffer(ds->key, header->key);
24588 +                                       buffer_copy_string_buffer(ds->value, header->value);
24589 +
24590 +                                       array_insert_unique(con->response.headers, (data_unset *)ds);
24591 +                               }
24592 +
24593 +                               /* header is complete ... go on with the body */
24594 +
24595 +                               con->file_started = 1;
24596 +
24597 +                               if (hctx->send_content_body) {
24598 +                                       chunk *c = hctx->http_rb->first;
24599 +
24600 +                                       /* if we don't have a content-length enable chunked encoding 
24601 +                                        * if possible
24602 +                                        * 
24603 +                                        * TODO: move this to a later stage in the filter-queue
24604 +                                        *  */
24605                                         if (con->request.http_version == HTTP_VERSION_1_1 &&
24606 -                                           !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
24607 +                                           !have_content_length) {
24608                                                 con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
24609                                         }
24610  
24611 -                                       http_chunk_append_mem(srv, con, c, blen);
24612 +                                       /* copy the rest of the data */
24613 +                                       for (c = hctx->http_rb->first; c; c = c->next) {
24614 +                                               if (c->mem->used > 1) {
24615 +                                                       http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
24616 +                                                       c->offset = c->mem->used - 1;
24617 +                                               }
24618 +                                       }
24619 +                                       chunkqueue_remove_finished_chunks(hctx->http_rb);
24620                                         joblist_append(srv, con);
24621                                 }
24622                         } else if (hctx->send_content_body && packet.b->used > 1) {
24623 -                               if (con->request.http_version == HTTP_VERSION_1_1 &&
24624 -                                   !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
24625 -                                       /* enable chunked-transfer-encoding */
24626 -                                       con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
24627 -                               }
24628 -
24629                                 http_chunk_append_mem(srv, con, packet.b->ptr, packet.b->used);
24630                                 joblist_append(srv, con);
24631                         }
24632                         break;
24633                 case FCGI_STDERR:
24634 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
24635 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
24636                                         "FastCGI-stderr:", packet.b);
24637 -                       
24638 +
24639                         break;
24640                 case FCGI_END_REQUEST:
24641                         con->file_finished = 1;
24642 -                       
24643 +
24644                         if (host->mode != FCGI_AUTHORIZER ||
24645                             !(con->http_status == 0 ||
24646                               con->http_status == 200)) {
24647 @@ -2547,39 +2424,39 @@
24648                                 http_chunk_append_mem(srv, con, NULL, 0);
24649                                 joblist_append(srv, con);
24650                         }
24651 -                       
24652 +
24653                         fin = 1;
24654                         break;
24655                 default:
24656 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
24657 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
24658                                         "FastCGI: header.type not handled: ", packet.type);
24659                         break;
24660                 }
24661                 buffer_free(packet.b);
24662         }
24663 -       
24664 +
24665         return fin;
24666  }
24667  
24668  static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_host *host) {
24669         fcgi_proc *proc;
24670 -       
24671 +
24672         for (proc = host->first; proc; proc = proc->next) {
24673                 int status;
24674  
24675                 if (p->conf.debug > 2) {
24676 -                       log_error_write(srv, __FILE__, __LINE__,  "sbdddd", 
24677 -                                       "proc:", 
24678 +                       log_error_write(srv, __FILE__, __LINE__,  "sbdddd",
24679 +                                       "proc:",
24680                                         proc->connection_name,
24681                                         proc->state,
24682                                         proc->is_local,
24683                                         proc->load,
24684                                         proc->pid);
24685                 }
24686 -               
24687 -               /* 
24688 +
24689 +               /*
24690                  * if the remote side is overloaded, we check back after <n> seconds
24691 -                * 
24692 +                *
24693                  */
24694                 switch (proc->state) {
24695                 case PROC_STATE_KILLED:
24696 @@ -2592,13 +2469,13 @@
24697                         break;
24698                 case PROC_STATE_OVERLOADED:
24699                         if (srv->cur_ts <= proc->disabled_until) break;
24700 -                       
24701 +
24702                         proc->state = PROC_STATE_RUNNING;
24703                         host->active_procs++;
24704 -                       
24705 -                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", 
24706 -                                       "fcgi-server re-enabled:", 
24707 -                                       host->host, host->port, 
24708 +
24709 +                       log_error_write(srv, __FILE__, __LINE__,  "sbdb",
24710 +                                       "fcgi-server re-enabled:",
24711 +                                       host->host, host->port,
24712                                         host->unixsocket);
24713                         break;
24714                 case PROC_STATE_DIED_WAIT_FOR_PID:
24715 @@ -2606,7 +2483,7 @@
24716                         if (!proc->is_local) break;
24717  
24718                         /* the child should not terminate at all */
24719 -                       
24720 +#ifndef _WIN32
24721                         switch(waitpid(proc->pid, &status, WNOHANG)) {
24722                         case 0:
24723                                 /* child is still alive */
24724 @@ -2616,45 +2493,45 @@
24725                         default:
24726                                 if (WIFEXITED(status)) {
24727  #if 0
24728 -                                       log_error_write(srv, __FILE__, __LINE__, "sdsd", 
24729 +                                       log_error_write(srv, __FILE__, __LINE__, "sdsd",
24730                                                         "child exited, pid:", proc->pid,
24731                                                         "status:", WEXITSTATUS(status));
24732  #endif
24733                                 } else if (WIFSIGNALED(status)) {
24734 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
24735 -                                                       "child signaled:", 
24736 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
24737 +                                                       "child signaled:",
24738                                                         WTERMSIG(status));
24739                                 } else {
24740 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
24741 -                                                       "child died somehow:", 
24742 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
24743 +                                                       "child died somehow:",
24744                                                         status);
24745                                 }
24746 -                               
24747 +
24748                                 proc->state = PROC_STATE_DIED;
24749                                 break;
24750                         }
24751 -
24752 +#endif
24753                         /* fall through if we have a dead proc now */
24754                         if (proc->state != PROC_STATE_DIED) break;
24755  
24756                 case PROC_STATE_DIED:
24757 -                       /* local proc get restarted by us, 
24758 +                       /* local proc get restarted by us,
24759                          * remote ones hopefully by the admin */
24760 -                       
24761 +
24762                         if (proc->is_local) {
24763                                 /* we still have connections bound to this proc,
24764                                  * let them terminate first */
24765                                 if (proc->load != 0) break;
24766 -                       
24767 +
24768                                 /* restart the child */
24769 -                               
24770 +
24771                                 if (p->conf.debug) {
24772                                         log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
24773                                                         "--- fastcgi spawning",
24774                                                         "\n\tsocket", proc->connection_name,
24775                                                         "\n\tcurrent:", 1, "/", host->min_procs);
24776                                 }
24777 -                               
24778 +
24779                                 if (fcgi_spawn_connection(srv, p, host, proc)) {
24780                                         log_error_write(srv, __FILE__, __LINE__, "s",
24781                                                         "ERROR: spawning fcgi failed.");
24782 @@ -2662,18 +2539,18 @@
24783                                 }
24784                         } else {
24785                                 if (srv->cur_ts <= proc->disabled_until) break;
24786 -                       
24787 +
24788                                 proc->state = PROC_STATE_RUNNING;
24789                                 host->active_procs++;
24790 -                       
24791 -                               log_error_write(srv, __FILE__, __LINE__,  "sb", 
24792 -                                               "fcgi-server re-enabled:", 
24793 +
24794 +                               log_error_write(srv, __FILE__, __LINE__,  "sb",
24795 +                                               "fcgi-server re-enabled:",
24796                                                 proc->connection_name);
24797                         }
24798                         break;
24799                 }
24800         }
24801 -       
24802 +
24803         return 0;
24804  }
24805  
24806 @@ -2682,19 +2559,19 @@
24807         fcgi_extension_host *host= hctx->host;
24808         connection *con   = hctx->remote_conn;
24809         fcgi_proc  *proc;
24810 -       
24811 +
24812         int ret;
24813  
24814 -       /* sanity check */      
24815 +       /* sanity check */
24816         if (!host ||
24817             ((!host->host->used || !host->port) && !host->unixsocket->used)) {
24818 -               log_error_write(srv, __FILE__, __LINE__, "sxddd", 
24819 +               log_error_write(srv, __FILE__, __LINE__, "sxddd",
24820                                 "write-req: error",
24821                                 host,
24822                                 host->host->used,
24823                                 host->port,
24824                                 host->unixsocket->used);
24825 -                       
24826 +
24827                 hctx->proc->disabled_until = srv->cur_ts + 10;
24828                 hctx->proc->state = PROC_STATE_DIED;
24829  
24830 @@ -2705,12 +2582,12 @@
24831         if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
24832                 int socket_error;
24833                 socklen_t socket_error_len = sizeof(socket_error);
24834 -                       
24835 +
24836                 /* try to finish the connect() */
24837 -               if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
24838 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
24839 +               if (0 != getsockopt(hctx->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
24840 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
24841                                         "getsockopt failed:", strerror(errno));
24842 -                       
24843 +
24844                         hctx->proc->disabled_until = srv->cur_ts + 10;
24845                         hctx->proc->state = PROC_STATE_DIED;
24846  
24847 @@ -2719,12 +2596,12 @@
24848                 if (socket_error != 0) {
24849                         if (!hctx->proc->is_local || p->conf.debug) {
24850                                 /* local procs get restarted */
24851 -                               
24852 +
24853                                 log_error_write(srv, __FILE__, __LINE__, "sssb",
24854 -                                               "establishing connection failed:", strerror(socket_error), 
24855 +                                               "establishing connection failed:", strerror(socket_error),
24856                                                 "socket:", hctx->proc->connection_name);
24857                         }
24858 -       
24859 +
24860                         hctx->proc->disabled_until = srv->cur_ts + 5;
24861  
24862                         if (hctx->proc->is_local) {
24863 @@ -2732,17 +2609,17 @@
24864                         } else {
24865                                 hctx->proc->state = PROC_STATE_DIED;
24866                         }
24867 -       
24868 +
24869                         hctx->proc->state = PROC_STATE_DIED;
24870 -               
24871 +
24872                         fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
24873                         buffer_append_string(p->statuskey, ".died");
24874  
24875 -                       status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
24876 -               
24877 +                       status_counter_inc(CONST_BUF_LEN(p->statuskey));
24878 +
24879                         return HANDLER_ERROR;
24880                 }
24881 -               /* go on with preparing the request */ 
24882 +               /* go on with preparing the request */
24883                 hctx->state = FCGI_STATE_PREPARE_WRITE;
24884         }
24885  
24886 @@ -2755,14 +2632,14 @@
24887                 /* do we have a running process for this host (max-procs) ? */
24888                 hctx->proc = NULL;
24889  
24890 -               for (proc = hctx->host->first; 
24891 -                    proc && proc->state != PROC_STATE_RUNNING; 
24892 +               for (proc = hctx->host->first;
24893 +                    proc && proc->state != PROC_STATE_RUNNING;
24894                      proc = proc->next);
24895 -                       
24896 +
24897                 /* all childs are dead */
24898                 if (proc == NULL) {
24899 -                       hctx->fde_ndx = -1;
24900 -               
24901 +                       hctx->sock->fde_ndx = -1;
24902 +
24903                         return HANDLER_ERROR;
24904                 }
24905  
24906 @@ -2775,50 +2652,50 @@
24907                 }
24908  
24909                 ret = host->unixsocket->used ? AF_UNIX : AF_INET;
24910 -               
24911 -               if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
24912 +
24913 +               if (-1 == (hctx->sock->fd = socket(ret, SOCK_STREAM, 0))) {
24914                         if (errno == EMFILE ||
24915                             errno == EINTR) {
24916 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
24917 -                                               "wait for fd at connection:", con->fd);
24918 -                               
24919 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
24920 +                                               "wait for fd at connection:", con->sock->fd);
24921 +
24922                                 return HANDLER_WAIT_FOR_FD;
24923                         }
24924 -                       
24925 -                       log_error_write(srv, __FILE__, __LINE__, "ssdd", 
24926 +
24927 +                       log_error_write(srv, __FILE__, __LINE__, "ssdd",
24928                                         "socket failed:", strerror(errno), srv->cur_fds, srv->max_fds);
24929                         return HANDLER_ERROR;
24930                 }
24931 -               hctx->fde_ndx = -1;
24932 -               
24933 +               hctx->sock->fde_ndx = -1;
24934 +
24935                 srv->cur_fds++;
24936 -               
24937 -               fdevent_register(srv->ev, hctx->fd, fcgi_handle_fdevent, hctx);
24938 -               
24939 -               if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
24940 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
24941 +
24942 +               fdevent_register(srv->ev, hctx->sock, fcgi_handle_fdevent, hctx);
24943 +
24944 +               if (-1 == fdevent_fcntl_set(srv->ev, hctx->sock)) {
24945 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
24946                                         "fcntl failed:", strerror(errno));
24947 -                       
24948 +
24949                         return HANDLER_ERROR;
24950                 }
24951 -                       
24952 +
24953                 if (hctx->proc->is_local) {
24954                         hctx->pid = hctx->proc->pid;
24955                 }
24956 -                       
24957 +
24958                 switch (fcgi_establish_connection(srv, hctx)) {
24959                 case CONNECTION_DELAYED:
24960                         /* connection is in progress, wait for an event and call getsockopt() below */
24961 -                       
24962 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
24963 -                       
24964 +
24965 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
24966 +
24967                         fcgi_set_state(srv, hctx, FCGI_STATE_CONNECT_DELAYED);
24968                         return HANDLER_WAIT_FOR_EVENT;
24969                 case CONNECTION_OVERLOADED:
24970                         /* cool down the backend, it is overloaded
24971                          * -> EAGAIN */
24972  
24973 -                       log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
24974 +                       log_error_write(srv, __FILE__, __LINE__, "ssdsd",
24975                                 "backend is overloaded, we disable it for a 2 seconds and send the request to another backend instead:",
24976                                 "reconnects:", hctx->reconnects,
24977                                 "load:", host->load);
24978 @@ -2830,8 +2707,8 @@
24979                         fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
24980                         buffer_append_string(p->statuskey, ".overloaded");
24981  
24982 -                       status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
24983 -                       
24984 +                       status_counter_inc(CONST_BUF_LEN(p->statuskey));
24985 +
24986                         return HANDLER_ERROR;
24987                 case CONNECTION_DEAD:
24988                         /* we got a hard error from the backend like
24989 @@ -2840,67 +2717,67 @@
24990                          *
24991                          * for check if the host is back in 5 seconds
24992                          *  */
24993 -                       
24994 +
24995                         hctx->proc->disabled_until = srv->cur_ts + 5;
24996                         if (hctx->proc->is_local) {
24997                                 hctx->proc->state = PROC_STATE_DIED_WAIT_FOR_PID;
24998                         } else {
24999                                 hctx->proc->state = PROC_STATE_DIED;
25000                         }
25001 -       
25002 -                       log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
25003 +
25004 +                       log_error_write(srv, __FILE__, __LINE__, "ssdsd",
25005                                 "backend died, we disable it for a 5 seconds and send the request to another backend instead:",
25006                                 "reconnects:", hctx->reconnects,
25007                                 "load:", host->load);
25008 -       
25009 +
25010                         fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
25011                         buffer_append_string(p->statuskey, ".died");
25012  
25013 -                       status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
25014 +                       status_counter_inc(CONST_BUF_LEN(p->statuskey));
25015  
25016                         return HANDLER_ERROR;
25017                 case CONNECTION_OK:
25018                         /* everything is ok, go on */
25019  
25020                         fcgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
25021 -                       
25022 +
25023                         break;
25024                 case CONNECTION_UNSET:
25025                         break;
25026                 }
25027 -               
25028 +
25029         case FCGI_STATE_PREPARE_WRITE:
25030                 /* ok, we have the connection */
25031 -               
25032 +
25033                 hctx->proc->load++;
25034                 hctx->proc->last_used = srv->cur_ts;
25035                 hctx->got_proc = 1;
25036 -       
25037 -               status_counter_inc(srv, CONST_STR_LEN("fastcgi.requests"));
25038 -               status_counter_inc(srv, CONST_STR_LEN("fastcgi.active-requests"));
25039 +
25040 +               status_counter_inc(CONST_STR_LEN("fastcgi.requests"));
25041 +               status_counter_inc(CONST_STR_LEN("fastcgi.active-requests"));
25042  
25043                 fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
25044                 buffer_append_string(p->statuskey, ".connected");
25045  
25046 -               status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
25047 +               status_counter_inc(CONST_BUF_LEN(p->statuskey));
25048  
25049                 /* the proc-load */
25050                 fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
25051                 buffer_append_string(p->statuskey, ".load");
25052  
25053 -               status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load);
25054 +               status_counter_set(CONST_BUF_LEN(p->statuskey), hctx->proc->load);
25055  
25056                 /* the host-load */
25057                 fastcgi_status_copy_procname(p->statuskey, hctx->host, NULL);
25058                 buffer_append_string(p->statuskey, ".load");
25059  
25060 -               status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->host->load);
25061 +               status_counter_set(CONST_BUF_LEN(p->statuskey), hctx->host->load);
25062  
25063                 if (p->conf.debug) {
25064                         log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
25065 -                                       "got proc:", 
25066 -                                       "pid:", hctx->proc->pid, 
25067 -                                       "socket:", hctx->proc->connection_name, 
25068 +                                       "got proc:",
25069 +                                       "pid:", hctx->proc->pid,
25070 +                                       "socket:", hctx->proc->connection_name,
25071                                         "load:", hctx->proc->load);
25072                 }
25073  
25074 @@ -2908,74 +2785,75 @@
25075                 if (hctx->request_id == 0) {
25076                         hctx->request_id = fcgi_requestid_new(srv, p);
25077                 } else {
25078 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
25079 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
25080                                         "fcgi-request is already in use:", hctx->request_id);
25081                 }
25082 -               
25083 +
25084                 /* fall through */
25085                 fcgi_create_env(srv, hctx, hctx->request_id);
25086 -               
25087 +
25088                 fcgi_set_state(srv, hctx, FCGI_STATE_WRITE);
25089 -               
25090 +
25091                 /* fall through */
25092         case FCGI_STATE_WRITE:
25093 -               ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); 
25094 +               ret = srv->network_backend_write(srv, con, hctx->sock, hctx->wb);
25095  
25096                 chunkqueue_remove_finished_chunks(hctx->wb);
25097 -               
25098 +
25099                 if (ret < 0) {
25100                         switch(errno) {
25101                         case ENOTCONN:
25102 -                               /* the connection got dropped after accept() 
25103 -                                * 
25104 -                                * this is most of the time a PHP which dies 
25105 +                               /* the connection got dropped after accept()
25106 +                                *
25107 +                                * this is most of the time a PHP which dies
25108                                  * after PHP_FCGI_MAX_REQUESTS
25109 -                                * 
25110 -                                */ 
25111 +                                *
25112 +                                */
25113                                 if (hctx->wb->bytes_out == 0 &&
25114                                     hctx->reconnects < 5) {
25115 -                                       usleep(10000); /* take away the load of the webserver 
25116 -                                                       * to let the php a chance to restart 
25117 +#ifndef _WIN32
25118 +                                       usleep(10000); /* take away the load of the webserver
25119 +                                                       * to let the php a chance to restart
25120                                                         */
25121 -                                       
25122 +#endif
25123                                         fcgi_reconnect(srv, hctx);
25124 -                               
25125 +
25126                                         return HANDLER_WAIT_FOR_FD;
25127                                 }
25128 -                               
25129 +
25130                                 /* not reconnected ... why
25131 -                                * 
25132 +                                *
25133                                  * far@#lighttpd report this for FreeBSD
25134 -                                * 
25135 +                                *
25136                                  */
25137 -                               
25138 -                               log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
25139 +
25140 +                               log_error_write(srv, __FILE__, __LINE__, "ssosd",
25141                                                 "[REPORT ME] connection was dropped after accept(). reconnect() denied:",
25142                                                 "write-offset:", hctx->wb->bytes_out,
25143                                                 "reconnect attempts:", hctx->reconnects);
25144 -                               
25145 +
25146                                 return HANDLER_ERROR;
25147                         case EAGAIN:
25148                         case EINTR:
25149 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
25150 -                               
25151 +                               fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
25152 +
25153                                 return HANDLER_WAIT_FOR_EVENT;
25154                         default:
25155 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", 
25156 +                               log_error_write(srv, __FILE__, __LINE__, "ssd",
25157                                                 "write failed:", strerror(errno), errno);
25158 -                               
25159 +
25160                                 return HANDLER_ERROR;
25161                         }
25162                 }
25163  
25164                 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
25165                         /* we don't need the out event anymore */
25166 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
25167 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
25168 +                       fdevent_event_del(srv->ev, hctx->sock);
25169 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
25170                         fcgi_set_state(srv, hctx, FCGI_STATE_READ);
25171                 } else {
25172 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
25173 -                               
25174 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
25175 +
25176                         return HANDLER_WAIT_FOR_EVENT;
25177                 }
25178  
25179 @@ -2987,7 +2865,7 @@
25180                 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
25181                 return HANDLER_ERROR;
25182         }
25183 -       
25184 +
25185         return HANDLER_WAIT_FOR_EVENT;
25186  }
25187  
25188 @@ -2996,18 +2874,18 @@
25189   * */
25190  SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
25191         plugin_data *p = p_d;
25192 -       
25193 +
25194         handler_ctx *hctx = con->plugin_ctx[p->id];
25195         fcgi_proc *proc;
25196         fcgi_extension_host *host;
25197 -       
25198 +
25199         if (NULL == hctx) return HANDLER_GO_ON;
25200 -       
25201 +
25202         /* not my job */
25203         if (con->mode != p->id) return HANDLER_GO_ON;
25204  
25205         /* we don't have a host yet, choose one
25206 -        * -> this happens in the first round 
25207 +        * -> this happens in the first round
25208          *    and when the host died and we have to select a new one */
25209         if (hctx->host == NULL) {
25210                 size_t k;
25211 @@ -3016,23 +2894,23 @@
25212                 /* get best server */
25213                 for (k = 0, ndx = -1; k < hctx->ext->used; k++) {
25214                         host = hctx->ext->hosts[k];
25215 -               
25216 +
25217                         /* we should have at least one proc that can do something */
25218                         if (host->active_procs == 0) continue;
25219  
25220                         if (used == -1 || host->load < used) {
25221                                 used = host->load;
25222 -                       
25223 +
25224                                 ndx = k;
25225                         }
25226                 }
25227 -       
25228 +
25229                 /* found a server */
25230                 if (ndx == -1) {
25231                         /* all hosts are down */
25232  
25233                         fcgi_connection_close(srv, hctx);
25234 -                       
25235 +
25236                         con->http_status = 500;
25237                         con->mode = DIRECT;
25238  
25239 @@ -3040,16 +2918,16 @@
25240                 }
25241  
25242                 host = hctx->ext->hosts[ndx];
25243 -               
25244 -               /* 
25245 -                * if check-local is disabled, use the uri.path handler 
25246 -                * 
25247 +
25248 +               /*
25249 +                * if check-local is disabled, use the uri.path handler
25250 +                *
25251                  */
25252 -               
25253 +
25254                 /* init handler-context */
25255                 hctx->host = host;
25256  
25257 -               /* we put a connection on this host, move the other new connections to other hosts 
25258 +               /* we put a connection on this host, move the other new connections to other hosts
25259                  *
25260                  * as soon as hctx->host is unassigned, decrease the load again */
25261                 hctx->host->load++;
25262 @@ -3063,7 +2941,7 @@
25263         case HANDLER_ERROR:
25264                 proc = hctx->proc;
25265                 host = hctx->host;
25266 -               
25267 +
25268                 if (hctx->state == FCGI_STATE_INIT ||
25269                     hctx->state == FCGI_STATE_CONNECT_DELAYED) {
25270                         if (proc) host->active_procs--;
25271 @@ -3078,7 +2956,7 @@
25272                                 return HANDLER_WAIT_FOR_FD;
25273                         } else {
25274                                 fcgi_connection_close(srv, hctx);
25275 -                       
25276 +
25277                                 buffer_reset(con->physical.path);
25278                                 con->mode = DIRECT;
25279                                 con->http_status = 500;
25280 @@ -3088,12 +2966,12 @@
25281                         }
25282                 } else {
25283                         fcgi_connection_close(srv, hctx);
25284 -                       
25285 +
25286                         buffer_reset(con->physical.path);
25287                         con->mode = DIRECT;
25288                         con->http_status = 503;
25289                         joblist_append(srv, con); /* really ? */
25290 -                       
25291 +
25292                         return HANDLER_FINISHED;
25293                 }
25294         case HANDLER_WAIT_FOR_EVENT:
25295 @@ -3115,7 +2993,7 @@
25296         handler_ctx *hctx = ctx;
25297         connection  *con  = hctx->remote_conn;
25298         plugin_data *p    = hctx->plugin_data;
25299 -       
25300 +
25301         fcgi_proc *proc   = hctx->proc;
25302         fcgi_extension_host *host= hctx->host;
25303  
25304 @@ -3125,8 +3003,8 @@
25305                 case 0:
25306                         break;
25307                 case 1:
25308 -                       
25309 -                       if (host->mode == FCGI_AUTHORIZER && 
25310 +
25311 +                       if (host->mode == FCGI_AUTHORIZER &&
25312                             (con->http_status == 200 ||
25313                              con->http_status == 0)) {
25314                                 /*
25315 @@ -3136,26 +3014,26 @@
25316                                  */
25317  
25318                                 buffer_copy_string_buffer(con->physical.doc_root, host->docroot);
25319 -                               
25320 +
25321                                 buffer_copy_string_buffer(con->physical.path, host->docroot);
25322                                 buffer_append_string_buffer(con->physical.path, con->uri.path);
25323                                 fcgi_connection_close(srv, hctx);
25324 -                               
25325 +
25326                                 con->mode = DIRECT;
25327                                 con->file_started = 1; /* fcgi_extension won't touch the request afterwards */
25328                         } else {
25329                                 /* we are done */
25330                                 fcgi_connection_close(srv, hctx);
25331                         }
25332 -                       
25333 +
25334                         joblist_append(srv, con);
25335                         return HANDLER_FINISHED;
25336                 case -1:
25337                         if (proc->pid && proc->state != PROC_STATE_DIED) {
25338                                 int status;
25339 -                               
25340 +
25341                                 /* only fetch the zombie if it is not already done */
25342 -                               
25343 +#ifndef _WIN32
25344                                 switch(waitpid(proc->pid, &status, WNOHANG)) {
25345                                 case 0:
25346                                         /* child is still alive */
25347 @@ -3165,60 +3043,61 @@
25348                                 default:
25349                                         /* the child should not terminate at all */
25350                                         if (WIFEXITED(status)) {
25351 -                                               log_error_write(srv, __FILE__, __LINE__, "sdsd", 
25352 +                                               log_error_write(srv, __FILE__, __LINE__, "sdsd",
25353                                                                 "child exited, pid:", proc->pid,
25354                                                                 "status:", WEXITSTATUS(status));
25355                                         } else if (WIFSIGNALED(status)) {
25356 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
25357 -                                                               "child signaled:", 
25358 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
25359 +                                                               "child signaled:",
25360                                                                 WTERMSIG(status));
25361                                         } else {
25362 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
25363 -                                                               "child died somehow:", 
25364 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
25365 +                                                               "child died somehow:",
25366                                                                 status);
25367                                         }
25368 -                                       
25369 +
25370                                         if (p->conf.debug) {
25371                                                 log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
25372                                                                 "--- fastcgi spawning",
25373                                                                 "\n\tsocket", proc->connection_name,
25374                                                                 "\n\tcurrent:", 1, "/", host->min_procs);
25375                                         }
25376 -                                       
25377 +
25378                                         if (fcgi_spawn_connection(srv, p, host, proc)) {
25379                                                 /* respawning failed, retry later */
25380                                                 proc->state = PROC_STATE_DIED;
25381  
25382 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
25383 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
25384                                                                 "respawning failed, will retry later");
25385                                         }
25386 -                                       
25387 +
25388                                         break;
25389                                 }
25390 +#endif
25391                         }
25392  
25393                         if (con->file_started == 0) {
25394                                 /* nothing has been send out yet, try to use another child */
25395 -                               
25396 +
25397                                 if (hctx->wb->bytes_out == 0 &&
25398                                     hctx->reconnects < 5) {
25399                                         fcgi_reconnect(srv, hctx);
25400 -                                       
25401 -                                       log_error_write(srv, __FILE__, __LINE__, "ssbsbs", 
25402 +
25403 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
25404                                                 "response not received, request not sent",
25405 -                                               "on socket:", proc->connection_name, 
25406 +                                               "on socket:", proc->connection_name,
25407                                                 "for", con->uri.path, ", reconnecting");
25408 -                                       
25409 +
25410                                         return HANDLER_WAIT_FOR_FD;
25411                                 }
25412 -                       
25413 -                               log_error_write(srv, __FILE__, __LINE__, "sosbsbs", 
25414 +
25415 +                               log_error_write(srv, __FILE__, __LINE__, "sosbsbs",
25416                                                 "response not received, request sent:", hctx->wb->bytes_out,
25417 -                                               "on socket:", proc->connection_name, 
25418 +                                               "on socket:", proc->connection_name,
25419                                                 "for", con->uri.path, ", closing connection");
25420 -                               
25421 +
25422                                 fcgi_connection_close(srv, hctx);
25423 -                               
25424 +
25425                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
25426                                 buffer_reset(con->physical.path);
25427                                 con->http_status = 500;
25428 @@ -3226,76 +3105,76 @@
25429                         } else {
25430                                 /* response might have been already started, kill the connection */
25431                                 fcgi_connection_close(srv, hctx);
25432 -                               
25433 -                               log_error_write(srv, __FILE__, __LINE__, "ssbsbs", 
25434 +
25435 +                               log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
25436                                                 "response already sent out, but backend returned error",
25437 -                                               "on socket:", proc->connection_name, 
25438 +                                               "on socket:", proc->connection_name,
25439                                                 "for", con->uri.path, ", terminating connection");
25440 -                               
25441 +
25442                                 connection_set_state(srv, con, CON_STATE_ERROR);
25443                         }
25444  
25445                         /* */
25446 -                       
25447 -                       
25448 +
25449 +
25450                         joblist_append(srv, con);
25451                         return HANDLER_FINISHED;
25452                 }
25453         }
25454 -       
25455 +
25456         if (revents & FDEVENT_OUT) {
25457                 if (hctx->state == FCGI_STATE_CONNECT_DELAYED ||
25458                     hctx->state == FCGI_STATE_WRITE) {
25459                         /* we are allowed to send something out
25460 -                        * 
25461 +                        *
25462                          * 1. in a unfinished connect() call
25463                          * 2. in a unfinished write() call (long POST request)
25464                          */
25465                         return mod_fastcgi_handle_subrequest(srv, con, p);
25466                 } else {
25467 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
25468 -                                       "got a FDEVENT_OUT and didn't know why:", 
25469 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
25470 +                                       "got a FDEVENT_OUT and didn't know why:",
25471                                         hctx->state);
25472                 }
25473         }
25474 -       
25475 +
25476         /* perhaps this issue is already handled */
25477         if (revents & FDEVENT_HUP) {
25478                 if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
25479                         /* getoptsock will catch this one (right ?)
25480 -                        * 
25481 -                        * if we are in connect we might get a EINPROGRESS 
25482 -                        * in the first call and a FDEVENT_HUP in the 
25483 +                        *
25484 +                        * if we are in connect we might get a EINPROGRESS
25485 +                        * in the first call and a FDEVENT_HUP in the
25486                          * second round
25487 -                        * 
25488 +                        *
25489                          * FIXME: as it is a bit ugly.
25490 -                        * 
25491 +                        *
25492                          */
25493                         return mod_fastcgi_handle_subrequest(srv, con, p);
25494                 } else if (hctx->state == FCGI_STATE_READ &&
25495                            hctx->proc->port == 0) {
25496                         /* FIXME:
25497 -                        * 
25498 +                        *
25499                          * ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket
25500                          * even if the FCGI_FIN packet is not received yet
25501                          */
25502                 } else {
25503 -                       log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd", 
25504 -                                       "error: unexpected close of fastcgi connection for", 
25505 +                       log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
25506 +                                       "error: unexpected close of fastcgi connection for",
25507                                         con->uri.path,
25508 -                                       "(no fastcgi process on host:", 
25509 +                                       "(no fastcgi process on host:",
25510                                         host->host,
25511 -                                       ", port: ", 
25512 +                                       ", port: ",
25513                                         host->port,
25514                                         " ?)",
25515                                         hctx->state);
25516 -                       
25517 +
25518                         connection_set_state(srv, con, CON_STATE_ERROR);
25519                         fcgi_connection_close(srv, hctx);
25520                         joblist_append(srv, con);
25521                 }
25522         } else if (revents & FDEVENT_ERR) {
25523 -               log_error_write(srv, __FILE__, __LINE__, "s", 
25524 +               log_error_write(srv, __FILE__, __LINE__, "s",
25525                                 "fcgi: got a FDEVENT_ERR. Don't know why.");
25526                 /* kill all connections to the fastcgi process */
25527  
25528 @@ -3304,45 +3183,42 @@
25529                 fcgi_connection_close(srv, hctx);
25530                 joblist_append(srv, con);
25531         }
25532 -       
25533 +
25534         return HANDLER_FINISHED;
25535  }
25536 -#define PATCH(x) \
25537 -       p->conf.x = s->x;
25538 +
25539  static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) {
25540         size_t i, j;
25541         plugin_config *s = p->config_storage[0];
25542 -       
25543 -       PATCH(exts);
25544 -       PATCH(debug);
25545 -       PATCH(ext_mapping);
25546 -       
25547 +
25548 +       PATCH_OPTION(exts);
25549 +       PATCH_OPTION(debug);
25550 +       PATCH_OPTION(ext_mapping);
25551 +
25552         /* skip the first, the global context */
25553         for (i = 1; i < srv->config_context->used; i++) {
25554                 data_config *dc = (data_config *)srv->config_context->data[i];
25555                 s = p->config_storage[i];
25556 -               
25557 +
25558                 /* condition didn't match */
25559                 if (!config_check_cond(srv, con, dc)) continue;
25560 -               
25561 +
25562                 /* merge config */
25563                 for (j = 0; j < dc->value->used; j++) {
25564                         data_unset *du = dc->value->data[j];
25565 -                       
25566 +
25567                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.server"))) {
25568 -                               PATCH(exts);
25569 +                               PATCH_OPTION(exts);
25570                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.debug"))) {
25571 -                               PATCH(debug);
25572 +                               PATCH_OPTION(debug);
25573                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.map-extensions"))) {
25574 -                               PATCH(ext_mapping);
25575 +                               PATCH_OPTION(ext_mapping);
25576                         }
25577                 }
25578         }
25579 -       
25580 +
25581         return 0;
25582  }
25583 -#undef PATCH
25584 -
25585  
25586  static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
25587         plugin_data *p = p_d;
25588 @@ -3351,16 +3227,16 @@
25589         buffer *fn;
25590         fcgi_extension *extension = NULL;
25591         fcgi_extension_host *host = NULL;
25592 -       
25593 +
25594         /* Possibly, we processed already this request */
25595         if (con->file_started == 1) return HANDLER_GO_ON;
25596  
25597         fn = uri_path_handler ? con->uri.path : con->physical.path;
25598  
25599         if (buffer_is_empty(fn)) return HANDLER_GO_ON;
25600 -       
25601 +
25602         s_len = fn->used - 1;
25603 -       
25604 +
25605         fcgi_patch_connection(srv, con, p);
25606  
25607         /* fastcgi.map-extensions maps extensions to existing fastcgi.server entries
25608 @@ -3368,24 +3244,24 @@
25609          * fastcgi.map-extensions = ( ".php3" => ".php" )
25610          *
25611          * fastcgi.server = ( ".php" => ... )
25612 -        * 
25613 +        *
25614          * */
25615  
25616         /* check if extension-mapping matches */
25617         for (k = 0; k < p->conf.ext_mapping->used; k++) {
25618                 data_string *ds = (data_string *)p->conf.ext_mapping->data[k];
25619                 size_t ct_len; /* length of the config entry */
25620 -               
25621 +
25622                 if (ds->key->used == 0) continue;
25623 -               
25624 +
25625                 ct_len = ds->key->used - 1;
25626 -               
25627 +
25628                 if (s_len < ct_len) continue;
25629 -               
25630 +
25631                 /* found a mapping */
25632                 if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
25633                         /* check if we know the extension */
25634 -                       
25635 +
25636                         /* we can reuse k here */
25637                         for (k = 0; k < p->conf.exts->used; k++) {
25638                                 extension = p->conf.exts->exts[k];
25639 @@ -3407,15 +3283,15 @@
25640                 /* check if extension matches */
25641                 for (k = 0; k < p->conf.exts->used; k++) {
25642                         size_t ct_len; /* length of the config entry */
25643 -               
25644 +
25645                         extension = p->conf.exts->exts[k];
25646 -               
25647 +
25648                         if (extension->key->used == 0) continue;
25649 -               
25650 +
25651                         ct_len = extension->key->used - 1;
25652 -               
25653 +
25654                         if (s_len < ct_len) continue;
25655 -               
25656 +
25657                         /* check extension in the form "/fcgi_pattern" */
25658                         if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
25659                                 break;
25660 @@ -3441,10 +3317,10 @@
25661                         continue;
25662                 }
25663  
25664 -               /* we found one host that is alive */ 
25665 +               /* we found one host that is alive */
25666                 break;
25667         }
25668 -       
25669 +
25670         if (!host) {
25671                 /* sorry, we don't have a server alive for this ext */
25672                 buffer_reset(con->physical.path);
25673 @@ -3459,72 +3335,72 @@
25674                                         "on", extension->key,
25675                                         "are down.");
25676                 }
25677 -               
25678 +
25679                 return HANDLER_FINISHED;
25680         }
25681  
25682         /* a note about no handler is not sent yey */
25683         extension->note_is_sent = 0;
25684  
25685 -       /* 
25686 -        * if check-local is disabled, use the uri.path handler 
25687 -        * 
25688 +       /*
25689 +        * if check-local is disabled, use the uri.path handler
25690 +        *
25691          */
25692 -       
25693 +
25694         /* init handler-context */
25695         if (uri_path_handler) {
25696                 if (host->check_local == 0) {
25697                         handler_ctx *hctx;
25698                         char *pathinfo;
25699 -                       
25700 +
25701                         hctx = handler_ctx_init();
25702 -                       
25703 +
25704                         hctx->remote_conn      = con;
25705                         hctx->plugin_data      = p;
25706                         hctx->proc             = NULL;
25707                         hctx->ext              = extension;
25708 -       
25709 +
25710  
25711                         hctx->conf.exts        = p->conf.exts;
25712                         hctx->conf.debug       = p->conf.debug;
25713 -                               
25714 +
25715                         con->plugin_ctx[p->id] = hctx;
25716 -                               
25717 +
25718                         con->mode = p->id;
25719 -                               
25720 +
25721                         if (con->conf.log_request_handling) {
25722 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
25723 +                               log_error_write(srv, __FILE__, __LINE__, "s",
25724                                 "handling it in mod_fastcgi");
25725                         }
25726 -                               
25727 -                       /* the prefix is the SCRIPT_NAME, 
25728 +
25729 +                       /* the prefix is the SCRIPT_NAME,
25730                          * everthing from start to the next slash
25731                          * this is important for check-local = "disable"
25732 -                        * 
25733 +                        *
25734                          * if prefix = /admin.fcgi
25735 -                        * 
25736 +                        *
25737                          * /admin.fcgi/foo/bar
25738 -                        * 
25739 +                        *
25740                          * SCRIPT_NAME = /admin.fcgi
25741                          * PATH_INFO   = /foo/bar
25742 -                        * 
25743 +                        *
25744                          * if prefix = /fcgi-bin/
25745 -                        * 
25746 +                        *
25747                          * /fcgi-bin/foo/bar
25748 -                        * 
25749 +                        *
25750                          * SCRIPT_NAME = /fcgi-bin/foo
25751                          * PATH_INFO   = /bar
25752 -                        * 
25753 +                        *
25754                          */
25755 -                       
25756 +
25757                         /* the rewrite is only done for /prefix/? matches */
25758                         if (extension->key->ptr[0] == '/' &&
25759                             con->uri.path->used > extension->key->used &&
25760                             NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
25761 -                               /* rewrite uri.path and pathinfo */ 
25762 -                               
25763 +                               /* rewrite uri.path and pathinfo */
25764 +
25765                                 buffer_copy_string(con->request.pathinfo, pathinfo);
25766 -                               
25767 +
25768                                 con->uri.path->used -= con->request.pathinfo->used - 1;
25769                                 con->uri.path->ptr[con->uri.path->used - 1] = '\0';
25770                         }
25771 @@ -3532,19 +3408,19 @@
25772         } else {
25773                 handler_ctx *hctx;
25774                 hctx = handler_ctx_init();
25775 -               
25776 +
25777                 hctx->remote_conn      = con;
25778                 hctx->plugin_data      = p;
25779                 hctx->proc             = NULL;
25780                 hctx->ext              = extension;
25781 -               
25782 +
25783                 hctx->conf.exts        = p->conf.exts;
25784                 hctx->conf.debug       = p->conf.debug;
25785 -               
25786 +
25787                 con->plugin_ctx[p->id] = hctx;
25788 -               
25789 +
25790                 con->mode = p->id;
25791 -               
25792 +
25793                 if (con->conf.log_request_handling) {
25794                         log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
25795                 }
25796 @@ -3566,19 +3442,19 @@
25797  JOBLIST_FUNC(mod_fastcgi_handle_joblist) {
25798         plugin_data *p = p_d;
25799         handler_ctx *hctx = con->plugin_ctx[p->id];
25800 -       
25801 +
25802         if (hctx == NULL) return HANDLER_GO_ON;
25803  
25804 -       if (hctx->fd != -1) {
25805 +       if (hctx->sock->fd != -1) {
25806                 switch (hctx->state) {
25807                 case FCGI_STATE_READ:
25808 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
25809 -                       
25810 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
25811 +
25812                         break;
25813                 case FCGI_STATE_CONNECT_DELAYED:
25814                 case FCGI_STATE_WRITE:
25815 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
25816 -                       
25817 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
25818 +
25819                         break;
25820                 case FCGI_STATE_INIT:
25821                         /* at reconnect */
25822 @@ -3595,7 +3471,7 @@
25823  
25824  static handler_t fcgi_connection_close_callback(server *srv, connection *con, void *p_d) {
25825         plugin_data *p = p_d;
25826 -       
25827 +
25828         fcgi_connection_close(srv, con->plugin_ctx[p->id]);
25829  
25830         return HANDLER_GO_ON;
25831 @@ -3604,16 +3480,39 @@
25832  TRIGGER_FUNC(mod_fastcgi_handle_trigger) {
25833         plugin_data *p = p_d;
25834         size_t i, j, n;
25835 -       
25836 -       
25837 +
25838 +
25839         /* perhaps we should kill a connect attempt after 10-15 seconds
25840 -        * 
25841 +        *
25842          * currently we wait for the TCP timeout which is on Linux 180 seconds
25843 -        * 
25844 -        * 
25845 -        * 
25846 +        *
25847          */
25848  
25849 +       for (i = 0; i < srv->conns->used; i++) {
25850 +               connection *con = srv->conns->ptr[i];
25851 +               handler_ctx *hctx = con->plugin_ctx[p->id];
25852 +
25853 +               /* if a connection is ours and is in handle-req for more than max-request-time
25854 +                * kill the connection */
25855 +
25856 +               if (con->mode != p->id) continue;
25857 +               if (con->state != CON_STATE_HANDLE_REQUEST) continue;
25858 +               if (srv->cur_ts < con->request_start + 60) continue;
25859 +
25860 +               /* the request is waiting for a FCGI_STDOUT since 60 seconds */
25861 +
25862 +               /* kill the connection */
25863 +
25864 +               log_error_write(srv, __FILE__, __LINE__, "s", "fastcgi backend didn't responded after 60 seconds");
25865 +
25866 +               fcgi_connection_close(srv, hctx);
25867 +
25868 +               con->mode = DIRECT;
25869 +               con->http_status = 500;
25870 +
25871 +               joblist_append(srv, con);
25872 +       }
25873 +
25874         /* check all childs if they are still up */
25875  
25876         for (i = 0; i < srv->config_context->used; i++) {
25877 @@ -3628,45 +3527,45 @@
25878                         fcgi_extension *ex;
25879  
25880                         ex = exts->exts[j];
25881 -                       
25882 +
25883                         for (n = 0; n < ex->used; n++) {
25884 -                               
25885 +
25886                                 fcgi_proc *proc;
25887                                 unsigned long sum_load = 0;
25888                                 fcgi_extension_host *host;
25889 -                               
25890 +
25891                                 host = ex->hosts[n];
25892 -                               
25893 +
25894                                 fcgi_restart_dead_procs(srv, p, host);
25895 -                               
25896 +
25897                                 for (proc = host->first; proc; proc = proc->next) {
25898                                         sum_load += proc->load;
25899                                 }
25900 -                               
25901 +
25902                                 if (host->num_procs &&
25903                                     host->num_procs < host->max_procs &&
25904                                     (sum_load / host->num_procs) > host->max_load_per_proc) {
25905                                         /* overload, spawn new child */
25906                                         if (p->conf.debug) {
25907 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
25908 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
25909                                                                 "overload detected, spawning a new child");
25910                                         }
25911 -                                       
25912 +
25913                                         for (proc = host->unused_procs; proc && proc->pid != 0; proc = proc->next);
25914 -                                       
25915 +
25916                                         if (proc) {
25917                                                 if (proc == host->unused_procs) host->unused_procs = proc->next;
25918 -                                               
25919 +
25920                                                 if (proc->next) proc->next->prev = NULL;
25921 -                                               
25922 +
25923                                                 host->max_id++;
25924                                         } else {
25925                                                 proc = fastcgi_process_init();
25926                                                 proc->id = host->max_id++;
25927                                         }
25928 -                                       
25929 +
25930                                         host->num_procs++;
25931 -                                       
25932 +
25933                                         if (buffer_is_empty(host->unixsocket)) {
25934                                                 proc->port = host->port + proc->id;
25935                                         } else {
25936 @@ -3674,13 +3573,13 @@
25937                                                 buffer_append_string(proc->unixsocket, "-");
25938                                                 buffer_append_long(proc->unixsocket, proc->id);
25939                                         }
25940 -                                       
25941 +
25942                                         if (fcgi_spawn_connection(srv, p, host, proc)) {
25943                                                 log_error_write(srv, __FILE__, __LINE__, "s",
25944                                                                 "ERROR: spawning fcgi failed.");
25945                                                 return HANDLER_ERROR;
25946                                         }
25947 -                                       
25948 +
25949                                         proc->prev = NULL;
25950                                         proc->next = host->first;
25951                                         if (host->first) {
25952 @@ -3688,56 +3587,56 @@
25953                                         }
25954                                         host->first = proc;
25955                                 }
25956 -                               
25957 +
25958                                 for (proc = host->first; proc; proc = proc->next) {
25959                                         if (proc->load != 0) break;
25960                                         if (host->num_procs <= host->min_procs) break;
25961                                         if (proc->pid == 0) continue;
25962 -                                       
25963 +
25964                                         if (srv->cur_ts - proc->last_used > host->idle_timeout) {
25965                                                 /* a proc is idling for a long time now,
25966                                                  * terminated it */
25967 -                                               
25968 +
25969                                                 if (p->conf.debug) {
25970 -                                                       log_error_write(srv, __FILE__, __LINE__, "ssbsd", 
25971 -                                                                       "idle-timeout reached, terminating child:", 
25972 -                                                                       "socket:", proc->connection_name, 
25973 +                                                       log_error_write(srv, __FILE__, __LINE__, "ssbsd",
25974 +                                                                       "idle-timeout reached, terminating child:",
25975 +                                                                       "socket:", proc->connection_name,
25976                                                                         "pid", proc->pid);
25977                                                 }
25978 -                                               
25979 -                                               
25980 +
25981 +
25982                                                 if (proc->next) proc->next->prev = proc->prev;
25983                                                 if (proc->prev) proc->prev->next = proc->next;
25984 -                                               
25985 +
25986                                                 if (proc->prev == NULL) host->first = proc->next;
25987 -                                               
25988 +
25989                                                 proc->prev = NULL;
25990                                                 proc->next = host->unused_procs;
25991 -                                               
25992 +
25993                                                 if (host->unused_procs) host->unused_procs->prev = proc;
25994                                                 host->unused_procs = proc;
25995 -                                               
25996 +
25997                                                 kill(proc->pid, SIGTERM);
25998 -                                               
25999 +
26000                                                 proc->state = PROC_STATE_KILLED;
26001 -                                               
26002 -                                               log_error_write(srv, __FILE__, __LINE__, "ssbsd", 
26003 -                                                                       "killed:", 
26004 -                                                                       "socket:", proc->connection_name, 
26005 +
26006 +                                               log_error_write(srv, __FILE__, __LINE__, "ssbsd",
26007 +                                                                       "killed:",
26008 +                                                                       "socket:", proc->connection_name,
26009                                                                         "pid", proc->pid);
26010 -                                               
26011 +
26012                                                 host->num_procs--;
26013 -                                               
26014 +
26015                                                 /* proc is now in unused, let the next second handle the next process */
26016                                                 break;
26017 -                                       }       
26018 +                                       }
26019                                 }
26020 -                               
26021 +
26022                                 for (proc = host->unused_procs; proc; proc = proc->next) {
26023                                         int status;
26024 -                                       
26025 +
26026                                         if (proc->pid == 0) continue;
26027 -                                       
26028 +#ifndef _WIN32
26029                                         switch (waitpid(proc->pid, &status, WNOHANG)) {
26030                                         case 0:
26031                                                 /* child still running after timeout, good */
26032 @@ -3745,10 +3644,10 @@
26033                                         case -1:
26034                                                 if (errno != EINTR) {
26035                                                         /* no PID found ? should never happen */
26036 -                                                       log_error_write(srv, __FILE__, __LINE__, "sddss", 
26037 +                                                       log_error_write(srv, __FILE__, __LINE__, "sddss",
26038                                                                         "pid ", proc->pid, proc->state,
26039                                                                         "not found:", strerror(errno));
26040 -                                                       
26041 +
26042  #if 0
26043                                                         if (errno == ECHILD) {
26044                                                                 /* someone else has cleaned up for us */
26045 @@ -3762,25 +3661,26 @@
26046                                                 /* the child should not terminate at all */
26047                                                 if (WIFEXITED(status)) {
26048                                                         if (proc->state != PROC_STATE_KILLED) {
26049 -                                                               log_error_write(srv, __FILE__, __LINE__, "sdb", 
26050 -                                                                               "child exited:", 
26051 +                                                               log_error_write(srv, __FILE__, __LINE__, "sdb",
26052 +                                                                               "child exited:",
26053                                                                                 WEXITSTATUS(status), proc->connection_name);
26054                                                         }
26055                                                 } else if (WIFSIGNALED(status)) {
26056                                                         if (WTERMSIG(status) != SIGTERM) {
26057 -                                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
26058 -                                                                               "child signaled:", 
26059 +                                                               log_error_write(srv, __FILE__, __LINE__, "sd",
26060 +                                                                               "child signaled:",
26061                                                                                 WTERMSIG(status));
26062                                                         }
26063                                                 } else {
26064 -                                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
26065 -                                                                       "child died somehow:", 
26066 +                                                       log_error_write(srv, __FILE__, __LINE__, "sd",
26067 +                                                                       "child died somehow:",
26068                                                                         status);
26069                                                 }
26070                                                 proc->pid = 0;
26071                                                 proc->state = PROC_STATE_UNSET;
26072                                                 host->max_id--;
26073                                         }
26074 +#endif
26075                                 }
26076                         }
26077                 }
26078 @@ -3804,8 +3704,8 @@
26079         p->handle_subrequest       = mod_fastcgi_handle_subrequest;
26080         p->handle_joblist          = mod_fastcgi_handle_joblist;
26081         p->handle_trigger          = mod_fastcgi_handle_trigger;
26082 -       
26083 +
26084         p->data         = NULL;
26085 -       
26086 +
26087         return 0;
26088  }
26089 --- ../lighttpd-1.4.11/src/mod_flv_streaming.c  2006-03-07 14:06:26.000000000 +0200
26090 +++ lighttpd-1.4.12/src/mod_flv_streaming.c     2006-07-16 00:26:04.000000000 +0300
26091 @@ -23,35 +23,35 @@
26092  
26093  typedef struct {
26094         PLUGIN_DATA;
26095 -       
26096 +
26097         buffer *query_str;
26098         array *get_params;
26099 -       
26100 +
26101         plugin_config **config_storage;
26102 -       
26103 -       plugin_config conf; 
26104 +
26105 +       plugin_config conf;
26106  } plugin_data;
26107  
26108  /* init the plugin data */
26109  INIT_FUNC(mod_flv_streaming_init) {
26110         plugin_data *p;
26111 -       
26112 +
26113         p = calloc(1, sizeof(*p));
26114 -       
26115 +
26116         p->query_str = buffer_init();
26117         p->get_params = array_init();
26118 -       
26119 +
26120         return p;
26121  }
26122  
26123  /* detroy the plugin data */
26124  FREE_FUNC(mod_flv_streaming_free) {
26125         plugin_data *p = p_d;
26126 -       
26127 +
26128         UNUSED(srv);
26129  
26130         if (!p) return HANDLER_GO_ON;
26131 -       
26132 +
26133         if (p->config_storage) {
26134                 size_t i;
26135  
26136 @@ -59,19 +59,19 @@
26137                         plugin_config *s = p->config_storage[i];
26138  
26139                         if (!s) continue;
26140 -                       
26141 +
26142                         array_free(s->extensions);
26143 -                       
26144 +
26145                         free(s);
26146                 }
26147                 free(p->config_storage);
26148         }
26149 -       
26150 +
26151         buffer_free(p->query_str);
26152         array_free(p->get_params);
26153 -       
26154 +
26155         free(p);
26156 -       
26157 +
26158         return HANDLER_GO_ON;
26159  }
26160  
26161 @@ -80,83 +80,80 @@
26162  SETDEFAULTS_FUNC(mod_flv_streaming_set_defaults) {
26163         plugin_data *p = p_d;
26164         size_t i = 0;
26165 -       
26166 -       config_values_t cv[] = { 
26167 +
26168 +       config_values_t cv[] = {
26169                 { "flv-streaming.extensions",   NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
26170                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
26171         };
26172 -       
26173 +
26174         if (!p) return HANDLER_ERROR;
26175 -       
26176 +
26177         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
26178 -       
26179 +
26180         for (i = 0; i < srv->config_context->used; i++) {
26181                 plugin_config *s;
26182 -               
26183 +
26184                 s = calloc(1, sizeof(plugin_config));
26185                 s->extensions     = array_init();
26186 -               
26187 +
26188                 cv[0].destination = s->extensions;
26189 -               
26190 +
26191                 p->config_storage[i] = s;
26192 -       
26193 +
26194                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
26195                         return HANDLER_ERROR;
26196                 }
26197         }
26198 -       
26199 +
26200         return HANDLER_GO_ON;
26201  }
26202  
26203 -#define PATCH(x) \
26204 -       p->conf.x = s->x;
26205  static int mod_flv_streaming_patch_connection(server *srv, connection *con, plugin_data *p) {
26206         size_t i, j;
26207         plugin_config *s = p->config_storage[0];
26208 -       
26209 -       PATCH(extensions);
26210 -       
26211 +
26212 +       PATCH_OPTION(extensions);
26213 +
26214         /* skip the first, the global context */
26215         for (i = 1; i < srv->config_context->used; i++) {
26216                 data_config *dc = (data_config *)srv->config_context->data[i];
26217                 s = p->config_storage[i];
26218 -               
26219 +
26220                 /* condition didn't match */
26221                 if (!config_check_cond(srv, con, dc)) continue;
26222 -               
26223 +
26224                 /* merge config */
26225                 for (j = 0; j < dc->value->used; j++) {
26226                         data_unset *du = dc->value->data[j];
26227 -                       
26228 +
26229                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("flv-streaming.extensions"))) {
26230 -                               PATCH(extensions);
26231 +                               PATCH_OPTION(extensions);
26232                         }
26233                 }
26234         }
26235 -       
26236 +
26237         return 0;
26238  }
26239 -#undef PATCH
26240  
26241 -static int split_get_params(server *srv, connection *con, array *get_params, buffer *qrystr) {
26242 +static int split_get_params(array *get_params, buffer *qrystr) {
26243         size_t is_key = 1;
26244         size_t i;
26245         char *key = NULL, *val = NULL;
26246 -       
26247 +
26248         key = qrystr->ptr;
26249 -       
26250 +
26251         /* we need the \0 */
26252         for (i = 0; i < qrystr->used; i++) {
26253                 switch(qrystr->ptr[i]) {
26254                 case '=':
26255                         if (is_key) {
26256                                 val = qrystr->ptr + i + 1;
26257 -                               
26258 +
26259                                 qrystr->ptr[i] = '\0';
26260 -                               
26261 +
26262                                 is_key = 0;
26263                         }
26264 -                       
26265 +
26266                         break;
26267                 case '&':
26268                 case '\0': /* fin symbol */
26269 @@ -167,7 +164,7 @@
26270                                 /* terminate the value */
26271                                 qrystr->ptr[i] = '\0';
26272  
26273 -                               if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
26274 +                               if (NULL == (ds = (data_string *)array_get_unused_element(get_params, TYPE_STRING))) {
26275                                         ds = data_string_init();
26276                                 }
26277                                 buffer_copy_string_len(ds->key, key, strlen(key));
26278 @@ -175,14 +172,14 @@
26279  
26280                                 array_insert_unique(get_params, (data_unset *)ds);
26281                         }
26282 -                       
26283 +
26284                         key = qrystr->ptr + i + 1;
26285                         val = NULL;
26286                         is_key = 1;
26287                         break;
26288                 }
26289         }
26290 -       
26291 +
26292         return 0;
26293  }
26294  
26295 @@ -190,34 +187,34 @@
26296         plugin_data *p = p_d;
26297         int s_len;
26298         size_t k;
26299 -       
26300 +
26301         UNUSED(srv);
26302  
26303         if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
26304 -       
26305 +
26306         mod_flv_streaming_patch_connection(srv, con, p);
26307  
26308         s_len = con->physical.path->used - 1;
26309 -       
26310 +
26311         for (k = 0; k < p->conf.extensions->used; k++) {
26312                 data_string *ds = (data_string *)p->conf.extensions->data[k];
26313                 int ct_len = ds->value->used - 1;
26314 -               
26315 +
26316                 if (ct_len > s_len) continue;
26317                 if (ds->value->used == 0) continue;
26318 -               
26319 +
26320                 if (0 == strncmp(con->physical.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
26321                         data_string *get_param;
26322                         stat_cache_entry *sce = NULL;
26323                         buffer *b;
26324                         int start;
26325                         char *err = NULL;
26326 -                       /* if there is a start=[0-9]+ in the header use it as start, 
26327 +                       /* if there is a start=[0-9]+ in the header use it as start,
26328                          * otherwise send the full file */
26329  
26330                         array_reset(p->get_params);
26331                         buffer_copy_string_buffer(p->query_str, con->uri.query);
26332 -                       split_get_params(srv, con, p->get_params, p->query_str);
26333 +                       split_get_params(p->get_params, p->query_str);
26334  
26335                         if (NULL == (get_param = (data_string *)array_get_element(p->get_params, "start"))) {
26336                                 return HANDLER_GO_ON;
26337 @@ -256,7 +253,7 @@
26338                         return HANDLER_FINISHED;
26339                 }
26340         }
26341 -       
26342 +
26343         /* not found */
26344         return HANDLER_GO_ON;
26345  }
26346 @@ -266,13 +263,13 @@
26347  int mod_flv_streaming_plugin_init(plugin *p) {
26348         p->version     = LIGHTTPD_VERSION_ID;
26349         p->name        = buffer_init_string("flv_streaming");
26350 -       
26351 +
26352         p->init        = mod_flv_streaming_init;
26353         p->handle_physical = mod_flv_streaming_path_handler;
26354         p->set_defaults  = mod_flv_streaming_set_defaults;
26355         p->cleanup     = mod_flv_streaming_free;
26356 -       
26357 +
26358         p->data        = NULL;
26359 -       
26360 +
26361         return 0;
26362  }
26363 --- ../lighttpd-1.4.11/src/mod_indexfile.c      2005-09-30 01:08:53.000000000 +0300
26364 +++ lighttpd-1.4.12/src/mod_indexfile.c 2006-07-16 00:26:04.000000000 +0300
26365 @@ -12,6 +12,8 @@
26366  
26367  #include "stat_cache.h"
26368  
26369 +#include "sys-strings.h"
26370 +#include "sys-files.h"
26371  /* plugin config for all request/connections */
26372  
26373  typedef struct {
26374 @@ -20,51 +22,51 @@
26375  
26376  typedef struct {
26377         PLUGIN_DATA;
26378 -       
26379 +
26380         buffer *tmp_buf;
26381 -       
26382 +
26383         plugin_config **config_storage;
26384 -       
26385 -       plugin_config conf; 
26386 +
26387 +       plugin_config conf;
26388  } plugin_data;
26389  
26390  /* init the plugin data */
26391  INIT_FUNC(mod_indexfile_init) {
26392         plugin_data *p;
26393 -       
26394 +
26395         p = calloc(1, sizeof(*p));
26396 -       
26397 +
26398         p->tmp_buf = buffer_init();
26399 -       
26400 +
26401         return p;
26402  }
26403  
26404  /* detroy the plugin data */
26405  FREE_FUNC(mod_indexfile_free) {
26406         plugin_data *p = p_d;
26407 -       
26408 +
26409         UNUSED(srv);
26410  
26411         if (!p) return HANDLER_GO_ON;
26412 -       
26413 +
26414         if (p->config_storage) {
26415                 size_t i;
26416                 for (i = 0; i < srv->config_context->used; i++) {
26417                         plugin_config *s = p->config_storage[i];
26418  
26419                         if (!s) continue;
26420 -                       
26421 +
26422                         array_free(s->indexfiles);
26423 -                       
26424 +
26425                         free(s);
26426                 }
26427                 free(p->config_storage);
26428         }
26429 -       
26430 +
26431         buffer_free(p->tmp_buf);
26432 -       
26433 +
26434         free(p);
26435 -       
26436 +
26437         return HANDLER_GO_ON;
26438  }
26439  
26440 @@ -73,131 +75,139 @@
26441  SETDEFAULTS_FUNC(mod_indexfile_set_defaults) {
26442         plugin_data *p = p_d;
26443         size_t i = 0;
26444 -       
26445 -       config_values_t cv[] = { 
26446 +
26447 +       config_values_t cv[] = {
26448                 { "index-file.names",           NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
26449                 { "server.indexfiles",          NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
26450                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
26451         };
26452 -       
26453 +
26454         if (!p) return HANDLER_ERROR;
26455 -       
26456 +
26457         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
26458 -       
26459 +
26460         for (i = 0; i < srv->config_context->used; i++) {
26461                 plugin_config *s;
26462 -               
26463 +
26464                 s = calloc(1, sizeof(plugin_config));
26465                 s->indexfiles    = array_init();
26466 -               
26467 +
26468                 cv[0].destination = s->indexfiles;
26469                 cv[1].destination = s->indexfiles; /* old name for [0] */
26470 -               
26471 +
26472                 p->config_storage[i] = s;
26473 -       
26474 +
26475                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
26476                         return HANDLER_ERROR;
26477                 }
26478         }
26479 -       
26480 +
26481         return HANDLER_GO_ON;
26482  }
26483  
26484 -#define PATCH(x) \
26485 -       p->conf.x = s->x;
26486  static int mod_indexfile_patch_connection(server *srv, connection *con, plugin_data *p) {
26487         size_t i, j;
26488         plugin_config *s = p->config_storage[0];
26489 -       
26490 -       PATCH(indexfiles);
26491 -       
26492 +
26493 +       PATCH_OPTION(indexfiles);
26494 +
26495         /* skip the first, the global context */
26496         for (i = 1; i < srv->config_context->used; i++) {
26497                 data_config *dc = (data_config *)srv->config_context->data[i];
26498                 s = p->config_storage[i];
26499 -               
26500 +
26501                 /* condition didn't match */
26502                 if (!config_check_cond(srv, con, dc)) continue;
26503 -               
26504 +
26505                 /* merge config */
26506                 for (j = 0; j < dc->value->used; j++) {
26507                         data_unset *du = dc->value->data[j];
26508 -                       
26509 +
26510                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.indexfiles"))) {
26511 -                               PATCH(indexfiles);
26512 +                               PATCH_OPTION(indexfiles);
26513                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("index-file.names"))) {
26514 -                               PATCH(indexfiles);
26515 +                               PATCH_OPTION(indexfiles);
26516                         }
26517                 }
26518         }
26519 -       
26520 +
26521         return 0;
26522  }
26523 -#undef PATCH
26524  
26525  URIHANDLER_FUNC(mod_indexfile_subrequest) {
26526         plugin_data *p = p_d;
26527         size_t k;
26528         stat_cache_entry *sce = NULL;
26529 -       
26530 +
26531         if (con->uri.path->used == 0) return HANDLER_GO_ON;
26532         if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
26533 -       
26534 +
26535         mod_indexfile_patch_connection(srv, con, p);
26536 -       
26537 +
26538 +       /* is the physical-path really a dir ? */
26539 +       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
26540 +               return HANDLER_GO_ON;
26541 +       }
26542 +
26543 +       if (!S_ISDIR(sce->st.st_mode)) {
26544 +               return HANDLER_GO_ON;
26545 +       }
26546 +
26547         if (con->conf.log_request_handling) {
26548                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling the request as Indexfile");
26549                 log_error_write(srv, __FILE__, __LINE__,  "sb", "URI          :", con->uri.path);
26550         }
26551 -       
26552 +
26553 +
26554         /* indexfile */
26555         for (k = 0; k < p->conf.indexfiles->used; k++) {
26556                 data_string *ds = (data_string *)p->conf.indexfiles->data[k];
26557 -               
26558 +
26559                 if (ds->value && ds->value->ptr[0] == '/') {
26560 -                       /* if the index-file starts with a prefix as use this file as 
26561 +                       /* if the index-file starts with a prefix as use this file as
26562                          * index-generator */
26563                         buffer_copy_string_buffer(p->tmp_buf, con->physical.doc_root);
26564                 } else {
26565                         buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
26566 +                       PATHNAME_APPEND_SLASH(p->tmp_buf);
26567                 }
26568                 buffer_append_string_buffer(p->tmp_buf, ds->value);
26569 -               
26570 +
26571                 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
26572                         if (errno == EACCES) {
26573                                 con->http_status = 403;
26574                                 buffer_reset(con->physical.path);
26575 -                               
26576 +
26577                                 return HANDLER_FINISHED;
26578                         }
26579 -                       
26580 +
26581                         if (errno != ENOENT &&
26582                             errno != ENOTDIR) {
26583                                 /* we have no idea what happend. let's tell the user so. */
26584 -                               
26585 +
26586                                 con->http_status = 500;
26587 -                               
26588 +
26589                                 log_error_write(srv, __FILE__, __LINE__, "ssbsb",
26590                                                 "file not found ... or so: ", strerror(errno),
26591                                                 con->uri.path,
26592                                                 "->", con->physical.path);
26593 -                               
26594 +
26595                                 buffer_reset(con->physical.path);
26596 -                               
26597 +
26598                                 return HANDLER_FINISHED;
26599                         }
26600                         continue;
26601                 }
26602 -                       
26603 +
26604                 /* rewrite uri.path to the real path (/ -> /index.php) */
26605                 buffer_append_string_buffer(con->uri.path, ds->value);
26606                 buffer_copy_string_buffer(con->physical.path, p->tmp_buf);
26607 -               
26608 +
26609                 /* fce is already set up a few lines above */
26610 -               
26611 +
26612                 return HANDLER_GO_ON;
26613         }
26614 -       
26615 +
26616         /* not found */
26617         return HANDLER_GO_ON;
26618  }
26619 @@ -207,13 +217,13 @@
26620  int mod_indexfile_plugin_init(plugin *p) {
26621         p->version     = LIGHTTPD_VERSION_ID;
26622         p->name        = buffer_init_string("indexfile");
26623 -       
26624 +
26625         p->init        = mod_indexfile_init;
26626         p->handle_subrequest_start = mod_indexfile_subrequest;
26627         p->set_defaults  = mod_indexfile_set_defaults;
26628         p->cleanup     = mod_indexfile_free;
26629 -       
26630 +
26631         p->data        = NULL;
26632 -       
26633 +
26634         return 0;
26635  }
26636 --- ../lighttpd-1.4.11/src/mod_mysql_vhost.c    2006-01-14 20:35:10.000000000 +0200
26637 +++ lighttpd-1.4.12/src/mod_mysql_vhost.c       2006-07-20 00:57:19.000000000 +0300
26638 @@ -1,13 +1,18 @@
26639 -#include <unistd.h>
26640  #include <stdio.h>
26641  #include <errno.h>
26642  #include <fcntl.h>
26643 -#include <strings.h>
26644 +#include <string.h>
26645  
26646  #ifdef HAVE_CONFIG_H
26647  #include "config.h"
26648  #endif
26649  
26650 +#ifdef HAVE_MYSQL_H 
26651 +# ifdef HAVE_LIBMYSQL
26652 +#  define HAVE_MYSQL
26653 +# endif
26654 +#endif
26655 +
26656  #ifdef HAVE_MYSQL
26657  #include <mysql.h>
26658  #endif
26659 @@ -16,61 +21,40 @@
26660  #include "log.h"
26661  
26662  #include "stat_cache.h"
26663 -#ifdef DEBUG_MOD_MYSQL_VHOST
26664 -#define DEBUG
26665 -#endif
26666 +#include "sys-files.h"
26667  
26668 -/*
26669 - * Plugin for lighttpd to use MySQL 
26670 - *   for domain to directory lookups,
26671 - *   i.e virtual hosts (vhosts).
26672 - *   
26673 - * Optionally sets fcgi_offset and fcgi_arg 
26674 - *   in preparation for fcgi.c to handle 
26675 - *   per-user fcgi chroot jails.
26676 - *
26677 - * /ada@riksnet.se 2004-12-06
26678 - */
26679 +#include "mod_sql_vhost_core.h"
26680  
26681  #ifdef HAVE_MYSQL
26682 +
26683 +#define CORE_PLUGIN "mod_sql_vhost_core"
26684 +
26685  typedef struct {
26686         MYSQL   *mysql;
26687 -       
26688 -       buffer  *mydb;
26689 -       buffer  *myuser;
26690 -       buffer  *mypass;
26691 -       buffer  *mysock;
26692 -       
26693 -       buffer  *hostname;
26694 -       unsigned short port;
26695 -       
26696 +
26697         buffer  *mysql_pre;
26698         buffer  *mysql_post;
26699 +
26700 +       mod_sql_vhost_core_plugin_config *core;
26701  } plugin_config;
26702  
26703  /* global plugin data */
26704  typedef struct {
26705         PLUGIN_DATA;
26706 -       
26707 +
26708         buffer  *tmp_buf;
26709 -       
26710 +
26711         plugin_config **config_storage;
26712 -       
26713 -       plugin_config conf; 
26714 +
26715 +       plugin_config conf;
26716  } plugin_data;
26717  
26718 -/* per connection plugin data */
26719 -typedef struct {
26720 -       buffer  *server_name;
26721 -       buffer  *document_root;
26722 -       buffer  *fcgi_arg;
26723 -       unsigned fcgi_offset;
26724 -} plugin_connection_data;
26725 +SQLVHOST_BACKEND_GETVHOST(mod_mysql_vhost_get_vhost); 
26726  
26727  /* init the plugin data */
26728  INIT_FUNC(mod_mysql_vhost_init) {
26729         plugin_data *p;
26730 -       
26731 +
26732         p = calloc(1, sizeof(*p));
26733  
26734         p->tmp_buf = buffer_init();
26735 @@ -83,144 +67,77 @@
26736         plugin_data *p = p_d;
26737  
26738         UNUSED(srv);
26739 -       
26740 -#ifdef DEBUG
26741 -       log_error_write(srv, __FILE__, __LINE__, "ss", 
26742 -               "mod_mysql_vhost_cleanup", p ? "yes" : "NO");
26743 -#endif
26744 +
26745         if (!p) return HANDLER_GO_ON;
26746 -       
26747 +
26748         if (p->config_storage) {
26749                 size_t i;
26750                 for (i = 0; i < srv->config_context->used; i++) {
26751                         plugin_config *s = p->config_storage[i];
26752  
26753                         if (!s) continue;
26754 -                       
26755 +
26756                         mysql_close(s->mysql);
26757 -                       
26758 -                       buffer_free(s->mydb);
26759 -                       buffer_free(s->myuser);
26760 -                       buffer_free(s->mypass);
26761 -                       buffer_free(s->mysock);
26762 +
26763                         buffer_free(s->mysql_pre);
26764                         buffer_free(s->mysql_post);
26765 -                       
26766 +
26767                         free(s);
26768                 }
26769                 free(p->config_storage);
26770         }
26771         buffer_free(p->tmp_buf);
26772 -       
26773 -       free(p);
26774  
26775 -       return HANDLER_GO_ON;
26776 -}
26777 -
26778 -/* handle the plugin per connection data */
26779 -static void* mod_mysql_vhost_connection_data(server *srv, connection *con, void *p_d)
26780 -{
26781 -       plugin_data *p = p_d;
26782 -       plugin_connection_data *c = con->plugin_ctx[p->id];
26783 -
26784 -       UNUSED(srv);
26785 -
26786 -#ifdef DEBUG
26787 -        log_error_write(srv, __FILE__, __LINE__, "ss", 
26788 -               "mod_mysql_connection_data", c ? "old" : "NEW");
26789 -#endif
26790 -
26791 -       if (c) return c;
26792 -       c = calloc(1, sizeof(*c));
26793 -
26794 -       c->server_name = buffer_init();
26795 -       c->document_root = buffer_init();
26796 -       c->fcgi_arg = buffer_init();
26797 -       c->fcgi_offset = 0;
26798 -
26799 -       return con->plugin_ctx[p->id] = c;
26800 -}
26801 -
26802 -/* destroy the plugin per connection data */
26803 -CONNECTION_FUNC(mod_mysql_vhost_handle_connection_close) {
26804 -       plugin_data *p = p_d;
26805 -       plugin_connection_data *c = con->plugin_ctx[p->id];
26806 -
26807 -       UNUSED(srv);
26808 -
26809 -#ifdef DEBUG
26810 -       log_error_write(srv, __FILE__, __LINE__, "ss", 
26811 -               "mod_mysql_vhost_handle_connection_close", c ? "yes" : "NO");
26812 -#endif
26813 -       
26814 -       if (!c) return HANDLER_GO_ON;
26815 -
26816 -       buffer_free(c->server_name);
26817 -       buffer_free(c->document_root);
26818 -       buffer_free(c->fcgi_arg);
26819 -       c->fcgi_offset = 0;
26820 -
26821 -       free(c);
26822 +       free(p);
26823  
26824 -       con->plugin_ctx[p->id] = NULL;
26825         return HANDLER_GO_ON;
26826  }
26827  
26828  /* set configuration values */
26829  SERVER_FUNC(mod_mysql_vhost_set_defaults) {
26830         plugin_data *p = p_d;
26831 +       mod_sql_vhost_core_plugin_data *core_config;
26832  
26833 -       char *qmark;
26834         size_t i = 0;
26835  
26836 -       config_values_t cv[] = {
26837 -               { "mysql-vhost.db",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
26838 -               { "mysql-vhost.user",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
26839 -               { "mysql-vhost.pass",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
26840 -               { "mysql-vhost.sock",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
26841 -               { "mysql-vhost.sql",    NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
26842 -               { "mysql-vhost.hostname", NULL, T_CONFIG_STRING,T_CONFIG_SCOPE_SERVER },
26843 -               { "mysql-vhost.port",   NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_SERVER },
26844 -                { NULL,                        NULL, T_CONFIG_UNSET,   T_CONFIG_SCOPE_UNSET }
26845 -        };
26846 -       
26847 +       /* our very own plugin storage, one entry for each conditional
26848 +        * 
26849 +        * srv->config_context->used is the number of conditionals
26850 +        * */
26851         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
26852 -       
26853 +
26854 +       /* get the config of the core-plugin */
26855 +       core_config = plugin_get_config(srv, CORE_PLUGIN);
26856 +
26857 +
26858 +       /* walk through all conditionals and check for assignments */
26859         for (i = 0; i < srv->config_context->used; i++) {
26860                 plugin_config *s;
26861                 buffer *sel;
26862 -               
26863 -               
26864 +               char *qmark;
26865 +
26866 +               /* get the config from the core plugin for this conditional-context */
26867                 s = calloc(1, sizeof(plugin_config));
26868 -               s->mydb = buffer_init();
26869 -               s->myuser = buffer_init();
26870 -               s->mypass = buffer_init();
26871 -               s->mysock = buffer_init();
26872 -               s->hostname = buffer_init();
26873 -               s->port   = 0;               /* default port for mysql */
26874 -               sel = buffer_init();
26875 -               s->mysql = NULL;
26876 +
26877 +               s->core = core_config->config_storage[i];
26878                 
26879 +               s->mysql = NULL;
26880 +
26881                 s->mysql_pre = buffer_init();
26882                 s->mysql_post = buffer_init();
26883 -               
26884 -               cv[0].destination = s->mydb;
26885 -               cv[1].destination = s->myuser;
26886 -               cv[2].destination = s->mypass;
26887 -               cv[3].destination = s->mysock;
26888 -               cv[4].destination = sel;
26889 -               cv[5].destination = s->hostname;
26890 -               cv[6].destination = &(s->port);
26891 -               
26892 +
26893                 p->config_storage[i] = s;
26894 -               
26895 -               if (config_insert_values_global(srv, 
26896 -                       ((data_config *)srv->config_context->data[i])->value,
26897 -                       cv)) return HANDLER_ERROR;
26898 -               
26899 -               s->mysql_pre = buffer_init();
26900 -               s->mysql_post = buffer_init();
26901 -               
26902 +
26903 +               /* check if we are the plugin for this backend */
26904 +               if (!buffer_is_equal_string(s->core->backend, CONST_STR_LEN("mysql"))) continue;
26905 +
26906 +               /* attach us to the core-plugin */
26907 +               s->core->backend_data = p;
26908 +               s->core->get_vhost = mod_mysql_vhost_get_vhost;
26909 +
26910 +               sel = buffer_init();
26911 +               buffer_copy_string_buffer(sel, s->core->select_vhost);
26912 +
26913                 if (sel->used && (qmark = index(sel->ptr, '?'))) {
26914                         *qmark = '\0';
26915                         buffer_copy_string(s->mysql_pre, sel->ptr);
26916 @@ -228,35 +145,38 @@
26917                 } else {
26918                         buffer_copy_string_buffer(s->mysql_pre, sel);
26919                 }
26920 -               
26921 +               buffer_free(sel);
26922 +
26923                 /* required:
26924                  * - username
26925 -                * - database 
26926 -                * 
26927 +                * - database
26928 +                *
26929                  * optional:
26930                  * - password, default: empty
26931                  * - socket, default: mysql default
26932                  * - hostname, if set overrides socket
26933                  * - port, default: 3306
26934                  */
26935 -               
26936 +
26937                 /* all have to be set */
26938 -               if (!(buffer_is_empty(s->myuser) ||
26939 -                     buffer_is_empty(s->mydb))) {
26940 +               if (!(buffer_is_empty(s->core->user) ||
26941 +                     buffer_is_empty(s->core->db))) {
26942  
26943                         int fd;
26944 -               
26945 +
26946                         if (NULL == (s->mysql = mysql_init(NULL))) {
26947                                 log_error_write(srv, __FILE__, __LINE__, "s", "mysql_init() failed, exiting...");
26948 -                               
26949 +
26950                                 return HANDLER_ERROR;
26951                         }
26952 -#define FOO(x) (s->x->used ? s->x->ptr : NULL)
26953 -                       
26954 -                       if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(myuser), FOO(mypass), 
26955 -                                               FOO(mydb), s->port, FOO(mysock), 0)) {
26956 +#define FOO(x) (s->core->x->used ? s->core->x->ptr : NULL)
26957 +
26958 +                       s->mysql->free_me = 1;
26959 +
26960 +                       if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(user), FOO(pass),
26961 +                                               FOO(db), s->core->port, FOO(sock), 0)) {
26962                                 log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(s->mysql));
26963 -                               
26964 +
26965                                 return HANDLER_ERROR;
26966                         }
26967  #undef FOO
26968 @@ -265,61 +185,47 @@
26969                         /* otherwise we cannot be sure that mysql is fd i-1 */
26970                         if (-1 == (fd = open("/dev/null", 0))) {
26971                                 close(fd);
26972 -                               fcntl(fd-1, F_SETFD, FD_CLOEXEC); 
26973 +                               fcntl(fd-1, F_SETFD, FD_CLOEXEC);
26974                         }
26975                 }
26976         }
26977 -       
26978 -       
26979 +
26980 +
26981  
26982          return HANDLER_GO_ON;
26983  }
26984  
26985 -#define PATCH(x) \
26986 -       p->conf.x = s->x;
26987  static int mod_mysql_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
26988 -       size_t i, j;
26989 +       size_t i;
26990         plugin_config *s = p->config_storage[0];
26991 -       
26992 -       PATCH(mysql_pre);
26993 -       PATCH(mysql_post);
26994 -#ifdef HAVE_MYSQL
26995 -       PATCH(mysql);
26996 -#endif
26997 -       
26998 +
26999 +       PATCH_OPTION(mysql_pre);
27000 +       PATCH_OPTION(mysql_post);
27001 +       PATCH_OPTION(mysql);
27002 +
27003         /* skip the first, the global context */
27004         for (i = 1; i < srv->config_context->used; i++) {
27005                 data_config *dc = (data_config *)srv->config_context->data[i];
27006                 s = p->config_storage[i];
27007 -               
27008 +
27009                 /* condition didn't match */
27010                 if (!config_check_cond(srv, con, dc)) continue;
27011 -               
27012 -               /* merge config */
27013 -               for (j = 0; j < dc->value->used; j++) {
27014 -                       data_unset *du = dc->value->data[j];
27015 -                       
27016 -                       if (buffer_is_equal_string(du->key, CONST_STR_LEN("mysql-vhost.sql"))) {
27017 -                               PATCH(mysql_pre);
27018 -                               PATCH(mysql_post);
27019 -                       }
27020 -               }
27021 -               
27022 +
27023                 if (s->mysql) {
27024 -                       PATCH(mysql);
27025 +                       PATCH_OPTION(mysql);
27026 +                       PATCH_OPTION(mysql_pre);
27027 +                       PATCH_OPTION(mysql_post);
27028                 }
27029         }
27030 -       
27031 +
27032         return 0;
27033  }
27034 -#undef PATCH
27035  
27036 -
27037 -/* handle document root request */
27038 -CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
27039 +/**
27040 + * get the vhost info from the database 
27041 + */
27042 +SQLVHOST_BACKEND_GETVHOST(mod_mysql_vhost_get_vhost) {
27043         plugin_data *p = p_d;
27044 -       plugin_connection_data *c;
27045 -       stat_cache_entry *sce;
27046  
27047         unsigned  cols;
27048         MYSQL_ROW row;
27049 @@ -332,13 +238,6 @@
27050  
27051         if (!p->conf.mysql) return HANDLER_GO_ON;
27052  
27053 -       /* sets up connection data if not done yet */
27054 -       c = mod_mysql_vhost_connection_data(srv, con, p_d);
27055 -
27056 -       /* check if cached this connection */
27057 -       if (c->server_name->used && /* con->uri.authority->used && */
27058 -            buffer_is_equal(c->server_name, con->uri.authority)) goto GO_ON;
27059 -
27060         /* build and run SQL query */
27061         buffer_copy_string_buffer(p->tmp_buf, p->conf.mysql_pre);
27062         if (p->conf.mysql_post->used) {
27063 @@ -347,77 +246,43 @@
27064         }
27065         if (mysql_query(p->conf.mysql, p->tmp_buf->ptr)) {
27066                 log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(p->conf.mysql));
27067 -               goto ERR500;
27068 +
27069 +               mysql_free_result(result);
27070 +               return HANDLER_GO_ON;
27071         }
27072         result = mysql_store_result(p->conf.mysql);
27073         cols = mysql_num_fields(result);
27074         row = mysql_fetch_row(result);
27075 +
27076         if (!row || cols < 1) {
27077                 /* no such virtual host */
27078                 mysql_free_result(result);
27079                 return HANDLER_GO_ON;
27080         }
27081  
27082 -       /* sanity check that really is a directory */
27083 -       buffer_copy_string(p->tmp_buf, row[0]);
27084 -       BUFFER_APPEND_SLASH(p->tmp_buf);
27085 -
27086 -       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
27087 -               log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
27088 -               goto ERR500;
27089 -       }
27090 -        if (!S_ISDIR(sce->st.st_mode)) {
27091 -               log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", p->tmp_buf);
27092 -               goto ERR500;
27093 -       }
27094 +       buffer_copy_string(docroot, row[0]);
27095  
27096 -       /* cache the data */
27097 -       buffer_copy_string_buffer(c->server_name, con->uri.authority);
27098 -       buffer_copy_string_buffer(c->document_root, p->tmp_buf);
27099 -
27100 -       /* fcgi_offset and fcgi_arg are optional */
27101 -       if (cols > 1 && row[1]) {
27102 -               c->fcgi_offset = atoi(row[1]);
27103 -               
27104 -               if (cols > 2 && row[2]) {
27105 -                       buffer_copy_string(c->fcgi_arg, row[2]);
27106 -               } else {
27107 -                       c->fcgi_arg->used = 0;
27108 -               }
27109 -       } else {
27110 -               c->fcgi_offset = c->fcgi_arg->used = 0;
27111 -       }
27112         mysql_free_result(result);
27113  
27114 -       /* fix virtual server and docroot */
27115 -GO_ON: buffer_copy_string_buffer(con->server_name, c->server_name);
27116 -       buffer_copy_string_buffer(con->physical.doc_root, c->document_root);
27117 -
27118 -#ifdef DEBUG
27119 -       log_error_write(srv, __FILE__, __LINE__, "sbbdb", 
27120 -               result ? "NOT CACHED" : "cached", 
27121 -               con->server_name, con->physical.doc_root,
27122 -               c->fcgi_offset, c->fcgi_arg);
27123 -#endif
27124 -       return HANDLER_GO_ON;   
27125 -
27126 -ERR500:        if (result) mysql_free_result(result);
27127 -       con->http_status = 500; /* Internal Error */
27128 -       return HANDLER_FINISHED;
27129 +       return HANDLER_GO_ON;
27130  }
27131  
27132  /* this function is called at dlopen() time and inits the callbacks */
27133  int mod_mysql_vhost_plugin_init(plugin *p) {
27134 +       data_string *ds;
27135 +       
27136         p->version     = LIGHTTPD_VERSION_ID;
27137         p->name                         = buffer_init_string("mysql_vhost");
27138  
27139         p->init                         = mod_mysql_vhost_init;
27140         p->cleanup                      = mod_mysql_vhost_cleanup;
27141 -       p->handle_request_done          = mod_mysql_vhost_handle_connection_close;
27142  
27143         p->set_defaults                 = mod_mysql_vhost_set_defaults;
27144 -       p->handle_docroot               = mod_mysql_vhost_handle_docroot;
27145         
27146 +       ds = data_string_init();
27147 +       buffer_copy_string(ds->value, CORE_PLUGIN);
27148 +       array_insert_unique(p->required_plugins, (data_unset *)ds);
27149 +
27150         return 0;
27151  }
27152  #else
27153 --- ../lighttpd-1.4.11/src/mod_proxy.c  2006-01-31 13:01:22.000000000 +0200
27154 +++ lighttpd-1.4.12/src/mod_proxy.c     2006-07-19 20:02:55.000000000 +0300
27155 @@ -1,6 +1,5 @@
27156  #include <sys/types.h>
27157  
27158 -#include <unistd.h>
27159  #include <errno.h>
27160  #include <fcntl.h>
27161  #include <string.h>
27162 @@ -23,6 +22,9 @@
27163  
27164  #include "inet_ntop_cache.h"
27165  #include "crc32.h"
27166 +#include "network.h"
27167 +
27168 +#include "http_resp.h"
27169  
27170  #include <stdio.h>
27171  
27172 @@ -31,6 +33,8 @@
27173  #endif
27174  
27175  #include "sys-socket.h"
27176 +#include "sys-files.h"
27177 +#include "sys-strings.h"
27178  
27179  #define data_proxy data_fastcgi
27180  #define data_proxy_init data_fastcgi_init
27181 @@ -38,22 +42,25 @@
27182  #define PROXY_RETRY_TIMEOUT 60
27183  
27184  /**
27185 - * 
27186 - * the proxy module is based on the fastcgi module 
27187 - * 
27188 + *
27189 + * the proxy module is based on the fastcgi module
27190 + *
27191   * 28.06.2004 Jan Kneschke     The first release
27192   * 01.07.2004 Evgeny Rodichev  Several bugfixes and cleanups
27193   *            - co-ordinate up- and downstream flows correctly (proxy_demux_response
27194   *              and proxy_handle_fdevent)
27195   *            - correctly transfer upstream http_response_status;
27196   *            - some unused structures removed.
27197 - * 
27198 + *
27199   * TODO:      - delay upstream read if write_queue is too large
27200   *              (to prevent memory eating, like in apache). Shoud be
27201   *              configurable).
27202   *            - persistent connection with upstream servers
27203   *            - HTTP/1.1
27204   */
27205 +
27206 +
27207 +
27208  typedef enum {
27209         PROXY_BALANCE_UNSET,
27210         PROXY_BALANCE_FAIR,
27211 @@ -66,26 +73,33 @@
27212         int debug;
27213  
27214         proxy_balance_t balance;
27215 +
27216 +       array *last_used_backends; /* "extension" : last_used_backend */
27217  } plugin_config;
27218  
27219  typedef struct {
27220         PLUGIN_DATA;
27221 -       
27222 +
27223         buffer *parse_response;
27224         buffer *balance_buf;
27225 -       
27226 +
27227 +       http_resp *resp;
27228 +
27229 +       array *ignore_headers;
27230 +
27231         plugin_config **config_storage;
27232 -       
27233 +
27234         plugin_config conf;
27235  } plugin_data;
27236  
27237 -typedef enum { 
27238 -       PROXY_STATE_INIT, 
27239 -       PROXY_STATE_CONNECT, 
27240 -       PROXY_STATE_PREPARE_WRITE, 
27241 -       PROXY_STATE_WRITE, 
27242 -       PROXY_STATE_READ, 
27243 -       PROXY_STATE_ERROR 
27244 +typedef enum {
27245 +       PROXY_STATE_INIT,
27246 +       PROXY_STATE_CONNECT,
27247 +       PROXY_STATE_PREPARE_WRITE,
27248 +       PROXY_STATE_WRITE,
27249 +       PROXY_STATE_RESPONSE_HEADER,
27250 +       PROXY_STATE_RESPONSE_CONTENT,
27251 +       PROXY_STATE_ERROR
27252  } proxy_connection_state_t;
27253  
27254  enum { PROXY_STDOUT, PROXY_END_REQUEST };
27255 @@ -93,19 +107,16 @@
27256  typedef struct {
27257         proxy_connection_state_t state;
27258         time_t state_timestamp;
27259 -       
27260 +
27261         data_proxy *host;
27262 -       
27263 -       buffer *response;
27264 -       buffer *response_header;
27265  
27266         chunkqueue *wb;
27267 -       
27268 -       int fd; /* fd to the proxy process */
27269 -       int fde_ndx; /* index into the fd-event buffer */
27270 +       chunkqueue *rb;
27271 +
27272 +       iosocket *sock; /* fd to the proxy process */
27273  
27274         size_t path_info_offset; /* start of path_info in uri.path */
27275 -       
27276 +
27277         connection *remote_conn;  /* dump pointer */
27278         plugin_data *plugin_data; /* dump pointer */
27279  } handler_ctx;
27280 @@ -116,69 +127,89 @@
27281  
27282  static handler_ctx * handler_ctx_init() {
27283         handler_ctx * hctx;
27284 -       
27285 +
27286  
27287         hctx = calloc(1, sizeof(*hctx));
27288 -       
27289 +
27290         hctx->state = PROXY_STATE_INIT;
27291         hctx->host = NULL;
27292 -       
27293 -       hctx->response = buffer_init();
27294 -       hctx->response_header = buffer_init();
27295  
27296         hctx->wb = chunkqueue_init();
27297 +       hctx->rb = chunkqueue_init();
27298 +
27299 +       hctx->sock = iosocket_init();
27300  
27301 -       hctx->fd = -1;
27302 -       hctx->fde_ndx = -1;
27303 -       
27304         return hctx;
27305  }
27306  
27307  static void handler_ctx_free(handler_ctx *hctx) {
27308 -       buffer_free(hctx->response);
27309 -       buffer_free(hctx->response_header);
27310         chunkqueue_free(hctx->wb);
27311 -       
27312 +       chunkqueue_free(hctx->rb);
27313 +
27314 +       iosocket_free(hctx->sock);
27315 +
27316         free(hctx);
27317  }
27318  
27319  INIT_FUNC(mod_proxy_init) {
27320         plugin_data *p;
27321 -       
27322 +       size_t i;
27323 +
27324 +       char *hop2hop_headers[] = {
27325 +               "Connection",
27326 +               "Keep-Alive",
27327 +               "Host",
27328 +               NULL
27329 +       };
27330 +
27331         p = calloc(1, sizeof(*p));
27332 -       
27333 -       p->parse_response = buffer_init();
27334 +
27335         p->balance_buf = buffer_init();
27336 -       
27337 +       p->ignore_headers = array_init();
27338 +       p->resp = http_response_init();
27339 +
27340 +       for (i = 0; hop2hop_headers[i]; i++) {
27341 +               data_string *ds;
27342 +
27343 +               if (NULL == (ds = (data_string *)array_get_unused_element(p->ignore_headers, TYPE_STRING))) {
27344 +                       ds = data_string_init();
27345 +               }
27346 +
27347 +               buffer_copy_string(ds->key, hop2hop_headers[i]);
27348 +               buffer_copy_string(ds->value, hop2hop_headers[i]);
27349 +               array_insert_unique(p->ignore_headers, (data_unset *)ds);
27350 +       }
27351 +
27352         return p;
27353  }
27354  
27355  
27356  FREE_FUNC(mod_proxy_free) {
27357         plugin_data *p = p_d;
27358 -       
27359 +
27360         UNUSED(srv);
27361  
27362 -       buffer_free(p->parse_response);
27363 -       buffer_free(p->balance_buf);
27364 -       
27365         if (p->config_storage) {
27366                 size_t i;
27367                 for (i = 0; i < srv->config_context->used; i++) {
27368                         plugin_config *s = p->config_storage[i];
27369 -                       
27370 +
27371                         if (s) {
27372 -                       
27373                                 array_free(s->extensions);
27374 -                       
27375 +                               array_free(s->last_used_backends);
27376 +
27377                                 free(s);
27378                         }
27379                 }
27380                 free(p->config_storage);
27381         }
27382 -       
27383 +
27384 +       array_free(p->ignore_headers);
27385 +       buffer_free(p->balance_buf);
27386 +       http_response_free(p->resp);
27387 +
27388         free(p);
27389 -       
27390 +
27391         return HANDLER_GO_ON;
27392  }
27393  
27394 @@ -186,37 +217,38 @@
27395         plugin_data *p = p_d;
27396         data_unset *du;
27397         size_t i = 0;
27398 -       
27399 -       config_values_t cv[] = { 
27400 +
27401 +       config_values_t cv[] = {
27402                 { "proxy.server",              NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
27403                 { "proxy.debug",               NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
27404                 { "proxy.balance",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 2 */
27405                 { NULL,                        NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
27406         };
27407 -       
27408 +
27409         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
27410 -       
27411 +
27412         for (i = 0; i < srv->config_context->used; i++) {
27413                 plugin_config *s;
27414                 array *ca;
27415 -               
27416 +
27417                 s = malloc(sizeof(plugin_config));
27418 -               s->extensions    = array_init();
27419 +               s->extensions         = array_init();
27420 +               s->last_used_backends = array_init();
27421                 s->debug         = 0;
27422 -               
27423 +
27424                 cv[0].destination = s->extensions;
27425                 cv[1].destination = &(s->debug);
27426                 cv[2].destination = p->balance_buf;
27427  
27428                 buffer_reset(p->balance_buf);
27429 -               
27430 +
27431                 p->config_storage[i] = s;
27432                 ca = ((data_config *)srv->config_context->data[i])->value;
27433 -       
27434 +
27435                 if (0 != config_insert_values_global(srv, ca, cv)) {
27436                         return HANDLER_ERROR;
27437                 }
27438 -       
27439 +
27440                 if (buffer_is_empty(p->balance_buf)) {
27441                         s->balance = PROXY_BALANCE_FAIR;
27442                 } else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("fair"))) {
27443 @@ -226,99 +258,99 @@
27444                 } else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("hash"))) {
27445                         s->balance = PROXY_BALANCE_HASH;
27446                 } else {
27447 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
27448 -                                       "proxy.balance has to be one of: fair, round-robin, hash, but not:", p->balance_buf);
27449 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
27450 +                               "proxy.balance has to be one of: fair, round-robin, hash, but not:", p->balance_buf);
27451                         return HANDLER_ERROR;
27452                 }
27453  
27454                 if (NULL != (du = array_get_element(ca, "proxy.server"))) {
27455                         size_t j;
27456                         data_array *da = (data_array *)du;
27457 -                       
27458 +
27459                         if (du->type != TYPE_ARRAY) {
27460 -                               log_error_write(srv, __FILE__, __LINE__, "sss", 
27461 +                               log_error_write(srv, __FILE__, __LINE__, "sss",
27462                                                 "unexpected type for key: ", "proxy.server", "array of strings");
27463 -                               
27464 +
27465                                 return HANDLER_ERROR;
27466                         }
27467 -                       
27468 -                       /* 
27469 +
27470 +                       /*
27471                          * proxy.server = ( "<ext>" => ...,
27472                          *                  "<ext>" => ... )
27473                          */
27474 -                       
27475 +
27476                         for (j = 0; j < da->value->used; j++) {
27477                                 data_array *da_ext = (data_array *)da->value->data[j];
27478                                 size_t n;
27479 -                               
27480 +
27481                                 if (da_ext->type != TYPE_ARRAY) {
27482 -                                       log_error_write(srv, __FILE__, __LINE__, "sssbs", 
27483 -                                                       "unexpected type for key: ", "proxy.server", 
27484 +                                       log_error_write(srv, __FILE__, __LINE__, "sssbs",
27485 +                                                       "unexpected type for key: ", "proxy.server",
27486                                                         "[", da->value->data[j]->key, "](string)");
27487 -                                       
27488 +
27489                                         return HANDLER_ERROR;
27490                                 }
27491 -                               
27492 -                               /* 
27493 -                                * proxy.server = ( "<ext>" => 
27494 -                                *                     ( "<host>" => ( ... ), 
27495 +
27496 +                               /*
27497 +                                * proxy.server = ( "<ext>" =>
27498 +                                *                     ( "<host>" => ( ... ),
27499                                  *                       "<host>" => ( ... )
27500 -                                *                     ), 
27501 +                                *                     ),
27502                                  *                    "<ext>" => ... )
27503                                  */
27504 -                               
27505 +
27506                                 for (n = 0; n < da_ext->value->used; n++) {
27507                                         data_array *da_host = (data_array *)da_ext->value->data[n];
27508 -                                       
27509 +
27510                                         data_proxy *df;
27511                                         data_array *dfa;
27512 -                                       
27513 -                                       config_values_t pcv[] = { 
27514 +
27515 +                                       config_values_t pcv[] = {
27516                                                 { "host",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 0 */
27517                                                 { "port",              NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
27518                                                 { NULL,                NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
27519                                         };
27520 -                                       
27521 +
27522                                         if (da_host->type != TYPE_ARRAY) {
27523 -                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS", 
27524 -                                                               "unexpected type for key:", 
27525 -                                                               "proxy.server", 
27526 +                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS",
27527 +                                                               "unexpected type for key:",
27528 +                                                               "proxy.server",
27529                                                                 "[", da_ext->value->data[n]->key, "](string)");
27530 -                                               
27531 +
27532                                                 return HANDLER_ERROR;
27533                                         }
27534 -                                       
27535 +
27536                                         df = data_proxy_init();
27537 -                                       
27538 +
27539                                         df->port = 80;
27540 -                                       
27541 +
27542                                         buffer_copy_string_buffer(df->key, da_host->key);
27543 -                                       
27544 +
27545                                         pcv[0].destination = df->host;
27546                                         pcv[1].destination = &(df->port);
27547 -                                       
27548 +
27549                                         if (0 != config_insert_values_internal(srv, da_host->value, pcv)) {
27550                                                 return HANDLER_ERROR;
27551                                         }
27552 -                                       
27553 +
27554                                         if (buffer_is_empty(df->host)) {
27555 -                                               log_error_write(srv, __FILE__, __LINE__, "sbbbs", 
27556 -                                                               "missing key (string):", 
27557 +                                               log_error_write(srv, __FILE__, __LINE__, "sbbbs",
27558 +                                                               "missing key (string):",
27559                                                                 da->key,
27560                                                                 da_ext->key,
27561                                                                 da_host->key,
27562                                                                 "host");
27563 -                                               
27564 +
27565                                                 return HANDLER_ERROR;
27566                                         }
27567 -                                       
27568 +
27569                                         /* if extension already exists, take it */
27570 -                                       
27571 +
27572                                         if (NULL == (dfa = (data_array *)array_get_element(s->extensions, da_ext->key->ptr))) {
27573                                                 dfa = data_array_init();
27574 -                                               
27575 +
27576                                                 buffer_copy_string_buffer(dfa->key, da_ext->key);
27577 -                                               
27578 +
27579                                                 array_insert_unique(dfa->value, (data_unset *)df);
27580                                                 array_insert_unique(s->extensions, (data_unset *)dfa);
27581                                         } else {
27582 @@ -328,67 +360,76 @@
27583                         }
27584                 }
27585         }
27586 -       
27587 +
27588         return HANDLER_GO_ON;
27589  }
27590  
27591  void proxy_connection_close(server *srv, handler_ctx *hctx) {
27592         plugin_data *p;
27593         connection *con;
27594 -       
27595 +
27596         if (NULL == hctx) return;
27597 -       
27598 +
27599         p    = hctx->plugin_data;
27600         con  = hctx->remote_conn;
27601 -       
27602 -       if (hctx->fd != -1) {
27603 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
27604 -               fdevent_unregister(srv->ev, hctx->fd);
27605  
27606 -               close(hctx->fd);
27607 +       if (hctx->sock->fd != -1) {
27608 +               fdevent_event_del(srv->ev, hctx->sock);
27609 +               fdevent_unregister(srv->ev, hctx->sock);
27610 +
27611 +               close(hctx->sock->fd);
27612                 srv->cur_fds--;
27613         }
27614 -       
27615 +
27616         handler_ctx_free(hctx);
27617 -       con->plugin_ctx[p->id] = NULL;  
27618 +       con->plugin_ctx[p->id] = NULL;
27619  }
27620  
27621  static int proxy_establish_connection(server *srv, handler_ctx *hctx) {
27622         struct sockaddr *proxy_addr;
27623         struct sockaddr_in proxy_addr_in;
27624         socklen_t servlen;
27625 -       
27626 +
27627         plugin_data *p    = hctx->plugin_data;
27628         data_proxy *host= hctx->host;
27629 -       int proxy_fd       = hctx->fd;
27630 -       
27631 +       int proxy_fd       = hctx->sock->fd;
27632 +
27633         memset(&proxy_addr, 0, sizeof(proxy_addr));
27634 -       
27635 +
27636         proxy_addr_in.sin_family = AF_INET;
27637         proxy_addr_in.sin_addr.s_addr = inet_addr(host->host->ptr);
27638         proxy_addr_in.sin_port = htons(host->port);
27639         servlen = sizeof(proxy_addr_in);
27640 -               
27641 +
27642         proxy_addr = (struct sockaddr *) &proxy_addr_in;
27643 -       
27644 +
27645         if (-1 == connect(proxy_fd, proxy_addr, servlen)) {
27646 -               if (errno == EINPROGRESS || errno == EALREADY) {
27647 +#ifdef _WIN32
27648 +       errno = WSAGetLastError();
27649 +#endif
27650 +       switch(errno) {
27651 +#ifdef _WIN32
27652 +       case WSAEWOULDBLOCK:
27653 +#endif
27654 +       case EINPROGRESS:
27655 +       case EALREADY:
27656                         if (p->conf.debug) {
27657 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
27658 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
27659                                                 "connect delayed:", proxy_fd);
27660                         }
27661 -                       
27662 +
27663                         return 1;
27664 -               } else {
27665 -                       
27666 -                       log_error_write(srv, __FILE__, __LINE__, "sdsd", 
27667 +               default:
27668 +
27669 +                       log_error_write(srv, __FILE__, __LINE__, "sdsd",
27670                                         "connect failed:", proxy_fd, strerror(errno), errno);
27671 -                       
27672 +
27673                         return -1;
27674                 }
27675         }
27676 +       fprintf(stderr, "%s.%d: connected fd = %d\r\n", __FILE__, __LINE__, proxy_fd);
27677         if (p->conf.debug) {
27678 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
27679 +               log_error_write(srv, __FILE__, __LINE__, "sd",
27680                                 "connect succeeded: ", proxy_fd);
27681         }
27682  
27683 @@ -396,51 +437,52 @@
27684  }
27685  
27686  void proxy_set_header(connection *con, const char *key, const char *value) {
27687 -    data_string *ds_dst;
27688 +       data_string *ds_dst;
27689  
27690 -    if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27691 -          ds_dst = data_string_init();
27692 -    }
27693 -
27694 -    buffer_copy_string(ds_dst->key, key);
27695 -    buffer_copy_string(ds_dst->value, value);
27696 -    array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27697 +       if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27698 +               ds_dst = data_string_init();
27699 +       }
27700 +
27701 +       buffer_copy_string(ds_dst->key, key);
27702 +       buffer_copy_string(ds_dst->value, value);
27703 +       array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27704  }
27705  
27706  void proxy_append_header(connection *con, const char *key, const char *value) {
27707 -    data_string *ds_dst;
27708 +       data_string *ds_dst;
27709  
27710 -    if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27711 -          ds_dst = data_string_init();
27712 -    }
27713 -
27714 -    buffer_copy_string(ds_dst->key, key);
27715 -    buffer_append_string(ds_dst->value, value);
27716 -    array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27717 +       if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27718 +               ds_dst = data_string_init();
27719 +       }
27720 +
27721 +       buffer_copy_string(ds_dst->key, key);
27722 +       buffer_append_string(ds_dst->value, value);
27723 +       array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27724  }
27725  
27726  
27727  static int proxy_create_env(server *srv, handler_ctx *hctx) {
27728         size_t i;
27729 -       
27730 +
27731         connection *con   = hctx->remote_conn;
27732 +       plugin_data *p    = hctx->plugin_data;
27733         buffer *b;
27734 -       
27735 +
27736         /* build header */
27737  
27738         b = chunkqueue_get_append_buffer(hctx->wb);
27739 -       
27740 +
27741         /* request line */
27742         buffer_copy_string(b, get_http_method_name(con->request.http_method));
27743         BUFFER_APPEND_STRING_CONST(b, " ");
27744 -       
27745 +
27746         buffer_append_string_buffer(b, con->request.uri);
27747         BUFFER_APPEND_STRING_CONST(b, " HTTP/1.0\r\n");
27748  
27749         proxy_append_header(con, "X-Forwarded-For", (char *)inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
27750 -       /* http_host is NOT is just a pointer to a buffer 
27751 +       /* http_host is NOT is just a pointer to a buffer
27752          * which is NULL if it is not set */
27753 -       if (con->request.http_host && 
27754 +       if (con->request.http_host &&
27755             !buffer_is_empty(con->request.http_host)) {
27756                 proxy_set_header(con, "X-Host", con->request.http_host->ptr);
27757         }
27758 @@ -449,24 +491,25 @@
27759         /* request header */
27760         for (i = 0; i < con->request.headers->used; i++) {
27761                 data_string *ds;
27762 -               
27763 +
27764                 ds = (data_string *)con->request.headers->data[i];
27765 -               
27766 -               if (ds->value->used && ds->key->used) {
27767 -                       if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
27768 -                       
27769 -                       buffer_append_string_buffer(b, ds->key);
27770 -                       BUFFER_APPEND_STRING_CONST(b, ": ");
27771 -                       buffer_append_string_buffer(b, ds->value);
27772 -                       BUFFER_APPEND_STRING_CONST(b, "\r\n");
27773 -               }
27774 +
27775 +               if (buffer_is_empty(ds->value) || buffer_is_empty(ds->key)) continue;
27776 +
27777 +               if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
27778 +               if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Keep-Alive"))) continue;
27779 +
27780 +               buffer_append_string_buffer(b, ds->key);
27781 +               BUFFER_APPEND_STRING_CONST(b, ": ");
27782 +               buffer_append_string_buffer(b, ds->value);
27783 +               BUFFER_APPEND_STRING_CONST(b, "\r\n");
27784         }
27785 -       
27786 +
27787         BUFFER_APPEND_STRING_CONST(b, "\r\n");
27788 -       
27789 +
27790         hctx->wb->bytes_in += b->used - 1;
27791         /* body */
27792 -       
27793 +
27794         if (con->request.content_length) {
27795                 chunkqueue *req_cq = con->request_content_queue;
27796                 chunk *req_c;
27797 @@ -479,7 +522,7 @@
27798  
27799                         /* we announce toWrite octects
27800                          * now take all the request_content chunk that we need to fill this request
27801 -                        * */   
27802 +                        * */
27803  
27804                         switch (req_c->type) {
27805                         case FILE_CHUNK:
27806 @@ -507,223 +550,150 @@
27807  
27808                                 req_c->offset += weHave;
27809                                 req_cq->bytes_out += weHave;
27810 -                               
27811 +
27812                                 hctx->wb->bytes_in += weHave;
27813  
27814                                 break;
27815                         default:
27816                                 break;
27817                         }
27818 -                       
27819 +
27820                         offset += weHave;
27821                 }
27822  
27823         }
27824 -       
27825 +
27826         return 0;
27827  }
27828  
27829  static int proxy_set_state(server *srv, handler_ctx *hctx, proxy_connection_state_t state) {
27830         hctx->state = state;
27831         hctx->state_timestamp = srv->cur_ts;
27832 -       
27833 -       return 0;
27834 -}
27835  
27836 -
27837 -static int proxy_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
27838 -       char *s, *ns;
27839 -       int http_response_status = -1;
27840 -       
27841 -       UNUSED(srv);
27842 -
27843 -       /* \r\n -> \0\0 */
27844 -       
27845 -       buffer_copy_string_buffer(p->parse_response, in);
27846 -       
27847 -       for (s = p->parse_response->ptr; NULL != (ns = strstr(s, "\r\n")); s = ns + 2) {
27848 -               char *key, *value;
27849 -               int key_len;
27850 -               data_string *ds;
27851 -               int copy_header;
27852 -               
27853 -               ns[0] = '\0';
27854 -               ns[1] = '\0';
27855 -
27856 -               if (-1 == http_response_status) {
27857 -                       /* The first line of a Response message is the Status-Line */
27858 -
27859 -                       for (key=s; *key && *key != ' '; key++);
27860 -
27861 -                       if (*key) {
27862 -                               http_response_status = (int) strtol(key, NULL, 10);
27863 -                               if (http_response_status <= 0) http_response_status = 502;
27864 -                       } else {
27865 -                               http_response_status = 502;
27866 -                       }
27867 -
27868 -                       con->http_status = http_response_status;
27869 -                       con->parsed_response |= HTTP_STATUS;
27870 -                       continue;
27871 -               }
27872 -               
27873 -               if (NULL == (value = strchr(s, ':'))) {
27874 -                       /* now we expect: "<key>: <value>\n" */
27875 -
27876 -                       continue;
27877 -               }
27878 -
27879 -               key = s;
27880 -               key_len = value - key;
27881 -               
27882 -               value++;
27883 -               /* strip WS */
27884 -               while (*value == ' ' || *value == '\t') value++;
27885 -               
27886 -               copy_header = 1;
27887 -               
27888 -               switch(key_len) {
27889 -               case 4:
27890 -                       if (0 == strncasecmp(key, "Date", key_len)) {
27891 -                               con->parsed_response |= HTTP_DATE;
27892 -                       }
27893 -                       break;
27894 -               case 8:
27895 -                       if (0 == strncasecmp(key, "Location", key_len)) {
27896 -                               con->parsed_response |= HTTP_LOCATION;
27897 -                       }
27898 -                       break;
27899 -               case 10:
27900 -                       if (0 == strncasecmp(key, "Connection", key_len)) {
27901 -                               copy_header = 0;
27902 -                       }
27903 -                       break;
27904 -               case 14:
27905 -                       if (0 == strncasecmp(key, "Content-Length", key_len)) {
27906 -                               con->response.content_length = strtol(value, NULL, 10);
27907 -                               con->parsed_response |= HTTP_CONTENT_LENGTH;
27908 -                       }
27909 -                       break;
27910 -               default:
27911 -                       break;
27912 -               }
27913 -
27914 -               if (copy_header) {
27915 -                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
27916 -                               ds = data_response_init();
27917 -                       }
27918 -                       buffer_copy_string_len(ds->key, key, key_len);
27919 -                       buffer_copy_string(ds->value, value);
27920 -                       
27921 -                       array_insert_unique(con->response.headers, (data_unset *)ds);
27922 -               }
27923 -       }
27924 -       
27925         return 0;
27926  }
27927  
27928  
27929  static int proxy_demux_response(server *srv, handler_ctx *hctx) {
27930 -       int fin = 0;
27931 -       int b;
27932 -       ssize_t r;
27933 -       
27934         plugin_data *p    = hctx->plugin_data;
27935         connection *con   = hctx->remote_conn;
27936 -       int proxy_fd       = hctx->fd;
27937 -       
27938 -       /* check how much we have to read */
27939 -       if (ioctl(hctx->fd, FIONREAD, &b)) {
27940 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
27941 -                               "ioctl failed: ",
27942 -                               proxy_fd);
27943 +       chunkqueue *next_queue = NULL;
27944 +       chunk *c = NULL;
27945 +
27946 +       switch(srv->network_backend_read(srv, con, hctx->sock, hctx->rb)) {
27947 +       case NETWORK_STATUS_SUCCESS:
27948 +               /* we got content */
27949 +               break;
27950 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
27951 +               return 0;
27952 +       case NETWORK_STATUS_CONNECTION_CLOSE:
27953 +               /* we are done, get out of here */
27954 +               con->file_finished = 1;
27955 +
27956 +               /* close the chunk-queue with a empty chunk */
27957 +
27958 +               return 1;
27959 +       default:
27960 +               /* oops */
27961                 return -1;
27962         }
27963  
27964 +       /* looks like we got some content
27965 +       *
27966 +       * split off the header from the incoming stream
27967 +       */
27968  
27969 -       if (p->conf.debug) {
27970 -               log_error_write(srv, __FILE__, __LINE__, "sd",
27971 -                              "proxy - have to read:", b);
27972 -       }
27973 +       if (hctx->state == PROXY_STATE_RESPONSE_HEADER) {
27974 +               size_t i;
27975 +               int have_content_length = 0;
27976  
27977 -       if (b > 0) {
27978 -               if (hctx->response->used == 0) {
27979 -                       /* avoid too small buffer */
27980 -                       buffer_prepare_append(hctx->response, b + 1);
27981 -                       hctx->response->used = 1;
27982 -               } else {
27983 -                       buffer_prepare_append(hctx->response, hctx->response->used + b);
27984 -               }
27985 -               
27986 -               if (-1 == (r = read(hctx->fd, hctx->response->ptr + hctx->response->used - 1, b))) {
27987 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
27988 -                                       "unexpected end-of-file (perhaps the proxy process died):",
27989 -                                       proxy_fd, strerror(errno));
27990 -                       return -1;
27991 -               }
27992 -               
27993 -               /* this should be catched by the b > 0 above */
27994 -               assert(r);
27995 -               
27996 -               hctx->response->used += r;
27997 -               hctx->response->ptr[hctx->response->used - 1] = '\0';
27998 -
27999 -#if 0
28000 -               log_error_write(srv, __FILE__, __LINE__, "sdsbs", 
28001 -                               "demux: Response buffer len", hctx->response->used, ":", hctx->response, ":");
28002 -#endif
28003 +               http_response_reset(p->resp);
28004  
28005 -               if (0 == con->got_response) {
28006 -                       con->got_response = 1;
28007 -                       buffer_prepare_copy(hctx->response_header, 128);
28008 -               }
28009 -                               
28010 -               if (0 == con->file_started) {
28011 -                       char *c;
28012 -                               
28013 -                       /* search for the \r\n\r\n in the string */
28014 -                       if (NULL != (c = buffer_search_string_len(hctx->response, "\r\n\r\n", 4))) {
28015 -                               size_t hlen = c - hctx->response->ptr + 4;
28016 -                               size_t blen = hctx->response->used - hlen - 1;
28017 -                               /* found */
28018 -                               
28019 -                               buffer_append_string_len(hctx->response_header, hctx->response->ptr, c - hctx->response->ptr + 4);
28020 -#if 0
28021 -                               log_error_write(srv, __FILE__, __LINE__, "sb", "Header:", hctx->response_header);
28022 -#endif
28023 -                               /* parse the response header */
28024 -                               proxy_response_parse(srv, con, p, hctx->response_header);
28025 -                                       
28026 -                               /* enable chunked-transfer-encoding */
28027 -                               if (con->request.http_version == HTTP_VERSION_1_1 &&
28028 -                                   !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
28029 -                                       con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
28030 +               /* the response header is not fully received yet,
28031 +               *
28032 +               * extract the http-response header from the rb-cq
28033 +               */
28034 +               switch (http_response_parse_cq(hctx->rb, p->resp)) {
28035 +               case PARSE_ERROR:
28036 +                       /* parsing failed */
28037 +
28038 +                       con->http_status = 502; /* Bad Gateway */
28039 +                       return 1;
28040 +               case PARSE_NEED_MORE:
28041 +                       return 0;
28042 +               case PARSE_SUCCESS:
28043 +                       con->http_status = p->resp->status;
28044 +
28045 +                       chunkqueue_remove_finished_chunks(hctx->rb);
28046 +
28047 +                       /* copy the http-headers */
28048 +                       for (i = 0; i < p->resp->headers->used; i++) {
28049 +                               const char *ign[] = { "Status", "Connection", NULL };
28050 +                               size_t j;
28051 +                               data_string *ds;
28052 +
28053 +                               data_string *header = (data_string *)p->resp->headers->data[i];
28054 +
28055 +                               /* some headers are ignored by default */
28056 +                               for (j = 0; ign[j]; j++) {
28057 +                                       if (0 == strcasecmp(ign[j], header->key->ptr)) break;
28058 +                               }
28059 +                               if (ign[j]) continue;
28060 +
28061 +                               if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
28062 +                                       /* CGI/1.1 rev 03 - 7.2.1.2 */
28063 +                                       if (con->http_status == 0) con->http_status = 302;
28064 +                               } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
28065 +                                       have_content_length = 1;
28066                                 }
28067 -                                       
28068 -                               con->file_started = 1;
28069 -                               if (blen) {
28070 -                                       http_chunk_append_mem(srv, con, c + 4, blen + 1);
28071 -                                       joblist_append(srv, con);
28072 +                               
28073 +                               if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
28074 +                                       ds = data_response_init();
28075                                 }
28076 -                               hctx->response->used = 0;
28077 +                               buffer_copy_string_buffer(ds->key, header->key);
28078 +                               buffer_copy_string_buffer(ds->value, header->value);
28079 +
28080 +                               array_insert_unique(con->response.headers, (data_unset *)ds);
28081                         }
28082 -               } else {
28083 -                       http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
28084 -                       joblist_append(srv, con);
28085 -                       hctx->response->used = 0;
28086 +
28087 +                       con->file_started = 1;
28088 +
28089 +                       if (con->request.http_version == HTTP_VERSION_1_1 &&
28090 +                           !have_content_length) {
28091 +                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
28092 +                       }
28093 +
28094 +                       hctx->state = PROXY_STATE_RESPONSE_CONTENT;
28095 +                       break;
28096                 }
28097 -               
28098 -       } else {
28099 -               /* reading from upstream done */
28100 -               con->file_finished = 1;
28101 -               
28102 -               http_chunk_append_mem(srv, con, NULL, 0);
28103 -               joblist_append(srv, con);
28104 -               
28105 -               fin = 1;
28106         }
28107 -       
28108 -       return fin;
28109 +
28110 +       /* FIXME: pass the response-header to the other plugins to
28111 +       * setup the filter-queue
28112 +       *
28113 +       * - use next-queue instead of con->write_queue
28114 +       */
28115 +
28116 +       next_queue = con->write_queue;
28117 +
28118 +       assert(hctx->state == PROXY_STATE_RESPONSE_CONTENT);
28119 +
28120 +       /* FIXME: if we have a content-length or chunked-encoding
28121 +       * handle it.
28122 +       *
28123 +       * for now we wait for EOF on the socket */
28124 +
28125 +       /* copy the content to the next cq */
28126 +       for (c = hctx->rb->first; c; c = c->next) {
28127 +               http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
28128 +
28129 +               c->offset = c->mem->used - 1;
28130 +       }
28131 +
28132 +       chunkqueue_remove_finished_chunks(hctx->rb);
28133 +       joblist_append(srv, con);
28134 +
28135 +       return 0;
28136  }
28137  
28138  
28139 @@ -731,32 +701,32 @@
28140         data_proxy *host= hctx->host;
28141         plugin_data *p    = hctx->plugin_data;
28142         connection *con   = hctx->remote_conn;
28143 -       
28144 +
28145         int ret;
28146 -       
28147 -       if (!host || 
28148 -           (!host->host->used || !host->port)) return -1;
28149 -       
28150 +
28151 +       if (!host ||
28152 +               (!host->host->used || !host->port)) return -1;
28153 +
28154         switch(hctx->state) {
28155         case PROXY_STATE_INIT:
28156 -               if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) {
28157 +               if (-1 == (hctx->sock->fd = socket(AF_INET, SOCK_STREAM, 0))) {
28158                         log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
28159                         return HANDLER_ERROR;
28160                 }
28161 -               hctx->fde_ndx = -1;
28162 -               
28163 +               hctx->sock->fde_ndx = -1;
28164 +
28165                 srv->cur_fds++;
28166 -               
28167 -               fdevent_register(srv->ev, hctx->fd, proxy_handle_fdevent, hctx);
28168 -               
28169 -               if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
28170 +
28171 +               fdevent_register(srv->ev, hctx->sock, proxy_handle_fdevent, hctx);
28172 +
28173 +               if (-1 == fdevent_fcntl_set(srv->ev, hctx->sock)) {
28174                         log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
28175 -                       
28176 +
28177                         return HANDLER_ERROR;
28178                 }
28179 -               
28180 +
28181                 /* fall through */
28182 -               
28183 +
28184         case PROXY_STATE_CONNECT:
28185                 /* try to finish the connect() */
28186                 if (hctx->state == PROXY_STATE_INIT) {
28187 @@ -764,16 +734,16 @@
28188                         switch (proxy_establish_connection(srv, hctx)) {
28189                         case 1:
28190                                 proxy_set_state(srv, hctx, PROXY_STATE_CONNECT);
28191 -                               
28192 +
28193                                 /* connection is in progress, wait for an event and call getsockopt() below */
28194 -                               
28195 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28196 -                               
28197 +
28198 +                               fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
28199 +
28200                                 return HANDLER_WAIT_FOR_EVENT;
28201                         case -1:
28202                                 /* if ECONNREFUSED choose another connection -> FIXME */
28203 -                               hctx->fde_ndx = -1;
28204 -                               
28205 +                               hctx->sock->fde_ndx = -1;
28206 +
28207                                 return HANDLER_ERROR;
28208                         default:
28209                                 /* everything is ok, go on */
28210 @@ -782,152 +752,152 @@
28211                 } else {
28212                         int socket_error;
28213                         socklen_t socket_error_len = sizeof(socket_error);
28214 -               
28215 -                       /* we don't need it anymore */  
28216 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
28217 +
28218 +                       /* we don't need it anymore */
28219 +                       fdevent_event_del(srv->ev, hctx->sock);
28220  
28221                         /* try to finish the connect() */
28222 -                       if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
28223 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
28224 +                       if (0 != getsockopt(hctx->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
28225 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
28226                                                 "getsockopt failed:", strerror(errno));
28227 -                               
28228 +
28229                                 return HANDLER_ERROR;
28230                         }
28231                         if (socket_error != 0) {
28232                                 log_error_write(srv, __FILE__, __LINE__, "ss",
28233 -                                               "establishing connection failed:", strerror(socket_error), 
28234 +                                               "establishing connection failed:", strerror(socket_error),
28235                                                 "port:", hctx->host->port);
28236 -                               
28237 +
28238                                 return HANDLER_ERROR;
28239                         }
28240                         if (p->conf.debug) {
28241 -                               log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - connect - delayed success"); 
28242 +                               log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - connect - delayed success");
28243                         }
28244                 }
28245 -               
28246 +
28247                 proxy_set_state(srv, hctx, PROXY_STATE_PREPARE_WRITE);
28248                 /* fall through */
28249         case PROXY_STATE_PREPARE_WRITE:
28250                 proxy_create_env(srv, hctx);
28251 -               
28252 +
28253                 proxy_set_state(srv, hctx, PROXY_STATE_WRITE);
28254 -               
28255 +
28256                 /* fall through */
28257         case PROXY_STATE_WRITE:;
28258 -               ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); 
28259 +               ret = srv->network_backend_write(srv, con, hctx->sock, hctx->wb);
28260  
28261                 chunkqueue_remove_finished_chunks(hctx->wb);
28262  
28263 -               if (-1 == ret) {
28264 -                       if (errno != EAGAIN &&
28265 -                           errno != EINTR) {
28266 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
28267 -                               
28268 -                               return HANDLER_ERROR;
28269 -                       } else {
28270 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28271 +               switch(ret) {
28272 +               case NETWORK_STATUS_FATAL_ERROR:
28273 +                       log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
28274  
28275 -                               return HANDLER_WAIT_FOR_EVENT;
28276 -                       }
28277 +                       return HANDLER_ERROR;
28278 +               case NETWORK_STATUS_WAIT_FOR_EVENT:
28279 +
28280 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
28281 +
28282 +                       return HANDLER_WAIT_FOR_EVENT;
28283                 }
28284  
28285                 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
28286 -                       proxy_set_state(srv, hctx, PROXY_STATE_READ);
28287 +                       proxy_set_state(srv, hctx, PROXY_STATE_RESPONSE_HEADER);
28288  
28289 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
28290 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
28291 +                       fdevent_event_del(srv->ev, hctx->sock);
28292 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
28293                 } else {
28294 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28295 -                               
28296 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
28297 +
28298                         return HANDLER_WAIT_FOR_EVENT;
28299                 }
28300 -               
28301 +
28302                 return HANDLER_WAIT_FOR_EVENT;
28303 -       case PROXY_STATE_READ:
28304 +       case PROXY_STATE_RESPONSE_CONTENT:
28305 +       case PROXY_STATE_RESPONSE_HEADER:
28306                 /* waiting for a response */
28307 +
28308                 return HANDLER_WAIT_FOR_EVENT;
28309         default:
28310                 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
28311                 return HANDLER_ERROR;
28312         }
28313 -       
28314 +
28315         return HANDLER_GO_ON;
28316  }
28317  
28318 -#define PATCH(x) \
28319 -       p->conf.x = s->x;
28320  static int mod_proxy_patch_connection(server *srv, connection *con, plugin_data *p) {
28321         size_t i, j;
28322         plugin_config *s = p->config_storage[0];
28323 -       
28324 -       PATCH(extensions);
28325 -       PATCH(debug);
28326 -       PATCH(balance);
28327 -       
28328 +
28329 +       PATCH_OPTION(extensions);
28330 +       PATCH_OPTION(debug);
28331 +       PATCH_OPTION(balance);
28332 +       PATCH_OPTION(last_used_backends);
28333 +
28334         /* skip the first, the global context */
28335         for (i = 1; i < srv->config_context->used; i++) {
28336                 data_config *dc = (data_config *)srv->config_context->data[i];
28337                 s = p->config_storage[i];
28338 -               
28339 +
28340                 /* condition didn't match */
28341                 if (!config_check_cond(srv, con, dc)) continue;
28342 -               
28343 +
28344                 /* merge config */
28345                 for (j = 0; j < dc->value->used; j++) {
28346                         data_unset *du = dc->value->data[j];
28347 -                       
28348 +
28349                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.server"))) {
28350 -                               PATCH(extensions);
28351 +                               PATCH_OPTION(extensions);
28352                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.debug"))) {
28353 -                               PATCH(debug);
28354 +                               PATCH_OPTION(debug);
28355                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.balance"))) {
28356 -                               PATCH(balance);
28357 +                               PATCH_OPTION(balance);
28358 +                               PATCH_OPTION(last_used_backends);
28359                         }
28360                 }
28361         }
28362 -       
28363 +
28364         return 0;
28365  }
28366 -#undef PATCH
28367  
28368  SUBREQUEST_FUNC(mod_proxy_handle_subrequest) {
28369         plugin_data *p = p_d;
28370 -       
28371 +
28372         handler_ctx *hctx = con->plugin_ctx[p->id];
28373         data_proxy *host;
28374 -       
28375 +
28376         if (NULL == hctx) return HANDLER_GO_ON;
28377  
28378         mod_proxy_patch_connection(srv, con, p);
28379 -       
28380 +
28381         host = hctx->host;
28382 -       
28383 +
28384         /* not my job */
28385         if (con->mode != p->id) return HANDLER_GO_ON;
28386 -       
28387 +
28388         /* ok, create the request */
28389         switch(proxy_write_request(srv, hctx)) {
28390         case HANDLER_ERROR:
28391 -               log_error_write(srv, __FILE__, __LINE__,  "sbdd", "proxy-server disabled:", 
28392 +               log_error_write(srv, __FILE__, __LINE__,  "sbdd", "proxy-server disabled:",
28393                                 host->host,
28394                                 host->port,
28395 -                               hctx->fd);
28396 -               
28397 +                               hctx->sock->fd);
28398 +
28399                 /* disable this server */
28400                 host->is_disabled = 1;
28401                 host->disable_ts = srv->cur_ts;
28402 -               
28403 +
28404                 proxy_connection_close(srv, hctx);
28405 -       
28406 -               /* reset the enviroment and restart the sub-request */  
28407 +
28408 +               /* reset the enviroment and restart the sub-request */
28409                 buffer_reset(con->physical.path);
28410                 con->mode = DIRECT;
28411  
28412                 joblist_append(srv, con);
28413  
28414 -               /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop 
28415 -                * and hope that the childs will be restarted 
28416 -                * 
28417 +               /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
28418 +                * and hope that the childs will be restarted
28419 +                *
28420                  */
28421  
28422                 return HANDLER_WAIT_FOR_FD;
28423 @@ -938,7 +908,7 @@
28424         default:
28425                 break;
28426         }
28427 -       
28428 +
28429         if (con->file_started == 1) {
28430                 return HANDLER_FINISHED;
28431         } else {
28432 @@ -951,13 +921,14 @@
28433         handler_ctx *hctx = ctx;
28434         connection  *con  = hctx->remote_conn;
28435         plugin_data *p    = hctx->plugin_data;
28436 -       
28437 -       
28438 +
28439 +
28440         if ((revents & FDEVENT_IN) &&
28441 -           hctx->state == PROXY_STATE_READ) {
28442 +           (hctx->state == PROXY_STATE_RESPONSE_HEADER ||
28443 +            hctx->state == PROXY_STATE_RESPONSE_CONTENT)) {
28444  
28445                 if (p->conf.debug) {
28446 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
28447 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
28448                                         "proxy: fdevent-in", hctx->state);
28449                 }
28450  
28451 @@ -965,11 +936,15 @@
28452                 case 0:
28453                         break;
28454                 case 1:
28455 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
28456 +                                       "proxy: request done", hctx->sock->fd);
28457                         hctx->host->usage--;
28458 -                       
28459 +
28460 +                       http_chunk_append_mem(srv, con, NULL, 0);
28461 +
28462                         /* we are done */
28463                         proxy_connection_close(srv, hctx);
28464 -                       
28465 +
28466                         joblist_append(srv, con);
28467                         return HANDLER_FINISHED;
28468                 case -1:
28469 @@ -982,53 +957,53 @@
28470                                 /* response might have been already started, kill the connection */
28471                                 connection_set_state(srv, con, CON_STATE_ERROR);
28472                         }
28473 -                       
28474 +
28475                         joblist_append(srv, con);
28476                         return HANDLER_FINISHED;
28477                 }
28478         }
28479 -       
28480 +
28481         if (revents & FDEVENT_OUT) {
28482                 if (p->conf.debug) {
28483 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
28484 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
28485                                         "proxy: fdevent-out", hctx->state);
28486                 }
28487  
28488                 if (hctx->state == PROXY_STATE_CONNECT ||
28489                     hctx->state == PROXY_STATE_WRITE) {
28490                         /* we are allowed to send something out
28491 -                        * 
28492 +                        *
28493                          * 1. in a unfinished connect() call
28494                          * 2. in a unfinished write() call (long POST request)
28495                          */
28496                         return mod_proxy_handle_subrequest(srv, con, p);
28497                 } else {
28498 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
28499 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
28500                                         "proxy: out", hctx->state);
28501                 }
28502         }
28503 -       
28504 +
28505         /* perhaps this issue is already handled */
28506         if (revents & FDEVENT_HUP) {
28507                 if (p->conf.debug) {
28508 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
28509 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
28510                                         "proxy: fdevent-hup", hctx->state);
28511                 }
28512 -               
28513 +
28514                 if (hctx->state == PROXY_STATE_CONNECT) {
28515                         /* connect() -> EINPROGRESS -> HUP */
28516 -                       
28517 +
28518                         /**
28519 -                        * what is proxy is doing if it can't reach the next hop ? 
28520 -                        * 
28521 +                        * what is proxy is doing if it can't reach the next hop ?
28522 +                        *
28523                          */
28524 -                       
28525 +
28526                         proxy_connection_close(srv, hctx);
28527                         joblist_append(srv, con);
28528 -                       
28529 +
28530                         con->http_status = 503;
28531                         con->mode = DIRECT;
28532 -                       
28533 +
28534                         return HANDLER_FINISHED;
28535                 }
28536  
28537 @@ -1038,13 +1013,13 @@
28538                 joblist_append(srv, con);
28539         } else if (revents & FDEVENT_ERR) {
28540                 /* kill all connections to the proxy process */
28541 -               
28542 +
28543                 log_error_write(srv, __FILE__, __LINE__, "sd", "proxy-FDEVENT_ERR, but no HUP", revents);
28544  
28545                 joblist_append(srv, con);
28546                 proxy_connection_close(srv, hctx);
28547         }
28548 -       
28549 +
28550         return HANDLER_FINISHED;
28551  }
28552  
28553 @@ -1058,44 +1033,48 @@
28554         buffer *fn;
28555         data_array *extension = NULL;
28556         size_t path_info_offset;
28557 -       
28558 +       data_integer *last_used_backend;
28559 +       data_proxy *host = NULL;
28560 +       handler_ctx *hctx = NULL;
28561 +
28562 +       array *backends = NULL;
28563 +
28564         /* Possibly, we processed already this request */
28565         if (con->file_started == 1) return HANDLER_GO_ON;
28566 -       
28567 +
28568         mod_proxy_patch_connection(srv, con, p);
28569 -       
28570 +
28571         fn = con->uri.path;
28572  
28573         if (fn->used == 0) {
28574                 return HANDLER_ERROR;
28575         }
28576 -       
28577 +
28578         s_len = fn->used - 1;
28579 -       
28580 -       
28581 +
28582         path_info_offset = 0;
28583  
28584 -       if (p->conf.debug) {    
28585 +       if (p->conf.debug) {
28586                 log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - start");
28587         }
28588  
28589         /* check if extension matches */
28590         for (k = 0; k < p->conf.extensions->used; k++) {
28591                 size_t ct_len;
28592 -               
28593 +
28594                 extension = (data_array *)p->conf.extensions->data[k];
28595 -               
28596 +
28597                 if (extension->key->used == 0) continue;
28598 -               
28599 +
28600                 ct_len = extension->key->used - 1;
28601 -               
28602 +
28603                 if (s_len < ct_len) continue;
28604 -               
28605 +
28606                 /* check extension in the form "/proxy_pattern" */
28607                 if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
28608                         if (s_len > ct_len + 1) {
28609                                 char *pi_offset;
28610 -                               
28611 +
28612                                 if (0 != (pi_offset = strchr(fn->ptr + ct_len + 1, '/'))) {
28613                                         path_info_offset = pi_offset - fn->ptr;
28614                                 }
28615 @@ -1106,12 +1085,14 @@
28616                         break;
28617                 }
28618         }
28619 -       
28620 +
28621         if (k == p->conf.extensions->used) {
28622                 return HANDLER_GO_ON;
28623         }
28624  
28625 -       if (p->conf.debug) {    
28626 +       backends = extension->value;
28627 +
28628 +       if (p->conf.debug) {
28629                 log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - ext found");
28630         }
28631  
28632 @@ -1120,34 +1101,34 @@
28633                 /* hash balancing */
28634  
28635                 if (p->conf.debug) {
28636 -                       log_error_write(srv, __FILE__, __LINE__,  "sd", 
28637 -                                       "proxy - used hash balancing, hosts:", extension->value->used);
28638 +                       log_error_write(srv, __FILE__, __LINE__,  "sd",
28639 +                                       "proxy - used hash balancing, hosts:", backends->used);
28640                 }
28641  
28642 -               for (k = 0, ndx = -1, last_max = ULONG_MAX; k < extension->value->used; k++) {
28643 -                       data_proxy *host = (data_proxy *)extension->value->data[k];
28644 +               for (k = 0, ndx = -1, last_max = ULONG_MAX; k < backends->used; k++) {
28645                         unsigned long cur_max;
28646  
28647 -                       if (host->is_disabled) continue;
28648 -                       
28649 +                       data_proxy *cur = (data_proxy *)backends->data[k];
28650 +
28651 +                       if (cur->is_disabled) continue;
28652 +
28653                         cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) +
28654 -                               generate_crc32c(CONST_BUF_LEN(host->host)) + /* we can cache this */
28655 +                               generate_crc32c(CONST_BUF_LEN(cur->host)) + /* we can cache this */
28656                                 generate_crc32c(CONST_BUF_LEN(con->uri.authority));
28657 -                       
28658 +
28659                         if (p->conf.debug) {
28660 -                               log_error_write(srv, __FILE__, __LINE__,  "sbbbd", 
28661 +                               log_error_write(srv, __FILE__, __LINE__,  "sbbbd",
28662                                                 "proxy - election:",
28663                                                 con->uri.path,
28664 -                                               host->host,
28665 +                                               cur->host,
28666                                                 con->uri.authority,
28667                                                 cur_max);
28668                         }
28669  
28670 -                       if ((last_max == ULONG_MAX) || /* first round */
28671 -                           (cur_max > last_max)) {
28672 +                       if (host == NULL || (cur_max > last_max)) {
28673                                 last_max = cur_max;
28674  
28675 -                               ndx = k;
28676 +                               host = cur;
28677                         }
28678                 }
28679  
28680 @@ -1155,19 +1136,20 @@
28681         case PROXY_BALANCE_FAIR:
28682                 /* fair balancing */
28683                 if (p->conf.debug) {
28684 -                       log_error_write(srv, __FILE__, __LINE__,  "s", 
28685 +                       log_error_write(srv, __FILE__, __LINE__,  "s",
28686                                         "proxy - used fair balancing");
28687                 }
28688  
28689 -               for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) {
28690 -                       data_proxy *host = (data_proxy *)extension->value->data[k];
28691 -               
28692 -                       if (host->is_disabled) continue;
28693 -
28694 -                       if (host->usage < max_usage) {
28695 -                               max_usage = host->usage;
28696 -                       
28697 -                               ndx = k;
28698 +               /* try to find the host with the lowest load */
28699 +               for (k = 0, max_usage = 0; k < backends->used; k++) {
28700 +                       data_proxy *cur = (data_proxy *)backends->data[k];
28701 +
28702 +                       if (cur->is_disabled) continue;
28703 +
28704 +                       if (NULL == host || cur->usage < max_usage) {
28705 +                               max_usage = cur->usage;
28706 +
28707 +                               host = cur;
28708                         }
28709                 }
28710  
28711 @@ -1175,89 +1157,100 @@
28712         case PROXY_BALANCE_RR:
28713                 /* round robin */
28714                 if (p->conf.debug) {
28715 -                       log_error_write(srv, __FILE__, __LINE__,  "s", 
28716 +                       log_error_write(srv, __FILE__, __LINE__,  "s",
28717                                         "proxy - used round-robin balancing");
28718                 }
28719  
28720                 /* just to be sure */
28721 -               assert(extension->value->used < INT_MAX);
28722 -               
28723 -               for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) {
28724 -                       data_proxy *host = (data_proxy *)extension->value->data[k];
28725 -               
28726 -                       if (host->is_disabled) continue;
28727 -
28728 -                       /* first usable ndx */
28729 -                       if (max_usage == INT_MAX) {
28730 -                               max_usage = k;
28731 -                       }
28732 +               assert(backends->used < INT_MAX);
28733  
28734 -                       /* get next ndx */
28735 -                       if ((int)k > host->last_used_ndx) {
28736 -                               ndx = k;
28737 -                               host->last_used_ndx = k;
28738 +               /* send each request to another host:
28739 +                *
28740 +                * e.g.:
28741 +                *
28742 +                * if we have three hosts it is
28743 +                *
28744 +                * 1 .. 2 .. 3 .. 1 .. 2 .. 3
28745 +                *
28746 +                **/
28747  
28748 -                               break;
28749 -                       }
28750 +               /* walk through the list */
28751 +               last_used_backend = (data_integer *)array_get_element(p->conf.last_used_backends, extension->key->ptr);
28752 +
28753 +               if (NULL == last_used_backend) {
28754 +                       last_used_backend = data_integer_init();
28755 +
28756 +                       buffer_copy_string_buffer(last_used_backend->key, extension->key);
28757 +                       last_used_backend->value = 0;
28758 +
28759 +                       array_insert_unique(p->conf.last_used_backends, (data_unset *)last_used_backend);
28760 +               }
28761 +
28762 +               /* scan all but the last host to see if they are up
28763 +                * take the first running host */
28764 +               for (k = last_used_backend->value + 1; (int)(k % backends->used) != last_used_backend->value; k++) {
28765 +                       data_proxy *cur = (data_proxy *)backends->data[k % backends->used];
28766 +
28767 +                       if (cur->is_disabled) continue;
28768 +
28769 +                       host = cur;
28770 +
28771 +                       last_used_backend->value = k;
28772 +
28773 +                       break;
28774                 }
28775 -               
28776 -               /* didn't found a higher id, wrap to the start */
28777 -               if (ndx != -1 && max_usage != INT_MAX) {
28778 -                       ndx = max_usage;
28779 +
28780 +               if (NULL == host) {
28781 +                       /* we found nothing better, fallback to the last used backend
28782 +                        * and check if it is still up */
28783 +                       host = (data_proxy *)backends->data[last_used_backend->value];
28784 +
28785 +                       if (host->is_disabled) host = NULL;
28786                 }
28787  
28788                 break;
28789         default:
28790                 break;
28791         }
28792 -       
28793 -       /* found a server */
28794 -       if (ndx != -1) {
28795 -               data_proxy *host = (data_proxy *)extension->value->data[ndx];
28796 -               
28797 -               /* 
28798 -                * if check-local is disabled, use the uri.path handler 
28799 -                * 
28800 -                */
28801 -               
28802 -               /* init handler-context */
28803 -               handler_ctx *hctx;
28804 -               hctx = handler_ctx_init();
28805 -                               
28806 -               hctx->path_info_offset = path_info_offset;
28807 -               hctx->remote_conn      = con;
28808 -               hctx->plugin_data      = p;
28809 -               hctx->host             = host;
28810 -                               
28811 -               con->plugin_ctx[p->id] = hctx;
28812 -               
28813 -               host->usage++;
28814 -               
28815 -               con->mode = p->id;
28816 -               
28817 -               if (p->conf.debug) {
28818 -                       log_error_write(srv, __FILE__, __LINE__,  "sbd", 
28819 -                                       "proxy - found a host",
28820 -                                       host->host, host->port);
28821 -               }
28822  
28823 -               return HANDLER_GO_ON;
28824 -       } else {
28825 -               /* no handler found */
28826 +       /* we havn't found a host */
28827 +       if (NULL == host) {
28828                 con->http_status = 500;
28829 -               
28830 -               log_error_write(srv, __FILE__, __LINE__,  "sb", 
28831 -                               "no proxy-handler found for:", 
28832 +
28833 +               log_error_write(srv, __FILE__, __LINE__,  "sb",
28834 +                               "no proxy-handler found for:",
28835                                 fn);
28836 -               
28837 +
28838                 return HANDLER_FINISHED;
28839         }
28840 +
28841 +       /* init handler-context */
28842 +       hctx = handler_ctx_init();
28843 +
28844 +       hctx->path_info_offset = path_info_offset;
28845 +       hctx->remote_conn      = con;
28846 +       hctx->plugin_data      = p;
28847 +       hctx->host             = host;
28848 +
28849 +       con->plugin_ctx[p->id] = hctx;
28850 +
28851 +       host->usage++;
28852 +
28853 +       /* we handle this request */
28854 +       con->mode = p->id;
28855 +
28856 +       if (p->conf.debug) {
28857 +               log_error_write(srv, __FILE__, __LINE__,  "sbd",
28858 +                               "proxy - found a host",
28859 +                               host->host, host->port);
28860 +       }
28861 +
28862         return HANDLER_GO_ON;
28863  }
28864  
28865  static handler_t mod_proxy_connection_close_callback(server *srv, connection *con, void *p_d) {
28866         plugin_data *p = p_d;
28867 -       
28868 +
28869         proxy_connection_close(srv, con->plugin_ctx[p->id]);
28870  
28871         return HANDLER_GO_ON;
28872 @@ -1276,11 +1269,11 @@
28873                 size_t i, n, k;
28874                 for (i = 0; i < srv->config_context->used; i++) {
28875                         plugin_config *s = p->config_storage[i];
28876 -                       
28877 -                       if (!s) continue; 
28878 +
28879 +                       if (!s) continue;
28880  
28881                         /* get the extensions for all configs */
28882 -                       
28883 +
28884                         for (k = 0; k < s->extensions->used; k++) {
28885                                 data_array *extension = (data_array *)s->extensions->data[k];
28886  
28887 @@ -1290,8 +1283,8 @@
28888  
28889                                         if (!host->is_disabled ||
28890                                             srv->cur_ts - host->disable_ts < 5) continue;
28891 -                       
28892 -                                       log_error_write(srv, __FILE__, __LINE__,  "sbd", 
28893 +
28894 +                                       log_error_write(srv, __FILE__, __LINE__,  "sbd",
28895                                                         "proxy - re-enabled:",
28896                                                         host->host, host->port);
28897  
28898 @@ -1317,8 +1310,8 @@
28899         p->handle_uri_clean        = mod_proxy_check_extension;
28900         p->handle_subrequest       = mod_proxy_handle_subrequest;
28901         p->handle_trigger          = mod_proxy_trigger;
28902 -       
28903 +
28904         p->data         = NULL;
28905 -       
28906 +
28907         return 0;
28908  }
28909 --- ../lighttpd-1.4.11/src/mod_proxy_core.c     1970-01-01 03:00:00.000000000 +0300
28910 +++ lighttpd-1.4.12/src/mod_proxy_core.c        2006-07-19 20:02:55.000000000 +0300
28911 @@ -0,0 +1,1713 @@
28912 +#include <string.h>
28913 +#include <stdlib.h>
28914 +#include <fcntl.h>
28915 +#include <errno.h>
28916 +#include <ctype.h>
28917 +
28918 +#include "buffer.h"
28919 +#include "array.h"
28920 +#include "log.h"
28921 +
28922 +#include "base.h"
28923 +#include "plugin.h"
28924 +#include "joblist.h"
28925 +#include "sys-files.h"
28926 +#include "inet_ntop_cache.h"
28927 +#include "http_resp.h"
28928 +#include "http_chunk.h"
28929 +#include "crc32.h"
28930 +
28931 +#include "mod_proxy_core_pool.h"       
28932 +#include "mod_proxy_core_backend.h"
28933 +#include "mod_proxy_core_backlog.h"
28934 +#include "mod_proxy_core_rewrites.h"
28935 +
28936 +#define CONFIG_PROXY_CORE_BALANCER "proxy-core.balancer"
28937 +#define CONFIG_PROXY_CORE_PROTOCOL "proxy-core.protocol"
28938 +#define CONFIG_PROXY_CORE_DEBUG "proxy-core.debug"
28939 +#define CONFIG_PROXY_CORE_BACKENDS "proxy-core.backends"
28940 +#define CONFIG_PROXY_CORE_REWRITE_REQUEST "proxy-core.rewrite-request"
28941 +#define CONFIG_PROXY_CORE_REWRITE_RESPONSE "proxy-core.rewrite-response"
28942 +
28943 +typedef enum {
28944 +       PROXY_PROTOCOL_UNSET,
28945 +       PROXY_PROTOCOL_HTTP,
28946 +       PROXY_PROTOCOL_HTTPS,
28947 +       PROXY_PROTOCOL_FASTCGI,
28948 +       PROXY_PROTOCOL_SCGI
28949 +} proxy_protocol_t;
28950 +
28951 +typedef struct {
28952 +       proxy_backends *backends;
28953 +
28954 +       proxy_backlog *backlog;
28955 +
28956 +       proxy_rewrites *request_rewrites;
28957 +       proxy_rewrites *response_rewrites;
28958 +
28959 +       int debug;
28960 +
28961 +       proxy_balance_t balancer;
28962 +       proxy_protocol_t protocol;
28963 +} plugin_config;
28964 +
28965 +typedef struct {
28966 +       PLUGIN_DATA;
28967 +
28968 +       http_resp *resp;
28969 +
28970 +       array *possible_balancers;
28971 +       array *possible_protocols;
28972 +
28973 +       /* for parsing only */
28974 +       array *backends_arr;
28975 +       buffer *protocol_buf;
28976 +       buffer *balance_buf;
28977 +
28978 +       buffer *replace_buf;
28979 +
28980 +       plugin_config **config_storage;
28981 +
28982 +       plugin_config conf;
28983 +} plugin_data;
28984 +
28985 +int array_insert_int(array *a, const char *key, int val) {
28986 +       data_integer *di;
28987 +
28988 +       if (NULL == (di = (data_integer *)array_get_unused_element(a, TYPE_INTEGER))) {
28989 +               di = data_integer_init();
28990 +       }
28991 +
28992 +       buffer_copy_string(di->key, key);
28993 +       di->value = val;
28994 +       array_insert_unique(a, (data_unset *)di);
28995 +
28996 +       return 0;
28997 +}
28998 +
28999 +INIT_FUNC(mod_proxy_core_init) {
29000 +       plugin_data *p;
29001 +
29002 +       p = calloc(1, sizeof(*p));
29003 +
29004 +       /* create some backends as long as we don't have the config-parser */
29005 +
29006 +       p->possible_balancers = array_init();
29007 +       array_insert_int(p->possible_balancers, "fair", PROXY_BALANCE_FAIR);
29008 +       array_insert_int(p->possible_balancers, "hash", PROXY_BALANCE_HASH);
29009 +       array_insert_int(p->possible_balancers, "round-robin", PROXY_BALANCE_RR);
29010 +
29011 +       p->possible_protocols = array_init();
29012 +       array_insert_int(p->possible_protocols, "http", PROXY_PROTOCOL_HTTP);
29013 +       array_insert_int(p->possible_protocols, "fastcgi", PROXY_PROTOCOL_FASTCGI);
29014 +       array_insert_int(p->possible_protocols, "scgi", PROXY_PROTOCOL_SCGI);
29015 +       array_insert_int(p->possible_protocols, "https", PROXY_PROTOCOL_HTTPS);
29016 +
29017 +       p->balance_buf = buffer_init();
29018 +       p->protocol_buf = buffer_init();
29019 +       p->replace_buf = buffer_init();
29020 +       p->backends_arr = array_init();
29021 +
29022 +       p->resp = http_response_init();
29023 +
29024 +       return p;
29025 +}
29026 +
29027 +FREE_FUNC(mod_proxy_core_free) {
29028 +       plugin_data *p = p_d;
29029 +
29030 +       if (!p) return HANDLER_GO_ON;
29031 +
29032 +       if (p->config_storage) {
29033 +               size_t i;
29034 +               for (i = 0; i < srv->config_context->used; i++) {
29035 +                       plugin_config *s = p->config_storage[i];
29036 +
29037 +                       if (!s) continue;
29038 +
29039 +                       proxy_backends_free(s->backends);
29040 +                       proxy_backlog_free(s->backlog);
29041 +
29042 +
29043 +                       free(s);
29044 +               }
29045 +               free(p->config_storage);
29046 +       }
29047 +
29048 +       array_free(p->possible_protocols);
29049 +       array_free(p->possible_balancers);
29050 +       array_free(p->backends_arr);
29051 +
29052 +       buffer_free(p->balance_buf);
29053 +       buffer_free(p->protocol_buf);
29054 +       buffer_free(p->replace_buf);
29055 +       
29056 +       http_response_free(p->resp);
29057 +
29058 +       free(p);
29059 +
29060 +       return HANDLER_GO_ON;
29061 +}
29062 +
29063 +static handler_t mod_proxy_core_config_parse_rewrites(proxy_rewrites *dest, array *src, const char *config_key) {
29064 +       data_unset *du;
29065 +       size_t j;
29066 +
29067 +       if (NULL != (du = array_get_element(src, config_key))) {
29068 +               data_array *keys = (data_array *)du;
29069 +
29070 +               if (keys->type != TYPE_ARRAY) {
29071 +                       ERROR("%s = <...>", 
29072 +                               config_key);
29073 +
29074 +                       return HANDLER_ERROR;
29075 +               }
29076 +
29077 +               /*
29078 +                * proxy-core.rewrite-request = (
29079 +                *   "_uri" => ( ... ) 
29080 +                * )
29081 +                */
29082 +
29083 +               for (j = 0; j < keys->value->used; j++) {
29084 +                       size_t k;
29085 +                       data_array *headers = (data_array *)keys->value->data[j];
29086 +
29087 +                       /* keys->key should be "_uri" and the value a array of rewrite */
29088 +                       if (headers->type != TYPE_ARRAY) {
29089 +                               ERROR("%s = ( %s => <...> ) has to a array", 
29090 +                                       config_key,
29091 +                                       BUF_STR(headers->key));
29092 +
29093 +                               return HANDLER_ERROR;
29094 +                       }
29095 +
29096 +                       if (headers->value->used > 1) {
29097 +                               ERROR("%s = ( %s => <...> ) has to a array with only one element", 
29098 +                                       config_key,
29099 +                                       BUF_STR(headers->key));
29100 +
29101 +                               return HANDLER_ERROR;
29102 +
29103 +                       }
29104 +
29105 +                       for (k = 0; k < headers->value->used; k++) {
29106 +                               data_string *rewrites = (data_string *)headers->value->data[k];
29107 +                               proxy_rewrite *rw;
29108 +
29109 +                               /* keys->key should be "_uri" and the value a array of rewrite */
29110 +                               if (rewrites->type != TYPE_STRING) {
29111 +                                       ERROR("%s = ( \"%s\" => ( \"%s\" => <value> ) ) has to a string", 
29112 +                                               config_key,
29113 +                                               BUF_STR(headers->key),
29114 +                                               BUF_STR(rewrites->key));
29115 +
29116 +                                       return HANDLER_ERROR;
29117 +                               }
29118 +                       
29119 +                               rw = proxy_rewrite_init();
29120 +
29121 +                               if (0 != proxy_rewrite_set_regex(rw, rewrites->key)) {
29122 +                                       return HANDLER_ERROR;
29123 +                               }
29124 +                               buffer_copy_string_buffer(rw->replace, rewrites->value);
29125 +                               buffer_copy_string_buffer(rw->match, rewrites->key);
29126 +                               buffer_copy_string_buffer(rw->header, headers->key);
29127 +
29128 +                               proxy_rewrites_add(dest, rw);
29129 +                       }
29130 +               }
29131 +       }
29132 +
29133 +       return HANDLER_GO_ON;
29134 +}
29135 +
29136 +
29137 +SETDEFAULTS_FUNC(mod_proxy_core_set_defaults) {
29138 +       plugin_data *p = p_d;
29139 +       size_t i, j;
29140 +
29141 +       config_values_t cv[] = {
29142 +               { CONFIG_PROXY_CORE_BACKENDS,       NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
29143 +               { CONFIG_PROXY_CORE_DEBUG,          NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
29144 +               { CONFIG_PROXY_CORE_BALANCER,       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 2 */
29145 +               { CONFIG_PROXY_CORE_PROTOCOL,       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 3 */
29146 +               { CONFIG_PROXY_CORE_REWRITE_REQUEST, NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
29147 +               { CONFIG_PROXY_CORE_REWRITE_RESPONSE, NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },/* 5 */
29148 +               { NULL,                        NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
29149 +       };
29150 +
29151 +       p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
29152 +
29153 +       for (i = 0; i < srv->config_context->used; i++) {
29154 +               plugin_config *s;
29155 +               array *ca;
29156 +               proxy_backend *backend;
29157 +
29158 +               array_reset(p->backends_arr);
29159 +               buffer_reset(p->balance_buf);
29160 +               buffer_reset(p->protocol_buf);
29161 +
29162 +               s = malloc(sizeof(plugin_config));
29163 +               s->debug     = 0;
29164 +               s->balancer  = PROXY_BALANCE_UNSET;
29165 +               s->protocol  = PROXY_PROTOCOL_UNSET;
29166 +               s->backends  = proxy_backends_init();
29167 +               s->backlog   = proxy_backlog_init();
29168 +               s->response_rewrites   = proxy_rewrites_init();
29169 +               s->request_rewrites   = proxy_rewrites_init();
29170 +
29171 +               cv[0].destination = p->backends_arr;
29172 +               cv[1].destination = &(s->debug);
29173 +               cv[2].destination = p->balance_buf; /* parse into a constant */
29174 +               cv[3].destination = p->protocol_buf; /* parse into a constant */
29175 +
29176 +               buffer_reset(p->balance_buf);
29177 +
29178 +               p->config_storage[i] = s;
29179 +               ca = ((data_config *)srv->config_context->data[i])->value;
29180 +
29181 +               if (0 != config_insert_values_global(srv, ca, cv)) {
29182 +                       return HANDLER_ERROR;
29183 +               }
29184 +
29185 +               if (!buffer_is_empty(p->balance_buf)) {
29186 +                       data_integer *di;
29187 +                       
29188 +                       if (NULL == (di = (data_integer *)array_get_element(p->possible_balancers, BUF_STR(p->balance_buf)))) {
29189 +                               ERROR("proxy.balance has to be on of 'fair', 'round-robin', 'hash', got %s", BUF_STR(p->balance_buf));
29190 +
29191 +                               return HANDLER_ERROR;
29192 +                       }
29193 +
29194 +                       s->balancer = di->value;
29195 +               }
29196 +
29197 +               if (!buffer_is_empty(p->protocol_buf)) {
29198 +                       data_integer *di;
29199 +                       
29200 +                       if (NULL == (di = (data_integer *)array_get_element(p->possible_protocols, BUF_STR(p->protocol_buf)))) {
29201 +                               ERROR("proxy.balance has to be on of 'fair', 'round-robin', 'hash', got %s", BUF_STR(p->protocol_buf));
29202 +
29203 +                               return HANDLER_ERROR;
29204 +                       }
29205 +
29206 +                       s->protocol = di->value;
29207 +               }
29208 +
29209 +               if (p->backends_arr->used) {
29210 +                       backend = proxy_backend_init();
29211 +
29212 +                       /* check if the backends have a valid host-name */
29213 +                       for (j = 0; j < p->backends_arr->used; j++) {
29214 +                               data_string *ds = (data_string *)p->backends_arr->data[j];
29215 +
29216 +                               /* the values should be ips or hostnames */
29217 +                               if (0 != proxy_address_pool_add_string(backend->address_pool, ds->value)) {
29218 +                                       return HANDLER_ERROR;
29219 +                               }
29220 +                       }
29221 +
29222 +                       proxy_backends_add(s->backends, backend);
29223 +               }
29224 +
29225 +               if (HANDLER_GO_ON != mod_proxy_core_config_parse_rewrites(s->request_rewrites, ca, CONFIG_PROXY_CORE_REWRITE_REQUEST)) {
29226 +                       return HANDLER_ERROR;
29227 +               }
29228 +               
29229 +               if (HANDLER_GO_ON != mod_proxy_core_config_parse_rewrites(s->response_rewrites, ca, CONFIG_PROXY_CORE_REWRITE_RESPONSE)) {
29230 +                       return HANDLER_ERROR;
29231 +               }
29232 +       }
29233 +
29234 +       return HANDLER_GO_ON;
29235 +}
29236 +
29237 +
29238 +typedef enum {
29239 +       PROXY_STATE_UNSET,
29240 +       PROXY_STATE_CONNECTING,
29241 +       PROXY_STATE_CONNECTED,
29242 +       PROXY_STATE_WRITE_REQUEST_HEADER,
29243 +       PROXY_STATE_WRITE_REQUEST_BODY,
29244 +       PROXY_STATE_READ_RESPONSE_HEADER,
29245 +       PROXY_STATE_READ_RESPONSE_BODY
29246 +} proxy_state_t;
29247 +
29248 +typedef struct {
29249 +       proxy_connection *proxy_con;
29250 +       proxy_backend *proxy_backend;
29251 +
29252 +       connection *remote_con;
29253 +
29254 +       array *request_headers;
29255 +
29256 +       int is_chunked;
29257 +       
29258 +       /**
29259 +        * chunkqueues
29260 +        * - the encoded_rb is the raw network stuff
29261 +        * - the rb is filtered through the stream decoder
29262 +        *
29263 +        * - wb is the normal bytes stream
29264 +        * - encoded_wb is encoded for the network by the stream encoder
29265 +        */
29266 +       chunkqueue *recv;
29267 +       chunkqueue *recv_raw;
29268 +       chunkqueue *send_raw;
29269 +       chunkqueue *send;
29270 +       
29271 +       off_t bytes_read;
29272 +       off_t content_length;
29273 +
29274 +       proxy_state_t state;
29275 +} proxy_session;
29276 +
29277 +proxy_session *proxy_session_init(void) {
29278 +       proxy_session *sess;
29279 +
29280 +       sess = calloc(1, sizeof(*sess));
29281 +
29282 +       sess->state = PROXY_STATE_UNSET;
29283 +       sess->request_headers = array_init();
29284 +
29285 +       sess->recv = chunkqueue_init();
29286 +       sess->recv_raw = chunkqueue_init();
29287 +       sess->send_raw = chunkqueue_init();
29288 +       sess->send = chunkqueue_init();
29289 +
29290 +       sess->is_chunked = 0;
29291 +
29292 +       return sess;
29293 +}
29294 +
29295 +void proxy_session_free(proxy_session *sess) {
29296 +       if (!sess) return;
29297 +
29298 +       array_free(sess->request_headers);
29299 +
29300 +       chunkqueue_free(sess->recv);
29301 +       chunkqueue_free(sess->recv_raw);
29302 +       chunkqueue_free(sess->send_raw);
29303 +       chunkqueue_free(sess->send);
29304 +
29305 +       free(sess);
29306 +}
29307 +
29308 +handler_t proxy_connection_connect(proxy_connection *con) {
29309 +       int fd;
29310 +       
29311 +       if (-1 == (fd = socket(con->address->addr.plain.sa_family, SOCK_STREAM, 0))) {
29312 +       }
29313 +
29314 +       fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
29315 +
29316 +       con->sock->fd = fd;
29317 +       con->sock->fde_ndx = -1;
29318 +       con->sock->type = IOSOCKET_TYPE_SOCKET;
29319 +
29320 +       if (-1 == connect(fd, &(con->address->addr.plain), sizeof(con->address->addr))) {
29321 +               switch(errno) {
29322 +               case EINPROGRESS:
29323 +               case EALREADY:
29324 +               case EINTR:
29325 +                       return HANDLER_WAIT_FOR_EVENT;
29326 +               default:
29327 +                       close(fd);
29328 +                       con->sock->fd = -1;
29329 +
29330 +                       return HANDLER_ERROR;
29331 +               }
29332 +       }
29333 +
29334 +       return HANDLER_GO_ON;
29335 +}
29336 +
29337 +/**
29338 + * event-handler for idling connections
29339 + *
29340 + * unused (idling) keep-alive connections are not bound to a session
29341 + * and need their own event-handler 
29342 + *
29343 + * if the connection closes (we get a FDEVENT_IN), close our side too and 
29344 + * let the trigger-func handle the cleanup
29345 + *
29346 + * @see proxy_trigger
29347 + */
29348 +
29349 +
29350 +static handler_t proxy_handle_fdevent_idle(void *s, void *ctx, int revents) {
29351 +       server      *srv  = (server *)s;
29352 +       proxy_connection *proxy_con = ctx;
29353 +
29354 +       if (revents & FDEVENT_IN) {
29355 +               switch (proxy_con->state) {
29356 +               case PROXY_CONNECTION_STATE_IDLE:
29357 +                       proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29358 +
29359 +                       /* close + unregister have to be in the same call,
29360 +                        * otherwise we get a events for a re-opened fd */
29361 +
29362 +                       fdevent_event_del(srv->ev, proxy_con->sock);
29363 +
29364 +                       break;
29365 +               case PROXY_CONNECTION_STATE_CLOSED:
29366 +                       /* poll() is state-driven, we will get events as long as it isn't disabled
29367 +                        * the close() above should disable the events too */
29368 +                       ERROR("%s", "hurry up buddy, I got another event for a closed idle-connection");
29369 +                       break;
29370 +               default:
29371 +                       ERROR("invalid connection state: %d, should be idle", proxy_con->state);
29372 +                       break;
29373 +               }
29374 +       }
29375 +
29376 +       return HANDLER_GO_ON;
29377 +}
29378 +
29379 +void chunkqueue_skip(chunkqueue *cq, off_t skip) {
29380 +       chunk *c;
29381 +
29382 +       for (c = cq->first; c && skip; c = c->next) {
29383 +               if (skip > c->mem->used - c->offset - 1) {
29384 +                       skip -= c->mem->used - c->offset - 1;
29385 +               } else {
29386 +                       c->offset += skip;
29387 +                       skip = 0;
29388 +               }
29389 +       }
29390 +
29391 +       return;
29392 +}
29393 +
29394 +int proxy_http_stream_decoder(server *srv, proxy_session *sess, chunkqueue *raw, chunkqueue *decoded) {
29395 +       chunk *c;
29396 +
29397 +       if (raw->first == NULL) return 0;
29398 +
29399 +       if (sess->is_chunked) {
29400 +               do {
29401 +                       /* the start should always be a chunk-length */
29402 +                       off_t chunk_len = 0;
29403 +                       char *err = NULL;
29404 +                       int chunklen_strlen = 0;
29405 +                       char ch;
29406 +                       off_t we_have = 0, we_need = 0;
29407 +
29408 +                       c = raw->first;
29409 +
29410 +                       if (c->mem->used == 0) return 0;
29411 +
29412 +                       chunk_len = strtol(BUF_STR(c->mem) + c->offset, &err, 16);
29413 +                       if (!(*err == ' ' || *err == '\r' || *err == ';')) {
29414 +                               if (*err == '\0') {
29415 +                                       /* we just need more data */
29416 +                                       return 0;
29417 +                               }
29418 +                               return -1;
29419 +                       }
29420 +
29421 +                       if (chunk_len < 0) {
29422 +                               ERROR("chunk_len is negative: %Ld", chunk_len);
29423 +                               return -1;
29424 +                       }
29425 +
29426 +                       chunklen_strlen = err - (BUF_STR(c->mem) + c->offset);
29427 +                       chunklen_strlen++; /* skip the err-char */ 
29428 +                       
29429 +                       do {
29430 +                               ch = BUF_STR(c->mem)[c->offset + chunklen_strlen];
29431 +       
29432 +                               switch (ch) {
29433 +                               case '\n':
29434 +                               case '\0':
29435 +                                       /* bingo, chunk-header is finished */
29436 +                                       break;
29437 +                               default:
29438 +                                       break;
29439 +                               }
29440 +                               chunklen_strlen++;
29441 +                       } while (ch != '\n' && c != '\0');
29442 +
29443 +                       if (ch != '\n') {
29444 +                               ERROR("%s", "missing the CRLF");
29445 +                               return 0;
29446 +                       }
29447 +
29448 +                       we_need = chunk_len + chunklen_strlen + 2;
29449 +                       /* do we have the full chunk ? */
29450 +                       for (c = raw->first; c; c = c->next) {
29451 +                               we_have += c->mem->used - 1 - c->offset;
29452 +
29453 +                               /* we have enough, jump out */
29454 +                               if (we_have > we_need) break;
29455 +                       }
29456 +
29457 +                       /* get more data */
29458 +                       if (we_have < we_need) {
29459 +                               return 0;
29460 +                       }
29461 +
29462 +                       /* skip the chunk-header */
29463 +                       chunkqueue_skip(raw, chunklen_strlen);
29464 +
29465 +                       /* final chunk */
29466 +                       if (chunk_len == 0) {
29467 +                               chunkqueue_skip(raw, 2);
29468 +
29469 +                               return 1;
29470 +                       }
29471 +
29472 +                       /* we have enough, copy the data */     
29473 +                       for (c = raw->first; c && chunk_len; c = c->next) {
29474 +                               off_t we_want = 0;
29475 +                               buffer *b = chunkqueue_get_append_buffer(decoded);
29476 +
29477 +                               we_want = chunk_len > (c->mem->used - c->offset - 1) ? c->mem->used - c->offset - 1: chunk_len;
29478 +
29479 +                               buffer_copy_string_len(b, c->mem->ptr + c->offset, we_want);
29480 +
29481 +                               c->offset += we_want;
29482 +                               chunk_len -= we_want;
29483 +                       }
29484 +
29485 +                       /* skip the \r\n */
29486 +                       chunkqueue_skip(raw, 2);
29487 +
29488 +                       /* we are done, give the connection to someone else */
29489 +                       chunkqueue_remove_finished_chunks(raw);
29490 +               } while (1);
29491 +       } else {
29492 +               /* no chunked encoding, ok, perhaps a content-length ? */
29493 +
29494 +               chunkqueue_remove_finished_chunks(raw);
29495 +               for (c = raw->first; c; c = c->next) {
29496 +                       buffer *b;
29497 +
29498 +                       if (c->mem->used == 0) continue;
29499 +                      
29500 +                       b = chunkqueue_get_append_buffer(decoded);
29501 +
29502 +                       sess->bytes_read += c->mem->used - c->offset - 1;
29503 +
29504 +                       buffer_copy_string_len(b, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
29505 +
29506 +                       c->offset = c->mem->used - 1;
29507 +
29508 +                       if (sess->bytes_read == sess->content_length) {
29509 +                               break;
29510 +                       }
29511 +
29512 +               }
29513 +               if (sess->bytes_read == sess->content_length) {
29514 +                       return 1; /* finished */
29515 +               }
29516 +       }
29517 +
29518 +       return 0;
29519 +}
29520 +/* don't call any proxy functions directly */
29521 +static handler_t proxy_handle_fdevent(void *s, void *ctx, int revents) {
29522 +       server      *srv  = (server *)s;
29523 +       proxy_session *sess = ctx;
29524 +
29525 +       if (revents & FDEVENT_OUT) {
29526 +               switch (sess->state) {
29527 +               case PROXY_STATE_CONNECTING: /* delayed connect */
29528 +               case PROXY_STATE_WRITE_REQUEST_HEADER:
29529 +               case PROXY_STATE_WRITE_REQUEST_BODY:
29530 +                       /* we are still connection */
29531 +
29532 +                       joblist_append(srv, sess->remote_con);
29533 +                       break;
29534 +               default:
29535 +                       ERROR("oops, unexpected state for fdevent-out %d", sess->state);
29536 +                       break;
29537 +               }
29538 +       } else if (revents & FDEVENT_IN) {
29539 +               chunk *c;
29540 +
29541 +               switch (sess->state) {
29542 +               case PROXY_STATE_READ_RESPONSE_HEADER:
29543 +                       /* call our header parser */
29544 +                       joblist_append(srv, sess->remote_con);
29545 +                       break;
29546 +               case PROXY_STATE_READ_RESPONSE_BODY:
29547 +                       /* we should be in the WRITE state now, 
29548 +                        * just read in the content and forward it to the outgoing connection
29549 +                        * */
29550 +
29551 +                       chunkqueue_remove_finished_chunks(sess->recv_raw);
29552 +                       switch (srv->network_backend_read(srv, sess->remote_con, sess->proxy_con->sock, sess->recv_raw)) {
29553 +                       case NETWORK_STATUS_CONNECTION_CLOSE:
29554 +                               fdevent_event_del(srv->ev,sess->proxy_con->sock);
29555 +
29556 +                               /* the connection is gone
29557 +                                * make the connect */
29558 +                               sess->remote_con->file_finished = 1;
29559 +                               sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29560 +
29561 +                       case NETWORK_STATUS_SUCCESS:
29562 +                               /* read even more, do we have all the content */
29563 +
29564 +                               /* how much do we want to read ? */
29565 +                               
29566 +                               /* call stream-decoder (HTTP-chunked, FastCGI, ... ) */
29567 +
29568 +                               switch (proxy_http_stream_decoder(srv, sess, sess->recv_raw, sess->recv)) {
29569 +                               case 0:
29570 +                                       /* need more */
29571 +                                       break;
29572 +                               case -1:
29573 +                                       /* error */
29574 +                                       break;
29575 +                               case 1:
29576 +                                       /* we are done */
29577 +                                       sess->remote_con->file_finished = 1;
29578 +
29579 +                                       break;
29580 +                               }
29581 +                               chunkqueue_remove_finished_chunks(sess->recv_raw);
29582 +
29583 +                               /* copy the content to the next cq */
29584 +                               for (c = sess->recv->first; c; c = c->next) {
29585 +                                       if (c->mem->used == 0) continue;
29586 +
29587 +                                       http_chunk_append_mem(srv, sess->remote_con, c->mem->ptr + c->offset, c->mem->used - c->offset);
29588 +       
29589 +                                       c->offset = c->mem->used - 1;
29590 +
29591 +                               }
29592 +                               chunkqueue_remove_finished_chunks(sess->recv);
29593 +
29594 +                               if (sess->remote_con->file_finished) {
29595 +                                       /* send final HTTP-Chunk packet */
29596 +                                       http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
29597 +                               }
29598 +                               
29599 +                               break;
29600 +                       default:
29601 +                               ERROR("%s", "oops, we failed to read");
29602 +                               break;
29603 +                       }
29604 +
29605 +                       joblist_append(srv, sess->remote_con);
29606 +                       break;
29607 +               default:
29608 +                       ERROR("oops, unexpected state for fdevent-in %d", sess->state);
29609 +                       break;
29610 +               }
29611 +       }
29612 +
29613 +       if (revents & FDEVENT_HUP) {
29614 +               /* someone closed our connection */
29615 +               switch (sess->state) {
29616 +               case PROXY_STATE_CONNECTING:
29617 +                       /* let the getsockopt() catch this */
29618 +                       joblist_append(srv, sess->remote_con);
29619 +                       break;
29620 +               default:
29621 +                       ERROR("oops, unexpected state for fdevent-hup %d", sess->state);
29622 +                       break;
29623 +               }
29624 +       }
29625 +
29626 +       return HANDLER_GO_ON;
29627 +}
29628 +
29629 +int pcre_replace(pcre *match, buffer *replace, buffer *match_buf, buffer *result) {
29630 +       const char *pattern = replace->ptr;
29631 +       size_t pattern_len = replace->used - 1;
29632 +
29633 +# define N 10
29634 +       int ovec[N * 3];
29635 +       int n;
29636 +
29637 +       if ((n = pcre_exec(match, NULL, match_buf->ptr, match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
29638 +               if (n != PCRE_ERROR_NOMATCH) {
29639 +                       return n;
29640 +               }
29641 +       } else {
29642 +               const char **list;
29643 +               size_t start, end;
29644 +               size_t k;
29645 +
29646 +               /* it matched */
29647 +               pcre_get_substring_list(match_buf->ptr, ovec, n, &list);
29648 +
29649 +               /* search for $[0-9] */
29650 +
29651 +               buffer_reset(result);
29652 +
29653 +               start = 0; end = pattern_len;
29654 +               for (k = 0; k < pattern_len; k++) {
29655 +                       if ((pattern[k] == '$') &&
29656 +                           isdigit((unsigned char)pattern[k + 1])) {
29657 +                               /* got one */
29658 +
29659 +                               size_t num = pattern[k + 1] - '0';
29660 +
29661 +                               end = k;
29662 +
29663 +                               buffer_append_string_len(result, pattern + start, end - start);
29664 +
29665 +                               /* n is always > 0 */
29666 +                               if (num < (size_t)n) {
29667 +                                       buffer_append_string(result, list[num]);
29668 +                               }
29669 +
29670 +                               k++;
29671 +                               start = k + 1;
29672 +                       }
29673 +               }
29674 +
29675 +               buffer_append_string_len(result, pattern + start, pattern_len - start);
29676 +
29677 +               pcre_free(list);
29678 +       }
29679 +
29680 +       return n;
29681 +}
29682 +
29683 +/**
29684 + * generate a HTTP/1.1 proxy request from the set of request-headers
29685 + *
29686 + * TODO: this is HTTP-proxy specific and will be moved moved into a separate backed
29687 + *
29688 + */
29689 +int proxy_get_request_chunk(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq) {
29690 +       buffer *b;
29691 +       size_t i;
29692 +       
29693 +       b = chunkqueue_get_append_buffer(cq);
29694 +
29695 +       /* request line */
29696 +       buffer_copy_string(b, get_http_method_name(con->request.http_method));
29697 +       BUFFER_APPEND_STRING_CONST(b, " ");
29698 +
29699 +       /* check if we want to rewrite the uri */
29700 +
29701 +       for (i = 0; i < p->conf.request_rewrites->used; i++) {
29702 +               proxy_rewrite *rw = p->conf.request_rewrites->ptr[i];
29703 +
29704 +               if (buffer_is_equal_string(rw->header, CONST_STR_LEN("_uri"))) {
29705 +                       int ret;
29706 +
29707 +                       if ((ret = pcre_replace(rw->regex, rw->replace, con->request.uri, p->replace_buf)) < 0) {
29708 +                               switch (ret) {
29709 +                               case PCRE_ERROR_NOMATCH:
29710 +                                       /* hmm, ok. no problem */
29711 +                                       buffer_append_string_buffer(b, con->request.uri);
29712 +                                       break;
29713 +                               default:
29714 +                                       TRACE("oops, pcre_replace failed with: %d", ret);
29715 +                                       break;
29716 +                               }
29717 +                       } else {
29718 +                               buffer_append_string_buffer(b, p->replace_buf);
29719 +                       }
29720 +
29721 +                       break;
29722 +               }
29723 +       }
29724 +
29725 +       if (i == p->conf.request_rewrites->used) {
29726 +               /* not found */
29727 +               buffer_append_string_buffer(b, con->request.uri);
29728 +       }
29729 +
29730 +       BUFFER_APPEND_STRING_CONST(b, " HTTP/1.1\r\n");
29731 +
29732 +       for (i = 0; i < sess->request_headers->used; i++) {
29733 +               data_string *ds;
29734 +
29735 +               ds = (data_string *)sess->request_headers->data[i];
29736 +
29737 +               buffer_append_string_buffer(b, ds->key);
29738 +               BUFFER_APPEND_STRING_CONST(b, ": ");
29739 +               buffer_append_string_buffer(b, ds->value);
29740 +               BUFFER_APPEND_STRING_CONST(b, "\r\n");
29741 +       }
29742 +
29743 +       BUFFER_APPEND_STRING_CONST(b, "\r\n");
29744 +       
29745 +       return 0;
29746 +}
29747 +
29748 +void proxy_set_header(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
29749 +       data_string *ds_dst;
29750 +
29751 +       if (NULL != (ds_dst = (data_string *)array_get_element(hdrs, key))) {
29752 +               buffer_copy_string_len(ds_dst->value, value, val_len);
29753 +               return;
29754 +       }
29755 +
29756 +       if (NULL == (ds_dst = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
29757 +               ds_dst = data_string_init();
29758 +       }
29759 +
29760 +       buffer_copy_string_len(ds_dst->key, key, key_len);
29761 +       buffer_copy_string_len(ds_dst->value, value, val_len);
29762 +       array_insert_unique(hdrs, (data_unset *)ds_dst);
29763 +}
29764 +
29765 +void proxy_append_header(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
29766 +       data_string *ds_dst;
29767 +
29768 +       if (NULL == (ds_dst = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
29769 +               ds_dst = data_string_init();
29770 +       }
29771 +
29772 +       buffer_copy_string_len(ds_dst->key, key, key_len);
29773 +       buffer_copy_string_len(ds_dst->value, value, val_len);
29774 +       array_insert_unique(hdrs, (data_unset *)ds_dst);
29775 +}
29776 +
29777 +
29778 +/**
29779 + * build the request-header array and call the backend specific request formater
29780 + * to fill the chunkqueue
29781 + */
29782 +int proxy_get_request_header(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
29783 +       /* request line */
29784 +       const char *remote_ip;
29785 +       size_t i;
29786 +
29787 +       remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
29788 +       proxy_append_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-For"), remote_ip, strlen(remote_ip));
29789 +
29790 +       /* http_host is NOT is just a pointer to a buffer
29791 +        * which is NULL if it is not set */
29792 +       if (con->request.http_host &&
29793 +           !buffer_is_empty(con->request.http_host)) {
29794 +               proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Host"), CONST_BUF_LEN(con->request.http_host));
29795 +       }
29796 +       if (con->conf.is_ssl) {
29797 +               proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-Proto"), CONST_STR_LEN("https"));
29798 +       } else {
29799 +               proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-Proto"), CONST_STR_LEN("http"));
29800 +       }
29801 +
29802 +       /* request header */
29803 +       for (i = 0; i < con->request.headers->used; i++) {
29804 +               data_string *ds;
29805 +               size_t k;
29806 +
29807 +               ds = (data_string *)con->request.headers->data[i];
29808 +
29809 +               if (buffer_is_empty(ds->value) || buffer_is_empty(ds->key)) continue;
29810 +
29811 +               if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
29812 +               if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Keep-Alive"))) continue;
29813 +
29814 +               for (k = 0; k < p->conf.request_rewrites->used; k++) {
29815 +                       proxy_rewrite *rw = p->conf.request_rewrites->ptr[k];
29816 +
29817 +                       if (buffer_is_equal(rw->header, ds->key)) {
29818 +                               int ret;
29819 +
29820 +                               if ((ret = pcre_replace(rw->regex, rw->replace, ds->value, p->replace_buf)) < 0) {
29821 +                                       switch (ret) {
29822 +                                       case PCRE_ERROR_NOMATCH:
29823 +                                               /* hmm, ok. no problem */
29824 +                                               proxy_set_header(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
29825 +                                               break;
29826 +                                       default:
29827 +                                               TRACE("oops, pcre_replace failed with: %d", ret);
29828 +                                               break;
29829 +                                       }
29830 +                               } else {
29831 +                                       proxy_set_header(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(p->replace_buf));
29832 +                               }
29833 +
29834 +                               break;
29835 +                       }
29836 +               }
29837 +
29838 +               if (k == p->conf.request_rewrites->used) {
29839 +                       proxy_set_header(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
29840 +               }
29841 +       }
29842 +
29843 +       proxy_get_request_chunk(srv, con, p, sess, sess->send_raw);
29844 +
29845 +       return 0;
29846 +}
29847 +
29848 +/**
29849 + * parse the response header
29850 + *
29851 + * NOTE: this can be used by all backends as they all send a HTTP-Response a clean block
29852 + * - fastcgi needs some decoding for the protocol
29853 + */
29854 +parse_status_t proxy_parse_response_header(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq) {
29855 +       int have_content_length = 0;
29856 +       size_t i;
29857 +
29858 +       http_response_reset(p->resp);
29859 +       
29860 +       switch (http_response_parse_cq(cq, p->resp)) {
29861 +       case PARSE_ERROR:
29862 +               /* parsing failed */
29863 +
29864 +               return PARSE_ERROR;
29865 +       case PARSE_NEED_MORE:
29866 +               return PARSE_NEED_MORE;
29867 +       case PARSE_SUCCESS:
29868 +               con->http_status = p->resp->status;
29869 +
29870 +               chunkqueue_remove_finished_chunks(cq);
29871 +
29872 +               sess->content_length = -1;
29873 +
29874 +               /* copy the http-headers */
29875 +               for (i = 0; i < p->resp->headers->used; i++) {
29876 +                       const char *ign[] = { "Status", "Connection", NULL };
29877 +                       size_t j, k;
29878 +                       data_string *ds;
29879 +
29880 +                       data_string *header = (data_string *)p->resp->headers->data[i];
29881 +
29882 +                       /* some headers are ignored by default */
29883 +                       for (j = 0; ign[j]; j++) {
29884 +                               if (0 == strcasecmp(ign[j], header->key->ptr)) break;
29885 +                       }
29886 +                       if (ign[j]) continue;
29887 +
29888 +                       if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
29889 +                               /* CGI/1.1 rev 03 - 7.2.1.2 */
29890 +                               if (con->http_status == 0) con->http_status = 302;
29891 +                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
29892 +                               have_content_length = 1;
29893 +
29894 +                               sess->content_length = strtol(header->value->ptr, NULL, 10);
29895 +
29896 +                               if (sess->content_length < 0) {
29897 +                                       return PARSE_ERROR;
29898 +                               }
29899 +                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Transfer-Encoding"))) {
29900 +                               if (strstr(header->value->ptr, "chunked")) {
29901 +                                       sess->is_chunked = 1;
29902 +                               }
29903 +                               /* ignore the header */
29904 +                               continue;
29905 +                       }
29906 +                       
29907 +                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
29908 +                               ds = data_response_init();
29909 +                       }
29910 +
29911 +
29912 +                       buffer_copy_string_buffer(ds->key, header->key);
29913 +
29914 +                       for (k = 0; k < p->conf.response_rewrites->used; k++) {
29915 +                               proxy_rewrite *rw = p->conf.response_rewrites->ptr[k];
29916 +
29917 +                               if (buffer_is_equal(rw->header, header->key)) {
29918 +                                       int ret;
29919 +       
29920 +                                       if ((ret = pcre_replace(rw->regex, rw->replace, header->value, p->replace_buf)) < 0) {
29921 +                                               switch (ret) {
29922 +                                               case PCRE_ERROR_NOMATCH:
29923 +                                                       /* hmm, ok. no problem */
29924 +                                                       buffer_append_string_buffer(ds->value, header->value);
29925 +                                                       break;
29926 +                                               default:
29927 +                                                       TRACE("oops, pcre_replace failed with: %d", ret);
29928 +                                                       break;
29929 +                                               }
29930 +                                       } else {
29931 +                                               buffer_append_string_buffer(ds->value, p->replace_buf);
29932 +                                       }
29933 +
29934 +                                       break;
29935 +                               }
29936 +                       }
29937 +
29938 +                       if (k == p->conf.response_rewrites->used) {
29939 +                               buffer_copy_string_buffer(ds->value, header->value);
29940 +                       }
29941 +
29942 +                       array_insert_unique(con->response.headers, (data_unset *)ds);
29943 +               }
29944 +
29945 +               /* does the client allow us to send chunked encoding ? */
29946 +               if (con->request.http_version == HTTP_VERSION_1_1 &&
29947 +                   !have_content_length) {
29948 +                       con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
29949 +               }
29950 +
29951 +               break;
29952 +       }
29953 +
29954 +       return PARSE_SUCCESS; /* we have a full header */
29955 +}
29956 +
29957 +/* we are event-driven
29958 + * 
29959 + * the first entry is connect() call, if the doesn't need a event 
29960 + *
29961 + * a bit boring
29962 + * - connect (+ delayed connect)
29963 + * - write header + content
29964 + * - read header + content
29965 + *
29966 + * as soon as have read the response header we switch con->file_started and return HANDLER_GO_ON to
29967 + * tell the core we are ready to stream out the content.
29968 + *  */
29969 +handler_t proxy_state_engine(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
29970 +       /* do we have a connection ? */
29971 +
29972 +       if (sess->state == PROXY_STATE_UNSET) {
29973 +               /* we are not started yet */
29974 +               switch(proxy_connection_connect(sess->proxy_con)) {
29975 +               case HANDLER_WAIT_FOR_EVENT:
29976 +                       /* waiting on the connect call */
29977 +
29978 +                       fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
29979 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_OUT);
29980 +
29981 +                       sess->state = PROXY_STATE_CONNECTING;
29982 +                       sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTING;
29983 +                       
29984 +                       return HANDLER_WAIT_FOR_EVENT;
29985 +               case HANDLER_GO_ON:
29986 +                       /* we are connected */
29987 +                       sess->state = PROXY_STATE_CONNECTED;
29988 +                       sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
29989 +                       fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
29990 +
29991 +                       break;
29992 +               case HANDLER_ERROR:
29993 +               default:
29994 +                       /* not good, something failed */
29995 +                       return HANDLER_ERROR;
29996 +               
29997 +               }
29998 +       } else if (sess->state == PROXY_STATE_CONNECTING) {
29999 +               int socket_error;
30000 +               socklen_t socket_error_len = sizeof(socket_error);
30001 +
30002 +               fdevent_event_del(srv->ev, sess->proxy_con->sock);
30003 +
30004 +               if (0 != getsockopt(sess->proxy_con->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
30005 +                       ERROR("getsockopt failed:", strerror(errno));
30006 +
30007 +                       return HANDLER_ERROR;
30008 +               }
30009 +               if (socket_error != 0) {
30010 +                       switch (socket_error) {
30011 +                       case ECONNREFUSED:
30012 +                               /* there is no-one on the other side */
30013 +                               sess->proxy_con->address->disabled_until = srv->cur_ts + 2;
30014 +
30015 +                               TRACE("address %s refused us, disabling for 2 sec", sess->proxy_con->address->name->ptr);
30016 +                               break;
30017 +                       case EHOSTUNREACH:
30018 +                               /* there is no-one on the other side */
30019 +                               sess->proxy_con->address->disabled_until = srv->cur_ts + 60;
30020 +
30021 +                               TRACE("host %s is unreachable, disabling for 60 sec", sess->proxy_con->address->name->ptr);
30022 +                               break;
30023 +                       default:
30024 +                               sess->proxy_con->address->disabled_until = srv->cur_ts + 60;
30025 +
30026 +                               TRACE("connected finally failed: %s (%d)", strerror(socket_error), socket_error);
30027 +
30028 +                               TRACE("connect to address %s failed and I don't know why, disabling for 10 sec", sess->proxy_con->address->name->ptr);
30029 +
30030 +                               break;
30031 +                       }
30032 +
30033 +                       sess->proxy_con->address->state = PROXY_ADDRESS_STATE_DISABLED;
30034 +
30035 +                       sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
30036 +                       return HANDLER_COMEBACK;
30037 +               }
30038 +
30039 +               sess->state = PROXY_STATE_CONNECTED;
30040 +               sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
30041 +       }
30042 +
30043 +       if (sess->state == PROXY_STATE_CONNECTED) {
30044 +               /* build the header */
30045 +               proxy_get_request_header(srv, con, p, sess);
30046 +
30047 +               sess->state = PROXY_STATE_WRITE_REQUEST_HEADER;
30048 +       }
30049 +
30050 +       switch (sess->state) {
30051 +       case PROXY_STATE_WRITE_REQUEST_HEADER:
30052 +               /* create the request-packet */ 
30053 +               fdevent_event_del(srv->ev, sess->proxy_con->sock);
30054 +
30055 +               switch (srv->network_backend_write(srv, con, sess->proxy_con->sock, sess->send_raw)) {
30056 +               case NETWORK_STATUS_SUCCESS:
30057 +                       sess->state = PROXY_STATE_WRITE_REQUEST_BODY;
30058 +                       break;
30059 +               case NETWORK_STATUS_WAIT_FOR_EVENT:
30060 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_OUT);
30061 +
30062 +                       return HANDLER_WAIT_FOR_EVENT;
30063 +               case NETWORK_STATUS_CONNECTION_CLOSE:
30064 +                       sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
30065 +
30066 +                       /* this connection is closed, restart the request with a new connection */
30067 +
30068 +                       return HANDLER_COMEBACK;
30069 +               default:
30070 +                       return HANDLER_ERROR;
30071 +               }
30072 +               /* fall through */
30073 +       case PROXY_STATE_WRITE_REQUEST_BODY:
30074 +               fdevent_event_del(srv->ev, sess->proxy_con->sock);
30075 +               sess->state = PROXY_STATE_READ_RESPONSE_HEADER;
30076 +
30077 +       case PROXY_STATE_READ_RESPONSE_HEADER:
30078 +               fdevent_event_del(srv->ev, sess->proxy_con->sock);
30079 +
30080 +               chunkqueue_remove_finished_chunks(sess->recv_raw);
30081 +
30082 +               switch (srv->network_backend_read(srv, con, sess->proxy_con->sock, sess->recv_raw)) {
30083 +               case NETWORK_STATUS_SUCCESS:
30084 +                       /* we read everything from the socket, do we have a full header ? */
30085 +
30086 +                       switch (proxy_parse_response_header(srv, con, p, sess, sess->recv_raw)) {
30087 +                       case PARSE_ERROR:
30088 +                               con->http_status = 502; /* bad gateway */
30089 +
30090 +                               return HANDLER_FINISHED;
30091 +                       case PARSE_NEED_MORE:
30092 +                               /* we need more */
30093 +                               fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
30094 +
30095 +                               return HANDLER_WAIT_FOR_EVENT;
30096 +                       case PARSE_SUCCESS:
30097 +                               break;
30098 +                       default:
30099 +                               return HANDLER_ERROR;
30100 +                       }
30101 +                       
30102 +                       con->file_started = 1;
30103 +
30104 +                       sess->state = PROXY_STATE_READ_RESPONSE_BODY;
30105 +
30106 +                       /**
30107 +                        * set the event to pass the content through to the server
30108 +                        *
30109 +                        * this triggers the event-handler
30110 +                        * @see proxy_handle_fdevent
30111 +                        */
30112 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
30113 +
30114 +                       return HANDLER_GO_ON; /* tell http_response_prepare that we are done with the header */
30115 +               case NETWORK_STATUS_WAIT_FOR_EVENT:
30116 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
30117 +                       return HANDLER_WAIT_FOR_EVENT;
30118 +               case NETWORK_STATUS_CONNECTION_CLOSE:
30119 +                       if (chunkqueue_length(sess->recv_raw) == 0) {
30120 +                               /* the connection went away before we got something back */
30121 +                               sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
30122 +
30123 +                               /**
30124 +                                * we might run into a 'race-condition' 
30125 +                                *
30126 +                                * 1. proxy-con is keep-alive, idling and just being closed (FDEVENT_IN) [fd=27]
30127 +                                * 2. new connection comes in, we use the idling connection [fd=14]
30128 +                                * 3. we write(), successful [to fd=27]
30129 +                                * 3. we read() ... and finally receive the close-event for the connection
30130 +                                */
30131 +
30132 +                               con->http_status = 500;
30133 +
30134 +                               ERROR("++ %s", "oops, connection got closed while we were reading from it");
30135 +                               return HANDLER_FINISHED;
30136 +                       }
30137 +
30138 +                       ERROR("%s", "conn-close after header-read");
30139 +                               
30140 +                       break;
30141 +               default:
30142 +                       ERROR("++ %s", "oops, something went wrong while reading");
30143 +                       return HANDLER_ERROR;
30144 +               }
30145 +       case PROXY_STATE_READ_RESPONSE_BODY:
30146 +               /* if we do everything right, we won't get call for this state-anymore */
30147 +
30148 +               ERROR("%s", "PROXY_STATE_READ_RESPONSE_BODY");
30149 +               
30150 +               break;
30151 +       }
30152 +
30153 +       return HANDLER_GO_ON;
30154 +}
30155 +
30156 +proxy_backend *proxy_get_backend(server *srv, connection *con, plugin_data *p) {
30157 +       size_t i;
30158 +
30159 +       for (i = 0; i < p->conf.backends->used; i++) {
30160 +               proxy_backend *backend = p->conf.backends->ptr[i];
30161 +
30162 +               return backend;
30163 +       }
30164 +
30165 +       return NULL;
30166 +}
30167 +
30168 +/**
30169 + * choose a available address from the address-pool
30170 + *
30171 + * the backend has different balancers 
30172 + */
30173 +proxy_address *proxy_backend_balance(server *srv, connection *con, proxy_backend *backend) {
30174 +       size_t i;
30175 +       proxy_address_pool *address_pool = backend->address_pool;
30176 +       unsigned long last_max; /* for the HASH balancer */
30177 +       proxy_address *address = NULL, *cur_address = NULL;
30178 +       int active_addresses = 0, rand_ndx;
30179 +
30180 +       switch(backend->balancer) {
30181 +       case PROXY_BALANCE_HASH:
30182 +               /* hash balancing */
30183 +
30184 +               for (i = 0, last_max = ULONG_MAX; i < address_pool->used; i++) {
30185 +                       unsigned long cur_max;
30186 +
30187 +                       cur_address = address_pool->ptr[i];
30188 +
30189 +                       if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
30190 +
30191 +                       cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) +
30192 +                               generate_crc32c(CONST_BUF_LEN(cur_address->name)) + /* we can cache this */
30193 +                               generate_crc32c(CONST_BUF_LEN(con->uri.authority));
30194 +#if 0
30195 +                       TRACE("hash-election: %s - %s - %s: %ld", 
30196 +                                       con->uri.path->ptr,
30197 +                                       cur_address->name->ptr,
30198 +                                       con->uri.authority->ptr,
30199 +                                       cur_max);
30200 +#endif
30201 +                       if (address == NULL || (cur_max > last_max)) {
30202 +                               last_max = cur_max;
30203 +
30204 +                               address = cur_address;
30205 +                       }
30206 +               }
30207 +
30208 +               break;
30209 +       case PROXY_BALANCE_FAIR:
30210 +               /* fair balancing */
30211 +
30212 +               for (i = 0; i < address_pool->used; i++) {
30213 +                       cur_address = address_pool->ptr[i];
30214 +
30215 +                       if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
30216 +
30217 +                       /* the address is up, use it */
30218 +
30219 +                       address = cur_address;
30220 +
30221 +                       break;
30222 +               }
30223 +
30224 +               break;
30225 +       case PROXY_BALANCE_RR:
30226 +               /* round robin */
30227 +
30228 +               /**
30229 +                * instead of real RoundRobin we just do a RandomSelect
30230 +                *
30231 +                * it is state-less and has the same distribution
30232 +                */
30233 +
30234 +               active_addresses = 0;
30235 +               
30236 +               for (i = 0; i < address_pool->used; i++) {
30237 +                       cur_address = address_pool->ptr[i];
30238 +
30239 +                       if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
30240 +
30241 +                       active_addresses++;
30242 +               }
30243 +
30244 +               rand_ndx = (int) (1.0 * active_addresses * rand()/(RAND_MAX));
30245 +       
30246 +               active_addresses = 0;
30247 +               for (i = 0; i < address_pool->used; i++) {
30248 +                       cur_address = address_pool->ptr[i];
30249 +
30250 +                       if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
30251 +
30252 +                       address = cur_address;
30253 +
30254 +                       if (rand_ndx == active_addresses++) break;
30255 +               }
30256 +
30257 +               break;
30258 +       default:
30259 +               break;
30260 +       }
30261 +
30262 +       return address;
30263 +}
30264 +
30265 +static int mod_proxy_core_patch_connection(server *srv, connection *con, plugin_data *p) {
30266 +       size_t i, j;
30267 +       plugin_config *s = p->config_storage[0];
30268 +
30269 +       /* global defaults */
30270 +       PATCH_OPTION(balancer);
30271 +       PATCH_OPTION(debug);
30272 +       PATCH_OPTION(backends);
30273 +       PATCH_OPTION(backlog);
30274 +       PATCH_OPTION(protocol);
30275 +       PATCH_OPTION(request_rewrites);
30276 +       PATCH_OPTION(response_rewrites);
30277 +
30278 +       /* skip the first, the global context */
30279 +       for (i = 1; i < srv->config_context->used; i++) {
30280 +               data_config *dc = (data_config *)srv->config_context->data[i];
30281 +               s = p->config_storage[i];
30282 +
30283 +               /* condition didn't match */
30284 +               if (!config_check_cond(srv, con, dc)) continue;
30285 +
30286 +               /* merge config */
30287 +               for (j = 0; j < dc->value->used; j++) {
30288 +                       data_unset *du = dc->value->data[j];
30289 +
30290 +                       if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_BACKENDS))) {
30291 +                               PATCH_OPTION(backends);
30292 +                               PATCH_OPTION(backlog);
30293 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_DEBUG))) {
30294 +                               PATCH_OPTION(debug);
30295 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_BALANCER))) {
30296 +                               PATCH_OPTION(balancer);
30297 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_PROTOCOL))) {
30298 +                               PATCH_OPTION(protocol);
30299 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_REWRITE_REQUEST))) {
30300 +                               PATCH_OPTION(request_rewrites);
30301 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_REWRITE_RESPONSE))) {
30302 +                               PATCH_OPTION(response_rewrites);
30303 +                       }
30304 +               }
30305 +       }
30306 +
30307 +       return 0;
30308 +}
30309 +
30310 +
30311 +SUBREQUEST_FUNC(mod_proxy_core_check_extension) {
30312 +       plugin_data *p = p_d;
30313 +       proxy_session *sess = con->plugin_ctx[p->id]; /* if this is the second round, sess is already prepared */
30314 +
30315 +       /* check if we have a matching conditional for this request */
30316 +
30317 +       if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
30318 +
30319 +       mod_proxy_core_patch_connection(srv, con, p);
30320 +
30321 +       if (p->conf.backends->used == 0) return HANDLER_GO_ON;
30322 +
30323 +       /* 
30324 +        * 0. build session
30325 +        * 1. get a proxy connection
30326 +        * 2. create the http-request header
30327 +        * 3. stream the content to the backend 
30328 +        * 4. wait for http-response header 
30329 +        * 5. decode the response + parse the response
30330 +        * 6. stream the response-content to the client 
30331 +        * 7. kill session
30332 +        * */
30333 +
30334 +       if (!sess) {
30335 +               /* a session lives for a single request */
30336 +               sess = proxy_session_init();
30337 +
30338 +               con->plugin_ctx[p->id] = sess;
30339 +               con->mode = p->id;
30340 +
30341 +               sess->remote_con = con;
30342 +       }
30343 +
30344 +       switch (sess->state) {
30345 +       case PROXY_STATE_CONNECTING:
30346 +               /* this connections is waited 10 seconds to connect to the backend
30347 +                * and didn't got a successful connection yet, sending timeout */
30348 +               if (srv->cur_ts - con->request_start > 10) {
30349 +                       con->http_status = 504; /* gateway timeout */
30350 +                       con->file_finished = 1;
30351 +
30352 +                       if (sess->proxy_con) {
30353 +                               /* if we are waiting for a proxy-connection right now, close it */
30354 +                               proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
30355 +       
30356 +                               fdevent_event_del(srv->ev, sess->proxy_con->sock);
30357 +                               fdevent_unregister(srv->ev, sess->proxy_con->sock);
30358 +
30359 +                               proxy_connection_free(sess->proxy_con);
30360 +                       
30361 +                               sess->proxy_con = NULL;
30362 +                       }
30363 +                       
30364 +                       return HANDLER_FINISHED;
30365 +               }
30366 +       default:
30367 +               /* handle-request-timeout,  */
30368 +               if (srv->cur_ts - con->request_start > 60) {
30369 +                       TRACE("request runs longer than 60sec: current state: %d", sess->state);
30370 +               }
30371 +               break;
30372 +       }
30373 +
30374 +       /* if the WRITE fails from the start, restart the connection */
30375 +       while (1) {
30376 +               if (sess->proxy_con == NULL) {
30377 +                       proxy_address *address = NULL;
30378 +                       if (NULL == (sess->proxy_backend = proxy_get_backend(srv, con, p))) {
30379 +                               /* no connection pool for this location */
30380 +                               SEGFAULT();
30381 +                       }
30382 +
30383 +                       sess->proxy_backend->balancer = p->conf.balancer;
30384 +
30385 +                       /**
30386 +                        * ask the balancer for the next address and
30387 +                        * check the connection pool if we have a connection open
30388 +                        * for that address
30389 +                        */
30390 +                       if (NULL == (address = proxy_backend_balance(srv, con, sess->proxy_backend))) {
30391 +                               /* we don't have any backends to connect to */
30392 +                               proxy_request *req;
30393 +
30394 +                               /* connection pool is full, queue the request for now */
30395 +                               req = proxy_request_init();
30396 +                               req->added_ts = srv->cur_ts;
30397 +                               req->con = con;
30398 +                               
30399 +                               TRACE("backlog: all backends are down, putting %s (%d) into the backlog", BUF_STR(con->uri.path), con->sock->fd);
30400 +                               proxy_backlog_push(p->conf.backlog, req);
30401 +
30402 +                               /* no, not really a event, 
30403 +                                * we just want to block the outer loop from stepping forward
30404 +                                *
30405 +                                * the trigger will bring this connection back into the game
30406 +                                * */
30407 +                               return HANDLER_WAIT_FOR_EVENT;
30408 +                       }
30409 +
30410 +                       if (PROXY_CONNECTIONPOOL_FULL == proxy_connection_pool_get_connection(
30411 +                                               sess->proxy_backend->pool, 
30412 +                                               address,
30413 +                                               &(sess->proxy_con))) {
30414 +                               proxy_request *req;
30415 +
30416 +                               /* connection pool is full, queue the request for now */
30417 +                               req = proxy_request_init();
30418 +                               req->added_ts = srv->cur_ts;
30419 +                               req->con = con;
30420 +                               
30421 +                               TRACE("backlog: the con-pool is full, putting %s (%d) into the backlog", con->uri.path->ptr, con->sock->fd);
30422 +                               proxy_backlog_push(p->conf.backlog, req);
30423 +
30424 +                               /* no, not really a event, 
30425 +                                * we just want to block the outer loop from stepping forward
30426 +                                *
30427 +                                * the trigger will bring this connection back into the game
30428 +                                * */
30429 +                               return HANDLER_WAIT_FOR_EVENT;
30430 +                       }
30431 +
30432 +                       /* a fresh connection, we need address for it */
30433 +                       if (sess->proxy_con->state == PROXY_CONNECTION_STATE_CONNECTING) {
30434 +                               sess->state = PROXY_STATE_UNSET;
30435 +                               sess->bytes_read = 0;
30436 +                       } else {
30437 +                               /* we are already connected */
30438 +                               sess->state = PROXY_STATE_CONNECTED;
30439 +                               
30440 +                               /* the connection was idling and using the fdevent_idle-handler 
30441 +                                * switch it back to the normal proxy-event-handler */
30442 +                               fdevent_event_del(srv->ev, sess->proxy_con->sock);
30443 +                               fdevent_unregister(srv->ev, sess->proxy_con->sock);
30444 +
30445 +                               fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
30446 +                               fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
30447 +                       }
30448 +               }
30449 +
30450 +               switch (proxy_state_engine(srv, con, p, sess)) {
30451 +               case HANDLER_WAIT_FOR_EVENT:
30452 +                       return HANDLER_WAIT_FOR_EVENT;
30453 +               case HANDLER_COMEBACK:
30454 +                       proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
30455 +       
30456 +                       fdevent_event_del(srv->ev, sess->proxy_con->sock);
30457 +                       fdevent_unregister(srv->ev, sess->proxy_con->sock);
30458 +
30459 +                       proxy_connection_free(sess->proxy_con);
30460 +
30461 +                       sess->proxy_con = NULL;
30462 +                       /* restart the connection to the backend */
30463 +                       TRACE("%s", "write failed, restarting request");
30464 +                       break;
30465 +               case HANDLER_GO_ON:
30466 +                       return HANDLER_GO_ON;
30467 +               default:
30468 +                       return HANDLER_ERROR;
30469 +               }
30470 +       }
30471 +
30472 +       /* should not be reached */
30473 +       return HANDLER_ERROR;
30474 +}
30475 +
30476 +/**
30477 + * end of the connection to the client
30478 + */
30479 +REQUESTDONE_FUNC(mod_proxy_connection_close_callback) {
30480 +       plugin_data *p = p_d;
30481 +       
30482 +       if (con->mode != p->id) return HANDLER_GO_ON;
30483 +
30484 +       return HANDLER_GO_ON;
30485 +}
30486 +
30487 +/**
30488 + * end of a request
30489 + */
30490 +CONNECTION_FUNC(mod_proxy_connection_reset) {
30491 +       plugin_data *p = p_d;
30492 +       proxy_session *sess = con->plugin_ctx[p->id]; 
30493 +
30494 +       if (con->mode != p->id) return HANDLER_GO_ON;
30495 +
30496 +       if (sess->proxy_con) {
30497 +               switch (sess->proxy_con->state) {
30498 +               case PROXY_CONNECTION_STATE_CONNECTED:
30499 +                       sess->proxy_con->state = PROXY_CONNECTION_STATE_IDLE;
30500 +
30501 +                       /* ignore events as the FD is idle, we might get a HUP as the remote connection might close */
30502 +                       fdevent_event_del(srv->ev, sess->proxy_con->sock);
30503 +                       fdevent_unregister(srv->ev, sess->proxy_con->sock);
30504 +
30505 +                       fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent_idle, sess->proxy_con);
30506 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
30507 +
30508 +                       break;
30509 +               case PROXY_CONNECTION_STATE_CLOSED:
30510 +                       proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
30511 +       
30512 +                       fdevent_event_del(srv->ev, sess->proxy_con->sock);
30513 +                       fdevent_unregister(srv->ev, sess->proxy_con->sock);
30514 +
30515 +                       proxy_connection_free(sess->proxy_con);
30516 +                       break;
30517 +               case PROXY_CONNECTION_STATE_IDLE:
30518 +                       TRACE("%s", "... connection is already back in the pool");
30519 +                       break;
30520 +               default:
30521 +                       ERROR("connection is in a unexpected state at close-time: %d", sess->proxy_con->state);
30522 +                       break;
30523 +               }
30524 +       } else {
30525 +               /* if we have the connection in the backlog, remove it */
30526 +               proxy_backlog_remove_connection(p->conf.backlog, con);
30527 +       }
30528 +       
30529 +
30530 +       proxy_session_free(sess);
30531 +
30532 +       con->plugin_ctx[p->id] = NULL;
30533 +       
30534 +       return HANDLER_GO_ON;
30535 +}
30536 +
30537 +
30538 +
30539 +/**
30540 + * cleanup dead connections once a second
30541 + *
30542 + * the idling event-handler can't cleanup connections itself and has to wait until the 
30543 + * trigger cleans up
30544 + */
30545 +handler_t mod_proxy_trigger_context(server *srv, plugin_config *p) {
30546 +       size_t i, j;
30547 +       proxy_request *req;
30548 +
30549 +       for (i = 0; i < p->backends->used; i++) {
30550 +               proxy_backend *backend = p->backends->ptr[i];
30551 +               proxy_connection_pool *pool = backend->pool;
30552 +               proxy_address_pool *address_pool = backend->address_pool;
30553 +
30554 +               for (j = 0; j < pool->used; ) {
30555 +                       proxy_connection *proxy_con = pool->ptr[j];
30556 +
30557 +                       /* remove-con is removing the current con and moves the good connections to the left
30558 +                        * no need to increment i */
30559 +                       if (proxy_con->state == PROXY_CONNECTION_STATE_CLOSED) {
30560 +                               proxy_connection_pool_remove_connection(backend->pool, proxy_con);
30561 +       
30562 +                               fdevent_event_del(srv->ev, proxy_con->sock);
30563 +                               fdevent_unregister(srv->ev, proxy_con->sock);
30564 +
30565 +                               proxy_connection_free(proxy_con);
30566 +                       } else {
30567 +                               j++;
30568 +                       }
30569 +               }
30570 +
30571 +               /* active the disabled addresses again */
30572 +               for (j = 0; j < address_pool->used; j++) {
30573 +                       proxy_address *address = address_pool->ptr[j];
30574 +
30575 +                       if (address->state != PROXY_ADDRESS_STATE_DISABLED) continue;
30576 +
30577 +                       if (srv->cur_ts > address->disabled_until) {
30578 +                               address->disabled_until = 0;
30579 +                               address->state = PROXY_ADDRESS_STATE_ACTIVE;
30580 +                       }
30581 +               }
30582 +       }
30583 +
30584 +       /* wake up the connections from the backlog */
30585 +       while ((req = proxy_backlog_shift(p->backlog))) {
30586 +               connection *con = req->con;
30587 +
30588 +               joblist_append(srv, con);
30589 +
30590 +               proxy_request_free(req);
30591 +       }
30592 +       
30593 +       return HANDLER_GO_ON;
30594 +}
30595 +
30596 +TRIGGER_FUNC(mod_proxy_trigger) {
30597 +       plugin_data *p = p_d;
30598 +       size_t i;
30599 +       
30600 +       for (i = 0; i < srv->config_context->used; i++) {
30601 +               mod_proxy_trigger_context(srv, p->config_storage[i]);
30602 +       }
30603 +
30604 +       return HANDLER_GO_ON;
30605 +}
30606 +
30607 +int mod_proxy_core_plugin_init(plugin *p) {
30608 +       p->version      = LIGHTTPD_VERSION_ID;
30609 +       p->name         = buffer_init_string("mod_proxy_core");
30610 +
30611 +       p->init         = mod_proxy_core_init;
30612 +       p->cleanup      = mod_proxy_core_free;
30613 +       p->set_defaults = mod_proxy_core_set_defaults;
30614 +       p->handle_uri_clean        = mod_proxy_core_check_extension;
30615 +       p->handle_subrequest_start = mod_proxy_core_check_extension;
30616 +       p->handle_subrequest       = mod_proxy_core_check_extension;
30617 +       p->connection_reset        = mod_proxy_connection_reset;
30618 +       p->handle_connection_close = mod_proxy_connection_close_callback;
30619 +       p->handle_trigger          = mod_proxy_trigger;
30620 +
30621 +       p->data         = NULL;
30622 +
30623 +       return 0;
30624 +}
30625 --- ../lighttpd-1.4.11/src/mod_proxy_core.h     1970-01-01 03:00:00.000000000 +0300
30626 +++ lighttpd-1.4.12/src/mod_proxy_core.h        2006-07-18 13:03:40.000000000 +0300
30627 @@ -0,0 +1,18 @@
30628 +#ifndef _MOD_PROXY_CORE_H_
30629 +#define _MOD_PROXY_CORE_H_
30630 +
30631 +#include "buffer.h"
30632 +#include "base.h"
30633 +
30634 +#define PROXY_BACKEND_CONNECT_PARAMS \
30635 +       (server *srv, connection *con, void *p_d)
30636 +
30637 +#define PROXY_BACKEND_CONNECT_RETVAL handler_t
30638 +
30639 +#define PROXY_BACKEND_CONNECT(name) \
30640 +       PROXY_BACKEND_CONNECT_RETVAL name PROXY_BACKEND_CONNECT_PARAMS
30641 +
30642 +#define PROXY_BACKEND_CONNECT_PTR(name) \
30643 +       PROXY_BACKEND_CONNECT_RETVAL (* name)PROXY_BACKEND_CONNECT_PARAMS
30644 +
30645 +#endif
30646 --- ../lighttpd-1.4.11/src/mod_proxy_core_address.c     1970-01-01 03:00:00.000000000 +0300
30647 +++ lighttpd-1.4.12/src/mod_proxy_core_address.c        2006-07-20 00:57:20.000000000 +0300
30648 @@ -0,0 +1,186 @@
30649 +#include <stdlib.h>
30650 +#include <string.h>
30651 +
30652 +#include "log.h"
30653 +#include "sys-socket.h"
30654 +#include "mod_proxy_core_address.h"
30655 +
30656 +proxy_address *proxy_address_init(void) {
30657 +       proxy_address *address;
30658 +
30659 +       address = calloc(1, sizeof(*address));
30660 +
30661 +       address->name = buffer_init();
30662 +
30663 +       return address;
30664 +}
30665 +
30666 +void proxy_address_free(proxy_address *address) {
30667 +       if (!address) return;
30668 +
30669 +       buffer_free(address->name);
30670 +
30671 +       free(address);
30672 +}
30673 +
30674 +
30675 +proxy_address_pool *proxy_address_pool_init(void) {
30676 +       proxy_address_pool *address_pool;
30677 +
30678 +       address_pool = calloc(1, sizeof(*address_pool));
30679 +
30680 +       return address_pool;
30681 +}
30682 +
30683 +void proxy_address_pool_free(proxy_address_pool *address_pool) {
30684 +       if (!address_pool) return;
30685 +
30686 +       FOREACH(address_pool, element, proxy_address_free(element));
30687 +
30688 +       if (address_pool->ptr) free(address_pool->ptr);
30689 +
30690 +       free(address_pool);
30691 +}
30692 +
30693 +void proxy_address_pool_add(proxy_address_pool *address_pool, proxy_address *address) {
30694 +       size_t i;
30695 +
30696 +       /* check if this address is already known */
30697 +
30698 +       for (i = 0; i < address_pool->used; i++) {
30699 +               proxy_address *pool_address = address_pool->ptr[i];
30700 +
30701 +               if (buffer_is_equal(address->name, pool_address->name)) {
30702 +                       TRACE("%s is already in the address-pool", BUF_STR(address->name));
30703 +
30704 +                       proxy_address_free(address);
30705 +
30706 +                       return;
30707 +               }       
30708 +       }
30709 +
30710 +       TRACE("adding %s to the address-pool", BUF_STR(address->name));
30711 +
30712 +       ARRAY_STATIC_PREPARE_APPEND(address_pool);
30713 +
30714 +       address_pool->ptr[address_pool->used++] = address;
30715 +}
30716 +
30717 +int  proxy_address_pool_add_string(proxy_address_pool *address_pool, buffer *name) {
30718 +       struct addrinfo *res = NULL, pref, *cur;
30719 +       int ret;
30720 +       buffer *hostname = NULL, *port = NULL;
30721 +       char *colon;
30722 +
30723 +       pref.ai_flags = 0;
30724 +       pref.ai_family = PF_UNSPEC;
30725 +       pref.ai_socktype = SOCK_STREAM;
30726 +       pref.ai_protocol = 0;
30727 +       pref.ai_addrlen = 0;
30728 +       pref.ai_addr = NULL;
30729 +       pref.ai_canonname = NULL;
30730 +       pref.ai_next = NULL;
30731 +
30732 +       /* check the address style
30733 +        *
30734 +        * unix:/tmp/socket
30735 +        * www.example.org
30736 +        * www.example.org:80
30737 +        * 127.0.0.1
30738 +        * 127.0.0.1:80
30739 +        * [::1]:80
30740 +        * [::1]
30741 +        */
30742 +
30743 +       if (buffer_is_empty(name)) return -1;
30744 +
30745 +       if (0 == strncmp(BUF_STR(name), "unix:", 5)) {
30746 +               /* a unix domain socket */
30747 +               ERROR("unix: scheme is not supported for %s", BUF_STR(name));
30748 +               return -1;
30749 +       } else if (name->ptr[0] == '[') {
30750 +               if (name->ptr[name->used - 1] == ']') {
30751 +                       /* no port-number attached */
30752 +               
30753 +                       hostname = buffer_init();
30754 +                       buffer_copy_string_len(hostname, BUF_STR(name) + 1, name->used - 3);
30755 +                       port = buffer_init_string("80");
30756 +               } else if (NULL != (colon = strrchr(BUF_STR(name), ':'))) {
30757 +                       /* with port number */
30758 +
30759 +                       hostname = buffer_init();
30760 +                       buffer_copy_string_len(hostname, BUF_STR(name) + 1, colon - BUF_STR(name) - 2);
30761 +                       port = buffer_init();
30762 +                       buffer_copy_string(port, colon + 1);
30763 +
30764 +               } else {
30765 +                       ERROR("this is neither [<ipv6-address>] nor [<ipv6-address>]:<port>: %s", BUF_STR(name));
30766 +
30767 +                       return -1;
30768 +               }
30769 +       } else if (name->ptr[name->used - 1] != ']' &&
30770 +                  NULL != (colon = strrchr(BUF_STR(name), ':'))) {
30771 +
30772 +               hostname = buffer_init();
30773 +               buffer_copy_string_len(hostname, BUF_STR(name), colon - BUF_STR(name));
30774 +               port = buffer_init();
30775 +               buffer_copy_string(port, colon + 1);
30776 +       } else {
30777 +               /* no colon, just a IPv4 address or a domain name */
30778 +
30779 +               hostname = buffer_init_string(BUF_STR(name));
30780 +               port = buffer_init_string("80");
30781 +       }
30782 +
30783 +       TRACE("resolving %s on port %s", BUF_STR(hostname), BUF_STR(port));
30784 +       
30785 +       if (0 != (ret = getaddrinfo(BUF_STR(hostname), BUF_STR(port), &pref, &res))) {
30786 +               ERROR("getaddrinfo failed: %s", gai_strerror(ret));
30787 +
30788 +               buffer_free(hostname);
30789 +               buffer_free(port);
30790 +
30791 +               return -1;
30792 +       }
30793 +
30794 +       buffer_free(hostname);
30795 +       buffer_free(port);
30796 +
30797 +       for (cur = res; cur; cur = cur->ai_next) {
30798 +               proxy_address *a = proxy_address_init();
30799 +
30800 +               memcpy(&(a->addr), cur->ai_addr, cur->ai_addrlen);
30801 +
30802 +               a->state = PROXY_ADDRESS_STATE_ACTIVE;
30803 +               buffer_prepare_copy(a->name, 128);
30804 +
30805 +               switch (cur->ai_family) {
30806 +               case AF_INET6:
30807 +                       a->name->ptr[0] = '[';
30808 +                       inet_ntop(cur->ai_family, &(a->addr.ipv6.sin6_addr), a->name->ptr + 1, a->name->size - 2);
30809 +                       a->name->used = strlen(a->name->ptr) + 1;
30810 +                       buffer_append_string(a->name, "]:");
30811 +                       buffer_append_long(a->name, ntohs(a->addr.ipv6.sin6_port));
30812 +                       break;
30813 +               case AF_INET:
30814 +                       inet_ntop(cur->ai_family, &(a->addr.ipv4.sin_addr), a->name->ptr, a->name->size - 1);
30815 +                       a->name->used = strlen(a->name->ptr) + 1;
30816 +
30817 +                       buffer_append_string(a->name, ":");
30818 +                       buffer_append_long(a->name, ntohs(a->addr.ipv4.sin_port));
30819 +                       break;
30820 +               default:
30821 +                       ERROR("unknown address-family: %d", cur->ai_family);
30822 +                       return -1;
30823 +               }
30824 +
30825 +
30826 +               proxy_address_pool_add(address_pool, a);
30827 +       }
30828 +
30829 +       freeaddrinfo(res);
30830 +
30831 +       return 0;
30832 +}
30833 +
30834 +
30835 --- ../lighttpd-1.4.11/src/mod_proxy_core_address.h     1970-01-01 03:00:00.000000000 +0300
30836 +++ lighttpd-1.4.12/src/mod_proxy_core_address.h        2006-07-18 13:03:40.000000000 +0300
30837 @@ -0,0 +1,33 @@
30838 +#ifndef _MOD_PROXY_CORE_ADDRESS_H_
30839 +#define _MOD_PROXY_CORE_ADDRESS_H_
30840 +
30841 +#include <time.h>
30842 +#include "buffer.h"
30843 +#include "sys-socket.h"
30844 +#include "array-static.h"
30845 +
30846 +typedef enum {
30847 +       PROXY_ADDRESS_STATE_UNSET,
30848 +       PROXY_ADDRESS_STATE_ACTIVE,
30849 +       PROXY_ADDRESS_STATE_DISABLED,
30850 +} proxy_address_state_t;
30851 +
30852 +typedef struct {
30853 +       sock_addr addr;
30854 +
30855 +       buffer *name; /* a inet_ntoa() prepresentation of the address */
30856 +
30857 +       time_t last_used;
30858 +       time_t disabled_until;
30859 +
30860 +       proxy_address_state_t state;
30861 +} proxy_address;
30862 +
30863 +ARRAY_STATIC_DEF(proxy_address_pool, proxy_address, );
30864 +
30865 +proxy_address_pool *proxy_address_pool_init(void); 
30866 +void proxy_address_pool_free(proxy_address_pool *address_pool); 
30867 +void proxy_address_pool_add(proxy_address_pool *address_pool, proxy_address *address);
30868 +int proxy_address_pool_add_string(proxy_address_pool *address_pool, buffer *address);
30869 +
30870 +#endif
30871 --- ../lighttpd-1.4.11/src/mod_proxy_core_backend.c     1970-01-01 03:00:00.000000000 +0300
30872 +++ lighttpd-1.4.12/src/mod_proxy_core_backend.c        2006-07-20 00:57:19.000000000 +0300
30873 @@ -0,0 +1,47 @@
30874 +#include <stdlib.h>
30875 +
30876 +#include "mod_proxy_core_backend.h"
30877 +#include "mod_proxy_core_pool.h"
30878 +#include "mod_proxy_core_address.h"
30879 +
30880 +proxy_backend *proxy_backend_init(void) {
30881 +       proxy_backend *backend;
30882 +
30883 +       backend = calloc(1, sizeof(*backend));
30884 +       backend->pool = proxy_connection_pool_init();
30885 +       backend->address_pool = proxy_address_pool_init();
30886 +       backend->balancer = PROXY_BALANCE_RR;
30887 +
30888 +       return backend;
30889 +}
30890 +
30891 +void proxy_backend_free(proxy_backend *backend) {
30892 +       if (!backend) return;
30893 +
30894 +       proxy_address_pool_free(backend->address_pool);
30895 +       proxy_connection_pool_free(backend->pool);
30896 +       
30897 +       free(backend);
30898 +}
30899 +
30900 +proxy_backends *proxy_backends_init(void) {
30901 +       proxy_backends *backends;
30902 +
30903 +       backends = calloc(1, sizeof(*backends));
30904 +
30905 +       return backends;
30906 +}
30907 +
30908 +void proxy_backends_free(proxy_backends *backends) {
30909 +       FOREACH(backends, element, proxy_backend_free(element))
30910 +
30911 +       if (backends->ptr) free(backends->ptr);
30912 +
30913 +       free(backends);
30914 +}
30915 +
30916 +void proxy_backends_add(proxy_backends *backends, proxy_backend *backend) {
30917 +       ARRAY_STATIC_PREPARE_APPEND(backends);
30918 +
30919 +       backends->ptr[backends->used++] = backend;
30920 +}
30921 --- ../lighttpd-1.4.11/src/mod_proxy_core_backend.h     1970-01-01 03:00:00.000000000 +0300
30922 +++ lighttpd-1.4.12/src/mod_proxy_core_backend.h        2006-07-18 13:03:40.000000000 +0300
30923 @@ -0,0 +1,54 @@
30924 +#ifndef _MOD_PROXY_CORE_BACKEND_H_
30925 +#define _MOD_PROXY_CORE_BACKEND_H_
30926 +
30927 +#include "array-static.h"
30928 +#include "buffer.h"
30929 +#include "mod_proxy_core_address.h"
30930 +#include "mod_proxy_core_pool.h"
30931 +#include "sys-socket.h"
30932 +
30933 +/**
30934 + * a single DNS name might explode to several IP addresses 
30935 + * 
30936 + * url: 
30937 + * - http://foo.bar/suburl/
30938 + * - https://foo.bar/suburl/
30939 + * - unix:/tmp/socket
30940 + * - tcp://foobar:1025/
30941 + *
30942 + * backend:
30943 + * - scgi
30944 + * - http
30945 + * - fastcgi
30946 + *
30947 + * request-url-rewrite
30948 + * response-url-rewrite
30949 + */ 
30950 +typedef enum {
30951 +       PROXY_BALANCE_UNSET,
30952 +       PROXY_BALANCE_FAIR,
30953 +       PROXY_BALANCE_HASH,
30954 +       PROXY_BALANCE_RR
30955 +} proxy_balance_t;
30956 +
30957 +typedef struct {
30958 +       buffer *url;
30959 +
30960 +       proxy_connection_pool *pool;  /* pool of active connections */
30961 +       int use_keepalive;
30962 +
30963 +       proxy_address_pool *address_pool; /* possible destination-addresses, disabling is done here */
30964 +       proxy_balance_t balancer; /* how to choose a address from the address-pool */
30965 +} proxy_backend;
30966 +
30967 +ARRAY_STATIC_DEF(proxy_backends, proxy_backend, );
30968 +
30969 +proxy_backend *proxy_backend_init(void);
30970 +void proxy_backend_free(proxy_backend *backend);
30971 +
30972 +proxy_backends *proxy_backends_init(void);
30973 +void proxy_backends_free(proxy_backends *backends);
30974 +void proxy_backends_add(proxy_backends *backends, proxy_backend *backend);
30975 +
30976 +#endif
30977 +
30978 --- ../lighttpd-1.4.11/src/mod_proxy_core_backlog.c     1970-01-01 03:00:00.000000000 +0300
30979 +++ lighttpd-1.4.12/src/mod_proxy_core_backlog.c        2006-07-18 13:03:40.000000000 +0300
30980 @@ -0,0 +1,109 @@
30981 +#include <stdlib.h>
30982 +
30983 +#include "mod_proxy_core_backlog.h"
30984 +#include "array-static.h"
30985 +
30986 +proxy_backlog *proxy_backlog_init(void) {
30987 +       STRUCT_INIT(proxy_backlog, backlog);
30988 +
30989 +       return backlog;
30990 +}
30991 +
30992 +void proxy_backlog_free(proxy_backlog *backlog) {
30993 +       if (!backlog) return;
30994 +
30995 +       free(backlog);
30996 +}
30997 +
30998 +int proxy_backlog_push(proxy_backlog *backlog, proxy_request *req) {
30999 +       /* first entry */
31000 +       if (NULL == backlog->first) {
31001 +               backlog->first = backlog->last = req;
31002 +       } else {
31003 +               backlog->last->next = req;
31004 +               backlog->last = req;
31005 +       }
31006 +       backlog->length++;
31007 +
31008 +       return 0;
31009 +}
31010 +
31011 +/**
31012 + * remove the first element from the backlog
31013 + */
31014 +proxy_request *proxy_backlog_shift(proxy_backlog *backlog) {
31015 +       proxy_request *req = NULL;
31016 +
31017 +       if (!backlog->first) return req;
31018 +
31019 +       backlog->length--;
31020 +
31021 +       req = backlog->first;
31022 +
31023 +       backlog->first = req->next;
31024 +
31025 +       /* the backlog is empty */
31026 +       if (backlog->first == NULL) backlog->last = NULL;
31027 +
31028 +       return req;
31029 +}
31030 +
31031 +int proxy_backlog_remove_connection(proxy_backlog *backlog, void *con) {
31032 +       proxy_request *req = NULL;
31033 +
31034 +       if (!backlog->first) return -1;
31035 +       if (!con) return -1;
31036 +
31037 +       /* the first element is what we look for */
31038 +       if (backlog->first->con == con) {
31039 +               req = backlog->first;
31040 +               
31041 +               backlog->first = req->next;
31042 +               if (backlog->first == NULL) backlog->last = NULL;
31043 +
31044 +               backlog->length--;
31045 +               
31046 +               proxy_request_free(req);
31047 +
31048 +               return 0;
31049 +       }
31050 +
31051 +
31052 +       for (req = backlog->first; req && req->next; req = req->next) {
31053 +               proxy_request *cur;
31054 +
31055 +               if (req->next->con != con) continue;
31056 +
31057 +               backlog->length--;
31058 +               /* the next node is our searched connection */
31059 +
31060 +               cur = req->next;
31061 +               req->next = cur->next;
31062 +
31063 +               /* the next node is the last one, make the current the new last */
31064 +               if (cur == backlog->last) {
31065 +                       backlog->last = req;
31066 +               }
31067 +               cur->next = NULL;
31068 +
31069 +               proxy_request_free(req);
31070 +
31071 +               return 0;
31072 +       }
31073 +
31074 +       return -1;
31075 +}
31076 +
31077 +proxy_request *proxy_request_init(void) {
31078 +       STRUCT_INIT(proxy_request, request);
31079 +
31080 +       return request;
31081 +}
31082 +
31083 +void proxy_request_free(proxy_request *request) {
31084 +       if (!request) return;
31085 +
31086 +       free(request);
31087 +}
31088 +
31089 +
31090 --- ../lighttpd-1.4.11/src/mod_proxy_core_backlog.h     1970-01-01 03:00:00.000000000 +0300
31091 +++ lighttpd-1.4.12/src/mod_proxy_core_backlog.h        2006-07-18 13:03:40.000000000 +0300
31092 @@ -0,0 +1,56 @@
31093 +#ifndef _MOD_PROXY_CORE_BACKLOG_H_
31094 +#define _MOD_PROXY_CORE_BACKLOG_H_
31095 +
31096 +#include <sys/types.h>
31097 +#include <sys/time.h>
31098 +
31099 +typedef struct _proxy_request {
31100 +       void *con; /* a pointer to the client-connection, (type: connection) */
31101 +
31102 +       time_t added_ts; /* when was the entry added (for timeout handling) */
31103 +
31104 +       struct _proxy_request *next;
31105 +} proxy_request;
31106 +
31107 +/**
31108 + * a we can't get a connection from the pool, queue the request in the
31109 + * request queue (FIFO)
31110 + *
31111 + * - the queue is infinite
31112 + * - entries are removed after a timeout (status 504)
31113 + */
31114 +typedef struct {
31115 +       proxy_request *first; /* pull() does q->first = q->first->next */
31116 +       proxy_request *last; /* push() does q->last = r */
31117 +
31118 +       size_t length;
31119 +} proxy_backlog;
31120 +
31121 +proxy_backlog *proxy_backlog_init(void);
31122 +void proxy_backlog_free(proxy_backlog *backlog);
31123 +
31124 +/**
31125 + * append a request to the end
31126 + * 
31127 + * @return 0 in success, -1 if full
31128 + */ 
31129 +int proxy_backlog_push(proxy_backlog *backlog, proxy_request *req);
31130 +
31131 +/**
31132 + * remove the first request from the backlog
31133 + *
31134 + * @return NULL if backlog is empty, the request otherwise
31135 + */
31136 +proxy_request *proxy_backlog_shift(proxy_backlog *backlog);
31137 +/**
31138 + * remove the request with the connection 'con' from the backlog
31139 + *
31140 + * @return -1 if not found, 0 otherwise
31141 + */
31142 +int proxy_backlog_remove_connection(proxy_backlog *backlog, void *con);
31143 +
31144 +proxy_request *proxy_request_init(void);
31145 +void proxy_request_free(proxy_request *req);
31146 +
31147 +#endif
31148 +
31149 --- ../lighttpd-1.4.11/src/mod_proxy_core_pool.c        1970-01-01 03:00:00.000000000 +0300
31150 +++ lighttpd-1.4.12/src/mod_proxy_core_pool.c   2006-07-18 13:03:40.000000000 +0300
31151 @@ -0,0 +1,127 @@
31152 +
31153 +#include <stdlib.h>
31154 +
31155 +#include "array-static.h"
31156 +#include "sys-files.h"
31157 +#include "log.h"
31158 +#include "mod_proxy_core_pool.h"
31159 +
31160 +proxy_connection * proxy_connection_init(void) {
31161 +       proxy_connection *con;
31162 +
31163 +       con = calloc(1, sizeof(*con));
31164 +
31165 +       con->sock = iosocket_init();
31166 +
31167 +       return con;
31168 +}
31169 +
31170 +void proxy_connection_free(proxy_connection *con) {
31171 +       if (!con) return;
31172 +
31173 +       iosocket_free(con->sock);
31174 +
31175 +       free(con);
31176 +}
31177 +
31178 +proxy_connection_pool *proxy_connection_pool_init(void) {
31179 +       proxy_connection_pool *pool;
31180 +
31181 +       pool = calloc(1, sizeof(*pool));
31182 +
31183 +               /* default: max parallel connections to the backend
31184 +        * 
31185 +        * this should match max-procs if we manage the procs ourself
31186 +                */
31187 +
31188 +       pool->max_size = 8;
31189 +
31190 +       return pool;
31191 +}
31192 +
31193 +void proxy_connection_pool_free(proxy_connection_pool *pool) {
31194 +       size_t i;
31195 +
31196 +       if (!pool) return;
31197 +
31198 +       for (i = 0; i < pool->used; i++) {
31199 +               proxy_connection_free(pool->ptr[i]);
31200 +       }
31201 +
31202 +       if (pool->size) free(pool->ptr);
31203 +
31204 +       free(pool);
31205 +}
31206 +
31207 +void proxy_connection_pool_add_connection(proxy_connection_pool *pool, proxy_connection *c) {
31208 +       ARRAY_STATIC_PREPARE_APPEND(pool);
31209 +
31210 +       pool->ptr[pool->used++] = c;
31211 +}
31212 +/**
31213 + * remove the connection from the pool
31214 + *
31215 + * usually called on conn-shutdown
31216 + */
31217 +int proxy_connection_pool_remove_connection(proxy_connection_pool *pool, proxy_connection *c) {
31218 +       size_t i;
31219 +
31220 +       if (pool->used == 0) return -1; /* empty */
31221 +
31222 +       for (i = 0; i < pool->used; i++) {
31223 +               if (pool->ptr[i] == c) {
31224 +                       break;
31225 +               }
31226 +       }
31227 +
31228 +       if (i == pool->used) return -1; /* not found */
31229 +
31230 +       /**
31231 +        * move all elements one to the left
31232 +        *
31233 +        * if the last element is going to be removed, skip the loop
31234 +        */
31235 +       for (; i < pool->used - 1; i++) {
31236 +               pool->ptr[i] = pool->ptr[i + 1];
31237 +       }
31238 +
31239 +       pool->used--;
31240 +
31241 +       return 0;
31242 +}
31243 +
31244 +proxy_connection_pool_t proxy_connection_pool_get_connection(proxy_connection_pool *pool, proxy_address *address, proxy_connection **rcon) {
31245 +       proxy_connection *proxy_con = NULL;
31246 +       size_t i;
31247 +
31248 +       /* search for a idling proxy connection with the given address */
31249 +       for (i = 0; i < pool->used; i++) {
31250 +               proxy_con = pool->ptr[i];
31251 +
31252 +               if (proxy_con->address == address &&
31253 +                   proxy_con->state == PROXY_CONNECTION_STATE_IDLE) {
31254 +                       break;
31255 +               }
31256 +       }
31257 +
31258 +       if (i == pool->used) {
31259 +               /* no idling connection found */
31260 +
31261 +               if (pool->used == pool->max_size) return PROXY_CONNECTIONPOOL_FULL;
31262 +               
31263 +               proxy_con = proxy_connection_init();
31264 +
31265 +               proxy_con->state = PROXY_CONNECTION_STATE_CONNECTING;
31266 +               proxy_con->address = address;
31267 +
31268 +               proxy_connection_pool_add_connection(pool, proxy_con);
31269 +       } else {
31270 +               proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
31271 +       }
31272 +
31273 +       *rcon = proxy_con;
31274 +
31275 +       return PROXY_CONNECTIONPOOL_GOT_CONNECTION;
31276 +}
31277 +
31278 +
31279 --- ../lighttpd-1.4.11/src/mod_proxy_core_pool.h        1970-01-01 03:00:00.000000000 +0300
31280 +++ lighttpd-1.4.12/src/mod_proxy_core_pool.h   2006-07-18 13:03:40.000000000 +0300
31281 @@ -0,0 +1,52 @@
31282 +#ifndef _MOD_PROXY_CORE_POOL_H_
31283 +#define _MOD_PROXY_CORE_POOL_H_
31284 +
31285 +#include <sys/time.h>
31286 +
31287 +#include "iosocket.h"
31288 +#include "array-static.h"
31289 +#include "mod_proxy_core_address.h"
31290 +
31291 +typedef enum {
31292 +       PROXY_CONNECTION_STATE_UNSET,
31293 +       PROXY_CONNECTION_STATE_CONNECTING,
31294 +       PROXY_CONNECTION_STATE_CONNECTED,
31295 +       PROXY_CONNECTION_STATE_IDLE,
31296 +       PROXY_CONNECTION_STATE_CLOSED,
31297 +} proxy_connection_state_t;
31298 +
31299 +/**
31300 + * a connection to a proxy backend
31301 + * 
31302 + * the connection is independent of the incoming request to allow keep-alive
31303 + */
31304 +typedef struct { 
31305 +       iosocket *sock;
31306 +
31307 +       time_t last_read; /* timeout handling for keep-alive connections */
31308 +       time_t last_write;
31309 +
31310 +       proxy_address *address; /* the struct sock_addr for the sock */
31311 +
31312 +       proxy_connection_state_t state;
31313 +} proxy_connection;
31314 +
31315 +ARRAY_STATIC_DEF(proxy_connection_pool, proxy_connection, size_t max_size;);
31316 +
31317 +typedef enum {
31318 +       PROXY_CONNECTIONPOOL_UNSET,
31319 +       PROXY_CONNECTIONPOOL_FULL,
31320 +       PROXY_CONNECTIONPOOL_GOT_CONNECTION,
31321 +} proxy_connection_pool_t;
31322 +
31323 +proxy_connection_pool *proxy_connection_pool_init(void); 
31324 +void proxy_connection_pool_free(proxy_connection_pool *pool); 
31325 +
31326 +proxy_connection_pool_t proxy_connection_pool_get_connection(proxy_connection_pool *pool, proxy_address *address, proxy_connection **rcon);
31327 +int proxy_connection_pool_remove_connection(proxy_connection_pool *pool, proxy_connection *c);
31328 +
31329 +proxy_connection * proxy_connection_init(void);
31330 +void proxy_connection_free(proxy_connection *pool);
31331 +
31332 +#endif
31333 +
31334 --- ../lighttpd-1.4.11/src/mod_proxy_core_rewrites.c    1970-01-01 03:00:00.000000000 +0300
31335 +++ lighttpd-1.4.12/src/mod_proxy_core_rewrites.c       2006-07-18 17:34:32.000000000 +0300
31336 @@ -0,0 +1,64 @@
31337 +#include <stdlib.h>
31338 +#include <string.h>
31339 +
31340 +#include "mod_proxy_core_rewrites.h"
31341 +#include "log.h"
31342 +
31343 +proxy_rewrite *proxy_rewrite_init(void) {
31344 +       STRUCT_INIT(proxy_rewrite, rewrite);
31345 +
31346 +       rewrite->header = buffer_init();
31347 +       rewrite->match = buffer_init();
31348 +       rewrite->replace = buffer_init();
31349 +
31350 +       return rewrite;
31351 +
31352 +}
31353 +void proxy_rewrite_free(proxy_rewrite *rewrite) {
31354 +       if (!rewrite) return;
31355 +
31356 +       if (rewrite->regex) pcre_free(rewrite->regex);
31357 +
31358 +       buffer_free(rewrite->header);
31359 +       buffer_free(rewrite->match);
31360 +       buffer_free(rewrite->replace);
31361 +
31362 +       free(rewrite);
31363 +}
31364 +
31365 +int proxy_rewrite_set_regex(proxy_rewrite *rewrite, buffer *regex) {
31366 +       const char *errptr;
31367 +       int erroff;
31368 +
31369 +       if (NULL == (rewrite->regex = pcre_compile(BUF_STR(regex),
31370 +                 0, &errptr, &erroff, NULL))) {
31371 +               
31372 +               TRACE("regex compilation for %s failed at %s", BUF_STR(regex), errptr);
31373 +
31374 +               return -1;
31375 +       }
31376 +
31377 +       return 0;
31378 +}
31379 +
31380 +
31381 +proxy_rewrites *proxy_rewrites_init(void) {
31382 +       STRUCT_INIT(proxy_rewrites, rewrites);
31383 +
31384 +       return rewrites;
31385 +}
31386 +
31387 +void proxy_rewrites_add(proxy_rewrites *rewrites, proxy_rewrite *rewrite) {
31388 +       ARRAY_STATIC_PREPARE_APPEND(rewrites);
31389 +
31390 +       rewrites->ptr[rewrites->used++] = rewrite;
31391 +}
31392 +
31393 +void proxy_rewrites_free(proxy_rewrites *rewrites) {
31394 +       if (!rewrites) return;
31395 +
31396 +       free(rewrites);
31397 +}
31398 +
31399 +
31400 +
31401 --- ../lighttpd-1.4.11/src/mod_proxy_core_rewrites.h    1970-01-01 03:00:00.000000000 +0300
31402 +++ lighttpd-1.4.12/src/mod_proxy_core_rewrites.h       2006-07-18 17:34:32.000000000 +0300
31403 @@ -0,0 +1,28 @@
31404 +#ifndef _MOD_PROXY_CORE_REWRITES_H_
31405 +#define _MOD_PROXY_CORE_REWRITES_H_
31406 +
31407 +#include <pcre.h>
31408 +#include "array-static.h"
31409 +#include "buffer.h"
31410 +
31411 +typedef struct {
31412 +       buffer *header;
31413 +
31414 +       pcre *regex; /* regex compiled from the <match> */
31415 +
31416 +       buffer *match;
31417 +       buffer *replace;
31418 +} proxy_rewrite;
31419 +
31420 +ARRAY_STATIC_DEF(proxy_rewrites, proxy_rewrite,);
31421 +
31422 +proxy_rewrite *proxy_rewrite_init(void);
31423 +void proxy_rewrite_free(proxy_rewrite *rewrite);
31424 +int proxy_rewrite_set_regex(proxy_rewrite *rewrite, buffer *regex);
31425 +
31426 +proxy_rewrites *proxy_rewrites_init(void);
31427 +void proxy_rewrites_add(proxy_rewrites *rewrites, proxy_rewrite *rewrite);
31428 +void proxy_rewrites_free(proxy_rewrites *rewrites);
31429 +
31430 +#endif
31431 +
31432 --- ../lighttpd-1.4.11/src/mod_redirect.c       2006-02-08 15:38:06.000000000 +0200
31433 +++ lighttpd-1.4.12/src/mod_redirect.c  2006-07-16 00:26:04.000000000 +0300
31434 @@ -22,35 +22,35 @@
31435         PLUGIN_DATA;
31436         buffer *match_buf;
31437         buffer *location;
31438 -       
31439 +
31440         plugin_config **config_storage;
31441 -       
31442 -       plugin_config conf; 
31443 +
31444 +       plugin_config conf;
31445  } plugin_data;
31446  
31447  INIT_FUNC(mod_redirect_init) {
31448         plugin_data *p;
31449 -       
31450 +
31451         p = calloc(1, sizeof(*p));
31452 -       
31453 +
31454         p->match_buf = buffer_init();
31455         p->location = buffer_init();
31456 -       
31457 +
31458         return p;
31459  }
31460  
31461  FREE_FUNC(mod_redirect_free) {
31462         plugin_data *p = p_d;
31463 -       
31464 +
31465         if (!p) return HANDLER_GO_ON;
31466  
31467         if (p->config_storage) {
31468                 size_t i;
31469                 for (i = 0; i < srv->config_context->used; i++) {
31470                         plugin_config *s = p->config_storage[i];
31471 -                       
31472 +
31473                         pcre_keyvalue_buffer_free(s->redirect);
31474 -                       
31475 +
31476                         free(s);
31477                 }
31478                 free(p->config_storage);
31479 @@ -59,9 +59,9 @@
31480  
31481         buffer_free(p->match_buf);
31482         buffer_free(p->location);
31483 -       
31484 +
31485         free(p);
31486 -       
31487 +
31488         return HANDLER_GO_ON;
31489  }
31490  
31491 @@ -69,195 +69,137 @@
31492         plugin_data *p = p_d;
31493         data_unset *du;
31494         size_t i = 0;
31495 -       
31496 -       config_values_t cv[] = { 
31497 +
31498 +       config_values_t cv[] = {
31499                 { "url.redirect",               NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
31500                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
31501         };
31502 -       
31503 +
31504         if (!p) return HANDLER_ERROR;
31505 -       
31506 +
31507         /* 0 */
31508         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
31509 -       
31510 +
31511         for (i = 0; i < srv->config_context->used; i++) {
31512                 plugin_config *s;
31513                 size_t j;
31514                 array *ca;
31515                 data_array *da = (data_array *)du;
31516 -               
31517 +
31518                 s = calloc(1, sizeof(plugin_config));
31519                 s->redirect   = pcre_keyvalue_buffer_init();
31520 -               
31521 +
31522                 cv[0].destination = s->redirect;
31523 -               
31524 +
31525                 p->config_storage[i] = s;
31526                 ca = ((data_config *)srv->config_context->data[i])->value;
31527 -       
31528 +
31529                 if (0 != config_insert_values_global(srv, ca, cv)) {
31530                         return HANDLER_ERROR;
31531                 }
31532 -               
31533 +
31534                 if (NULL == (du = array_get_element(ca, "url.redirect"))) {
31535                         /* no url.redirect defined */
31536                         continue;
31537                 }
31538 -               
31539 +
31540                 if (du->type != TYPE_ARRAY) {
31541 -                       log_error_write(srv, __FILE__, __LINE__, "sss", 
31542 +                       log_error_write(srv, __FILE__, __LINE__, "sss",
31543                                         "unexpected type for key: ", "url.redirect", "array of strings");
31544 -                       
31545 +
31546                         return HANDLER_ERROR;
31547                 }
31548 -               
31549 +
31550                 da = (data_array *)du;
31551 -                               
31552 +
31553                 for (j = 0; j < da->value->used; j++) {
31554                         if (da->value->data[j]->type != TYPE_STRING) {
31555 -                               log_error_write(srv, __FILE__, __LINE__, "sssbs", 
31556 -                                               "unexpected type for key: ", 
31557 -                                               "url.redirect", 
31558 +                               log_error_write(srv, __FILE__, __LINE__, "sssbs",
31559 +                                               "unexpected type for key: ",
31560 +                                               "url.redirect",
31561                                                 "[", da->value->data[j]->key, "](string)");
31562 -                               
31563 +
31564                                 return HANDLER_ERROR;
31565                         }
31566 -                               
31567 -                       if (0 != pcre_keyvalue_buffer_append(s->redirect, 
31568 +
31569 +                       if (0 != pcre_keyvalue_buffer_append(s->redirect,
31570                                                              ((data_string *)(da->value->data[j]))->key->ptr,
31571                                                              ((data_string *)(da->value->data[j]))->value->ptr)) {
31572 -                                       
31573 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
31574 +
31575 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
31576                                                 "pcre-compile failed for", da->value->data[j]->key);
31577                         }
31578                 }
31579         }
31580 -       
31581 +
31582         return HANDLER_GO_ON;
31583  }
31584  #ifdef HAVE_PCRE_H
31585  static int mod_redirect_patch_connection(server *srv, connection *con, plugin_data *p) {
31586         size_t i, j;
31587         plugin_config *s = p->config_storage[0];
31588 -       
31589 +
31590         p->conf.redirect = s->redirect;
31591 -       
31592 +
31593         /* skip the first, the global context */
31594         for (i = 1; i < srv->config_context->used; i++) {
31595                 data_config *dc = (data_config *)srv->config_context->data[i];
31596                 s = p->config_storage[i];
31597 -               
31598 +
31599                 /* condition didn't match */
31600                 if (!config_check_cond(srv, con, dc)) continue;
31601 -               
31602 +
31603                 /* merge config */
31604                 for (j = 0; j < dc->value->used; j++) {
31605                         data_unset *du = dc->value->data[j];
31606 -                       
31607 +
31608                         if (0 == strcmp(du->key->ptr, "url.redirect")) {
31609                                 p->conf.redirect = s->redirect;
31610                                 p->conf.context = dc;
31611                         }
31612                 }
31613         }
31614 -       
31615 +
31616         return 0;
31617  }
31618  #endif
31619  static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_data) {
31620  #ifdef HAVE_PCRE_H
31621         plugin_data *p = p_data;
31622 -       size_t i;
31623 +       int i;
31624  
31625 -       /* 
31626 +       /*
31627          * REWRITE URL
31628 -        * 
31629 +        *
31630          * e.g. redirect /base/ to /index.php?section=base
31631 -        * 
31632 +        *
31633          */
31634 -       
31635 +
31636         mod_redirect_patch_connection(srv, con, p);
31637 -       
31638 +
31639         buffer_copy_string_buffer(p->match_buf, con->request.uri);
31640 -       
31641 -       for (i = 0; i < p->conf.redirect->used; i++) {
31642 -               pcre *match;
31643 -               pcre_extra *extra;
31644 -               const char *pattern;
31645 -               size_t pattern_len;
31646 -               int n;
31647 -               pcre_keyvalue *kv = p->conf.redirect->kv[i];
31648 -# define N 10
31649 -               int ovec[N * 3];
31650 -               
31651 -               match       = kv->key;
31652 -               extra       = kv->key_extra;
31653 -               pattern     = kv->value->ptr;
31654 -               pattern_len = kv->value->used - 1;
31655 -               
31656 -               if ((n = pcre_exec(match, extra, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
31657 -                       if (n != PCRE_ERROR_NOMATCH) {
31658 -                               log_error_write(srv, __FILE__, __LINE__, "sd",
31659 -                                               "execution error while matching: ", n);
31660 -                               return HANDLER_ERROR;
31661 -                       }
31662 -               } else {
31663 -                       const char **list;
31664 -                       size_t start, end;
31665 -                       size_t k;
31666 -                       
31667 -                       /* it matched */
31668 -                       pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list);
31669 -                       
31670 -                       /* search for $[0-9] */
31671 -                       
31672 -                       buffer_reset(p->location);
31673 -                       
31674 -                       start = 0; end = pattern_len;
31675 -                       for (k = 0; k < pattern_len; k++) {
31676 -                               if ((pattern[k] == '$' || pattern[k] == '%') &&
31677 -                                   isdigit((unsigned char)pattern[k + 1])) {
31678 -                                       /* got one */
31679 -                                       
31680 -                                       size_t num = pattern[k + 1] - '0';
31681 -                                       
31682 -                                       end = k;
31683 -                                       
31684 -                                       buffer_append_string_len(p->location, pattern + start, end - start);
31685 -                                       
31686 -                                       if (pattern[k] == '$') {
31687 -                                               /* n is always > 0 */
31688 -                                               if (num < (size_t)n) {
31689 -                                                       buffer_append_string(p->location, list[num]);
31690 -                                               }
31691 -                                       } else {
31692 -                                               config_append_cond_match_buffer(con, p->conf.context, p->location, num);
31693 -                                       }
31694 -                                       
31695 -                                       k++;
31696 -                                       start = k + 1;
31697 -                               } 
31698 -                       }
31699 -                       
31700 -                       buffer_append_string_len(p->location, pattern + start, pattern_len - start);
31701 -                       
31702 -                       pcre_free(list);
31703 -                       
31704 -                       response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location));
31705 -                       
31706 -                       con->http_status = 301;
31707 -                       con->file_finished = 1;
31708 -                       
31709 -                       return HANDLER_FINISHED;
31710 -               }
31711 +       i = config_exec_pcre_keyvalue_buffer(con, p->conf.redirect, p->conf.context, p->match_buf, p->location);
31712 +
31713 +       if (i >= 0) {
31714 +               response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location));
31715 +
31716 +               con->http_status = 301;
31717 +               con->file_finished = 1;
31718 +
31719 +               return HANDLER_FINISHED;
31720 +       }
31721 +       else if (i != PCRE_ERROR_NOMATCH) {
31722 +               log_error_write(srv, __FILE__, __LINE__, "s",
31723 +                               "execution error while matching", i);
31724         }
31725  #undef N
31726 -               
31727 +
31728  #else
31729         UNUSED(srv);
31730         UNUSED(con);
31731         UNUSED(p_data);
31732  #endif
31733 -       
31734 +
31735         return HANDLER_GO_ON;
31736  }
31737  
31738 @@ -265,13 +207,13 @@
31739  int mod_redirect_plugin_init(plugin *p) {
31740         p->version     = LIGHTTPD_VERSION_ID;
31741         p->name        = buffer_init_string("redirect");
31742 -       
31743 +
31744         p->init        = mod_redirect_init;
31745         p->handle_uri_clean  = mod_redirect_uri_handler;
31746         p->set_defaults  = mod_redirect_set_defaults;
31747         p->cleanup     = mod_redirect_free;
31748 -       
31749 +
31750         p->data        = NULL;
31751 -       
31752 +
31753         return 0;
31754  }
31755 --- ../lighttpd-1.4.11/src/mod_rewrite.c        2005-09-29 20:59:10.000000000 +0300
31756 +++ lighttpd-1.4.12/src/mod_rewrite.c   2006-07-16 00:26:03.000000000 +0300
31757 @@ -13,24 +13,8 @@
31758  #endif
31759  
31760  typedef struct {
31761 -#ifdef HAVE_PCRE_H
31762 -       pcre *key;
31763 -#endif
31764 -       
31765 -       buffer *value;
31766 -       
31767 -       int once;
31768 -} rewrite_rule;
31769 -
31770 -typedef struct {
31771 -       rewrite_rule **ptr;
31772 -       
31773 -       size_t used;
31774 -       size_t size;
31775 -} rewrite_rule_buffer;
31776 -
31777 -typedef struct {
31778 -       rewrite_rule_buffer *rewrite;
31779 +       pcre_keyvalue_buffer *rewrite;
31780 +       buffer *once;
31781         data_config *context; /* to which apply me */
31782  } plugin_config;
31783  
31784 @@ -42,20 +26,20 @@
31785  typedef struct {
31786         PLUGIN_DATA;
31787         buffer *match_buf;
31788 -       
31789 +
31790         plugin_config **config_storage;
31791 -       
31792 -       plugin_config conf; 
31793 +
31794 +       plugin_config conf;
31795  } plugin_data;
31796  
31797  static handler_ctx * handler_ctx_init() {
31798         handler_ctx * hctx;
31799 -       
31800 +
31801         hctx = calloc(1, sizeof(*hctx));
31802 -       
31803 +
31804         hctx->state = REWRITE_STATE_UNSET;
31805         hctx->loops = 0;
31806 -       
31807 +
31808         return hctx;
31809  }
31810  
31811 @@ -63,207 +47,136 @@
31812         free(hctx);
31813  }
31814  
31815 -rewrite_rule_buffer *rewrite_rule_buffer_init(void) {
31816 -       rewrite_rule_buffer *kvb;
31817 -       
31818 -       kvb = calloc(1, sizeof(*kvb));
31819 -       
31820 -       return kvb;
31821 -}
31822 -
31823 -int rewrite_rule_buffer_append(rewrite_rule_buffer *kvb, buffer *key, buffer *value, int once) {
31824 -#ifdef HAVE_PCRE_H
31825 -       size_t i;
31826 -       const char *errptr;
31827 -       int erroff;
31828 -       
31829 -       if (!key) return -1;
31830 -
31831 -       if (kvb->size == 0) {
31832 -               kvb->size = 4;
31833 -               kvb->used = 0;
31834 -               
31835 -               kvb->ptr = malloc(kvb->size * sizeof(*kvb->ptr));
31836 -               
31837 -               for(i = 0; i < kvb->size; i++) {
31838 -                       kvb->ptr[i] = calloc(1, sizeof(**kvb->ptr));
31839 -               }
31840 -       } else if (kvb->used == kvb->size) {
31841 -               kvb->size += 4;
31842 -               
31843 -               kvb->ptr = realloc(kvb->ptr, kvb->size * sizeof(*kvb->ptr));
31844 -               
31845 -               for(i = kvb->used; i < kvb->size; i++) {
31846 -                       kvb->ptr[i] = calloc(1, sizeof(**kvb->ptr));
31847 -               }
31848 -       }
31849 -       
31850 -       if (NULL == (kvb->ptr[kvb->used]->key = pcre_compile(key->ptr,
31851 -                                                           0, &errptr, &erroff, NULL))) {
31852 -               
31853 -               return -1;
31854 -       }
31855 -       
31856 -       kvb->ptr[kvb->used]->value = buffer_init();
31857 -       buffer_copy_string_buffer(kvb->ptr[kvb->used]->value, value);
31858 -       kvb->ptr[kvb->used]->once = once;
31859 -       
31860 -       kvb->used++;
31861 -       
31862 -       return 0;
31863 -#else
31864 -       UNUSED(kvb);
31865 -       UNUSED(value);
31866 -       UNUSED(once);
31867 -       UNUSED(key);
31868 -
31869 -       return -1;
31870 -#endif
31871 -}
31872 -
31873 -void rewrite_rule_buffer_free(rewrite_rule_buffer *kvb) {
31874 -#ifdef HAVE_PCRE_H
31875 -       size_t i;
31876 -
31877 -       for (i = 0; i < kvb->size; i++) {
31878 -               if (kvb->ptr[i]->key) pcre_free(kvb->ptr[i]->key);
31879 -               if (kvb->ptr[i]->value) buffer_free(kvb->ptr[i]->value);
31880 -               free(kvb->ptr[i]);
31881 -       }
31882 -       
31883 -       if (kvb->ptr) free(kvb->ptr);
31884 -#endif
31885 -       
31886 -       free(kvb);
31887 -}
31888 -
31889  
31890  INIT_FUNC(mod_rewrite_init) {
31891         plugin_data *p;
31892 -       
31893 +
31894         p = calloc(1, sizeof(*p));
31895 -       
31896 +
31897         p->match_buf = buffer_init();
31898 -       
31899 +
31900         return p;
31901  }
31902  
31903  FREE_FUNC(mod_rewrite_free) {
31904         plugin_data *p = p_d;
31905 -       
31906 +
31907         UNUSED(srv);
31908  
31909         if (!p) return HANDLER_GO_ON;
31910 -       
31911 +
31912         buffer_free(p->match_buf);
31913         if (p->config_storage) {
31914                 size_t i;
31915                 for (i = 0; i < srv->config_context->used; i++) {
31916                         plugin_config *s = p->config_storage[i];
31917 -                       rewrite_rule_buffer_free(s->rewrite);
31918 -                       
31919 +                       pcre_keyvalue_buffer_free(s->rewrite);
31920 +                       buffer_free(s->once);
31921 +
31922                         free(s);
31923                 }
31924                 free(p->config_storage);
31925         }
31926 -       
31927 +
31928         free(p);
31929 -       
31930 +
31931         return HANDLER_GO_ON;
31932  }
31933  
31934  static int parse_config_entry(server *srv, plugin_config *s, array *ca, const char *option, int once) {
31935         data_unset *du;
31936 -       
31937 +
31938         if (NULL != (du = array_get_element(ca, option))) {
31939                 data_array *da = (data_array *)du;
31940                 size_t j;
31941 -               
31942 +
31943                 if (du->type != TYPE_ARRAY) {
31944 -                       log_error_write(srv, __FILE__, __LINE__, "sss", 
31945 +                       log_error_write(srv, __FILE__, __LINE__, "sss",
31946                                         "unexpected type for key: ", option, "array of strings");
31947 -                       
31948 +
31949                         return HANDLER_ERROR;
31950                 }
31951 -               
31952 +
31953                 da = (data_array *)du;
31954 -               
31955 +
31956                 for (j = 0; j < da->value->used; j++) {
31957                         if (da->value->data[j]->type != TYPE_STRING) {
31958 -                               log_error_write(srv, __FILE__, __LINE__, "sssbs", 
31959 -                                               "unexpected type for key: ", 
31960 -                                               option, 
31961 +                               log_error_write(srv, __FILE__, __LINE__, "sssbs",
31962 +                                               "unexpected type for key: ",
31963 +                                               option,
31964                                                 "[", da->value->data[j]->key, "](string)");
31965 -                               
31966 +
31967                                 return HANDLER_ERROR;
31968                         }
31969 -                       
31970 -                       if (0 != rewrite_rule_buffer_append(s->rewrite, 
31971 -                                                           ((data_string *)(da->value->data[j]))->key,
31972 -                                                           ((data_string *)(da->value->data[j]))->value,
31973 -                                                           once)) {
31974 +
31975 +                       if (0 != pcre_keyvalue_buffer_append(s->rewrite,
31976 +                                                           ((data_string *)(da->value->data[j]))->key->ptr,
31977 +                                                           ((data_string *)(da->value->data[j]))->value->ptr)) {
31978  #ifdef HAVE_PCRE_H
31979 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
31980 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
31981                                                 "pcre-compile failed for", da->value->data[j]->key);
31982  #else
31983 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
31984 +                               log_error_write(srv, __FILE__, __LINE__, "s",
31985                                                 "pcre support is missing, please install libpcre and the headers");
31986  #endif
31987                         }
31988 +
31989 +                       if (once) {
31990 +                               buffer_append_string_len(s->once, CONST_STR_LEN("1"));
31991 +                       } else {
31992 +                               buffer_append_string_len(s->once, CONST_STR_LEN("0"));
31993 +                       }
31994                 }
31995         }
31996 -       
31997 +
31998         return 0;
31999  }
32000  
32001  SETDEFAULTS_FUNC(mod_rewrite_set_defaults) {
32002         plugin_data *p = p_d;
32003         size_t i = 0;
32004 -       
32005 -       config_values_t cv[] = { 
32006 +
32007 +       config_values_t cv[] = {
32008                 { "url.rewrite-repeat",        NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
32009                 { "url.rewrite-once",          NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
32010 -               
32011 -               /* old names, still supported 
32012 -                * 
32013 +
32014 +               /* old names, still supported
32015 +                *
32016                  * url.rewrite remapped to url.rewrite-once
32017                  * url.rewrite-final    is url.rewrite-once
32018 -                * 
32019 +                *
32020                  */
32021                 { "url.rewrite",               NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
32022                 { "url.rewrite-final",         NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
32023                 { NULL,                        NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
32024         };
32025 -       
32026 +
32027         if (!p) return HANDLER_ERROR;
32028 -       
32029 +
32030         /* 0 */
32031         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
32032 -       
32033 +
32034         for (i = 0; i < srv->config_context->used; i++) {
32035                 plugin_config *s;
32036                 array *ca;
32037 -               
32038 +
32039                 s = calloc(1, sizeof(plugin_config));
32040 -               s->rewrite   = rewrite_rule_buffer_init();
32041 -               
32042 -               cv[0].destination = s->rewrite;
32043 -               cv[1].destination = s->rewrite;
32044 -               cv[2].destination = s->rewrite;
32045 -               
32046 +               s->rewrite   = pcre_keyvalue_buffer_init();
32047 +               s->once      = buffer_init();
32048 +
32049                 p->config_storage[i] = s;
32050                 ca = ((data_config *)srv->config_context->data[i])->value;
32051 -       
32052 +
32053                 if (0 != config_insert_values_global(srv, ca, cv)) {
32054                         return HANDLER_ERROR;
32055                 }
32056 -               
32057 +
32058                 parse_config_entry(srv, s, ca, "url.rewrite-once",   1);
32059                 parse_config_entry(srv, s, ca, "url.rewrite-final",  1);
32060                 parse_config_entry(srv, s, ca, "url.rewrite",        1);
32061                 parse_config_entry(srv, s, ca, "url.rewrite-repeat", 0);
32062         }
32063 -       
32064 +
32065         return HANDLER_GO_ON;
32066  }
32067  #ifdef HAVE_PCRE_H
32068 @@ -271,157 +184,107 @@
32069         size_t i, j;
32070         plugin_config *s = p->config_storage[0];
32071         p->conf.rewrite = s->rewrite;
32072 -       
32073 +       p->conf.once    = s->once;
32074 +
32075         /* skip the first, the global context */
32076         for (i = 1; i < srv->config_context->used; i++) {
32077                 data_config *dc = (data_config *)srv->config_context->data[i];
32078                 s = p->config_storage[i];
32079 -               
32080 +
32081                 if (COMP_HTTP_URL == dc->comp) continue;
32082 -               
32083 +
32084                 /* condition didn't match */
32085                 if (!config_check_cond(srv, con, dc)) continue;
32086 -               
32087 +
32088                 /* merge config */
32089                 for (j = 0; j < dc->value->used; j++) {
32090                         data_unset *du = dc->value->data[j];
32091 -                       
32092 +
32093                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite"))) {
32094                                 p->conf.rewrite = s->rewrite;
32095 +                               p->conf.once    = s->once;
32096                                 p->conf.context = dc;
32097                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-once"))) {
32098                                 p->conf.rewrite = s->rewrite;
32099 +                               p->conf.once    = s->once;
32100                                 p->conf.context = dc;
32101                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-repeat"))) {
32102                                 p->conf.rewrite = s->rewrite;
32103 +                               p->conf.once    = s->once;
32104                                 p->conf.context = dc;
32105                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-final"))) {
32106                                 p->conf.rewrite = s->rewrite;
32107 +                               p->conf.once    = s->once;
32108                                 p->conf.context = dc;
32109                         }
32110                 }
32111         }
32112 -       
32113 +
32114         return 0;
32115  }
32116  #endif
32117  URIHANDLER_FUNC(mod_rewrite_con_reset) {
32118         plugin_data *p = p_d;
32119 -       
32120 +
32121         UNUSED(srv);
32122 -       
32123 +
32124         if (con->plugin_ctx[p->id]) {
32125                 handler_ctx_free(con->plugin_ctx[p->id]);
32126                 con->plugin_ctx[p->id] = NULL;
32127         }
32128 -       
32129 +
32130         return HANDLER_GO_ON;
32131  }
32132  
32133  URIHANDLER_FUNC(mod_rewrite_uri_handler) {
32134  #ifdef HAVE_PCRE_H
32135         plugin_data *p = p_d;
32136 -       size_t i;
32137 +       int i;
32138         handler_ctx *hctx;
32139  
32140 -       /* 
32141 +       /*
32142          * REWRITE URL
32143 -        * 
32144 +        *
32145          * e.g. rewrite /base/ to /index.php?section=base
32146 -        * 
32147 +        *
32148          */
32149 -       
32150 +
32151         if (con->plugin_ctx[p->id]) {
32152                 hctx = con->plugin_ctx[p->id];
32153 -               
32154 +
32155                 if (hctx->loops++ > 100) {
32156 -                       log_error_write(srv, __FILE__, __LINE__,  "s",  
32157 +                       log_error_write(srv, __FILE__, __LINE__,  "s",
32158                                         "ENDLESS LOOP IN rewrite-rule DETECTED ... aborting request, perhaps you want to use url.rewrite-once instead of url.rewrite-repeat");
32159 -                       
32160 +
32161                         return HANDLER_ERROR;
32162                 }
32163 -               
32164 +
32165                 if (hctx->state == REWRITE_STATE_FINISHED) return HANDLER_GO_ON;
32166         }
32167 -       
32168 +
32169         mod_rewrite_patch_connection(srv, con, p);
32170  
32171         if (!p->conf.rewrite) return HANDLER_GO_ON;
32172 -       
32173 +
32174         buffer_copy_string_buffer(p->match_buf, con->request.uri);
32175 -       
32176 -       for (i = 0; i < p->conf.rewrite->used; i++) {
32177 -               pcre *match;
32178 -               const char *pattern;
32179 -               size_t pattern_len;
32180 -               int n;
32181 -               rewrite_rule *rule = p->conf.rewrite->ptr[i];
32182 -# define N 10
32183 -               int ovec[N * 3];
32184 -               
32185 -               match       = rule->key;
32186 -               pattern     = rule->value->ptr;
32187 -               pattern_len = rule->value->used - 1;
32188 -               
32189 -               if ((n = pcre_exec(match, NULL, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
32190 -                       if (n != PCRE_ERROR_NOMATCH) {
32191 -                               log_error_write(srv, __FILE__, __LINE__, "sd",
32192 -                                               "execution error while matching: ", n);
32193 -                               return HANDLER_ERROR;
32194 -                       }
32195 -               } else {
32196 -                       const char **list;
32197 -                       size_t start, end;
32198 -                       size_t k;
32199 -                       
32200 -                       /* it matched */
32201 -                       pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list);
32202 -                       
32203 -                       /* search for $[0-9] */
32204 -                       
32205 -                       buffer_reset(con->request.uri);
32206 -                       
32207 -                       start = 0; end = pattern_len;
32208 -                       for (k = 0; k < pattern_len; k++) {
32209 -                               if ((pattern[k] == '$' || pattern[k] == '%') &&
32210 -                                   isdigit((unsigned char)pattern[k + 1])) {
32211 -                                       /* got one */
32212 -                                       
32213 -                                       size_t num = pattern[k + 1] - '0';
32214 -                                       
32215 -                                       end = k;
32216 -                                       
32217 -                                       buffer_append_string_len(con->request.uri, pattern + start, end - start);
32218 -                                       
32219 -                                       if (pattern[k] == '$') {
32220 -                                               /* n is always > 0 */
32221 -                                               if (num < (size_t)n) {
32222 -                                                       buffer_append_string(con->request.uri, list[num]);
32223 -                                               }
32224 -                                       } else {
32225 -                                               config_append_cond_match_buffer(con, p->conf.context, con->request.uri, num);
32226 -                                       }
32227 -                                       
32228 -                                       k++;
32229 -                                       start = k + 1;
32230 -                               } 
32231 -                       }
32232 -                       
32233 -                       buffer_append_string_len(con->request.uri, pattern + start, pattern_len - start);
32234 -                       
32235 -                       pcre_free(list);
32236 -                       
32237 -                       hctx = handler_ctx_init();
32238 -                               
32239 -                       con->plugin_ctx[p->id] = hctx;
32240 -                       
32241 -                       if (rule->once) hctx->state = REWRITE_STATE_FINISHED;
32242 -                       
32243 -                       return HANDLER_COMEBACK;
32244 -               }
32245 +       i = config_exec_pcre_keyvalue_buffer(con, p->conf.rewrite, p->conf.context, p->match_buf, con->request.uri);
32246 +
32247 +       if (i >= 0) {
32248 +               hctx = handler_ctx_init();
32249 +
32250 +               con->plugin_ctx[p->id] = hctx;
32251 +
32252 +               if (p->conf.once->ptr[i] == '1')
32253 +                       hctx->state = REWRITE_STATE_FINISHED;
32254 +
32255 +               return HANDLER_COMEBACK;
32256 +       }
32257 +       else if (i != PCRE_ERROR_NOMATCH) {
32258 +               log_error_write(srv, __FILE__, __LINE__, "s",
32259 +                               "execution error while matching", i);
32260         }
32261  #undef N
32262 -               
32263 +
32264  #else
32265         UNUSED(srv);
32266         UNUSED(con);
32267 @@ -434,17 +297,17 @@
32268  int mod_rewrite_plugin_init(plugin *p) {
32269         p->version     = LIGHTTPD_VERSION_ID;
32270         p->name        = buffer_init_string("rewrite");
32271 -       
32272 +
32273         p->init        = mod_rewrite_init;
32274         /* it has to stay _raw as we are matching on uri + querystring
32275          */
32276 -       
32277 +
32278         p->handle_uri_raw = mod_rewrite_uri_handler;
32279         p->set_defaults = mod_rewrite_set_defaults;
32280         p->cleanup     = mod_rewrite_free;
32281         p->connection_reset = mod_rewrite_con_reset;
32282 -       
32283 +
32284         p->data        = NULL;
32285 -       
32286 +
32287         return 0;
32288  }
32289 --- ../lighttpd-1.4.11/src/mod_rrdtool.c        2005-08-22 01:52:24.000000000 +0300
32290 +++ lighttpd-1.4.12/src/mod_rrdtool.c   2006-07-18 13:03:40.000000000 +0300
32291 @@ -5,7 +5,6 @@
32292  #include <stdlib.h>
32293  #include <stdio.h>
32294  #include <string.h>
32295 -#include <unistd.h>
32296  #include <errno.h>
32297  #include <time.h>
32298  
32299 @@ -20,10 +19,14 @@
32300  /* no need for waitpid if we don't have fork */
32301  #include <sys/wait.h>
32302  #endif
32303 +
32304 +#include "sys-files.h"
32305 +#include "sys-process.h"
32306 +
32307  typedef struct {
32308         buffer *path_rrdtool_bin;
32309         buffer *path_rrd;
32310 -       
32311 +
32312         double requests, *requests_ptr;
32313         double bytes_written, *bytes_written_ptr;
32314         double bytes_read, *bytes_read_ptr;
32315 @@ -31,84 +34,84 @@
32316  
32317  typedef struct {
32318         PLUGIN_DATA;
32319 -       
32320 +
32321         buffer *cmd;
32322         buffer *resp;
32323 -       
32324 +
32325         int read_fd, write_fd;
32326         pid_t rrdtool_pid;
32327 -       
32328 +
32329         int rrdtool_running;
32330 -       
32331 +
32332         plugin_config **config_storage;
32333         plugin_config conf;
32334  } plugin_data;
32335  
32336  INIT_FUNC(mod_rrd_init) {
32337         plugin_data *p;
32338 -       
32339 +
32340         p = calloc(1, sizeof(*p));
32341 -       
32342 +
32343         p->resp = buffer_init();
32344         p->cmd = buffer_init();
32345 -       
32346 +
32347         return p;
32348  }
32349  
32350  FREE_FUNC(mod_rrd_free) {
32351         plugin_data *p = p_d;
32352         size_t i;
32353 -       
32354 +
32355         if (!p) return HANDLER_GO_ON;
32356 -       
32357 +
32358         if (p->config_storage) {
32359                 for (i = 0; i < srv->config_context->used; i++) {
32360                         plugin_config *s = p->config_storage[i];
32361 -                       
32362 +
32363                         buffer_free(s->path_rrdtool_bin);
32364                         buffer_free(s->path_rrd);
32365 -                       
32366 +
32367                         free(s);
32368                 }
32369         }
32370         buffer_free(p->cmd);
32371         buffer_free(p->resp);
32372 -       
32373 +
32374         free(p->config_storage);
32375 -       
32376 +
32377         if (p->rrdtool_pid) {
32378                 int status;
32379                 close(p->read_fd);
32380                 close(p->write_fd);
32381 -#ifdef HAVE_FORK       
32382 +#ifdef HAVE_FORK
32383                 /* collect status */
32384                 waitpid(p->rrdtool_pid, &status, 0);
32385  #endif
32386         }
32387 -       
32388 +
32389         free(p);
32390 -       
32391 +
32392         return HANDLER_GO_ON;
32393  }
32394  
32395  int mod_rrd_create_pipe(server *srv, plugin_data *p) {
32396         pid_t pid;
32397 -       
32398 +
32399         int to_rrdtool_fds[2];
32400         int from_rrdtool_fds[2];
32401 -#ifdef HAVE_FORK       
32402 +#ifdef HAVE_FORK
32403         if (pipe(to_rrdtool_fds)) {
32404 -               log_error_write(srv, __FILE__, __LINE__, "ss", 
32405 +               log_error_write(srv, __FILE__, __LINE__, "ss",
32406                                 "pipe failed: ", strerror(errno));
32407                 return -1;
32408         }
32409 -       
32410 +
32411         if (pipe(from_rrdtool_fds)) {
32412 -               log_error_write(srv, __FILE__, __LINE__, "ss", 
32413 +               log_error_write(srv, __FILE__, __LINE__, "ss",
32414                                 "pipe failed: ", strerror(errno));
32415                 return -1;
32416         }
32417 -       
32418 +
32419         /* fork, execve */
32420         switch (pid = fork()) {
32421         case 0: {
32422 @@ -117,33 +120,28 @@
32423                 int argc;
32424                 int i = 0;
32425                 char *dash = "-";
32426 -               
32427 +
32428                 /* move stdout to from_rrdtool_fd[1] */
32429                 close(STDOUT_FILENO);
32430                 dup2(from_rrdtool_fds[1], STDOUT_FILENO);
32431                 close(from_rrdtool_fds[1]);
32432                 /* not needed */
32433                 close(from_rrdtool_fds[0]);
32434 -               
32435 +
32436                 /* move the stdin to to_rrdtool_fd[0] */
32437                 close(STDIN_FILENO);
32438                 dup2(to_rrdtool_fds[0], STDIN_FILENO);
32439                 close(to_rrdtool_fds[0]);
32440                 /* not needed */
32441                 close(to_rrdtool_fds[1]);
32442 -               
32443 +
32444                 close(STDERR_FILENO);
32445 -               
32446 -               if (srv->errorlog_mode == ERRORLOG_FILE) {
32447 -                       dup2(srv->errorlog_fd, STDERR_FILENO);
32448 -                       close(srv->errorlog_fd);
32449 -               }
32450 -               
32451 +
32452                 /* set up args */
32453                 argc = 3;
32454                 args = malloc(sizeof(*args) * argc);
32455                 i = 0;
32456 -               
32457 +
32458                 args[i++] = p->conf.path_rrdtool_bin->ptr;
32459                 args[i++] = dash;
32460                 args[i++] = NULL;
32461 @@ -152,12 +150,12 @@
32462                 for (i = 3; i < 256; i++) {
32463                         close(i);
32464                 }
32465 -               
32466 +
32467                 /* exec the cgi */
32468                 execv(args[0], args);
32469 -               
32470 +
32471                 log_error_write(srv, __FILE__, __LINE__, "sss", "spawing rrdtool failed: ", strerror(errno), args[0]);
32472 -               
32473 +
32474                 /* */
32475                 SEGFAULT();
32476                 break;
32477 @@ -168,19 +166,19 @@
32478                 break;
32479         default: {
32480                 /* father */
32481 -               
32482 +
32483                 close(from_rrdtool_fds[1]);
32484                 close(to_rrdtool_fds[0]);
32485 -               
32486 +
32487                 /* register PID and wait for them asyncronously */
32488                 p->write_fd = to_rrdtool_fds[1];
32489                 p->read_fd = from_rrdtool_fds[0];
32490                 p->rrdtool_pid = pid;
32491 -               
32492 +
32493                 break;
32494         }
32495         }
32496 -       
32497 +
32498         return 0;
32499  #else
32500         return -1;
32501 @@ -189,19 +187,19 @@
32502  
32503  static int mod_rrdtool_create_rrd(server *srv, plugin_data *p, plugin_config *s) {
32504         struct stat st;
32505 -       
32506 +
32507         /* check if DB already exists */
32508         if (0 == stat(s->path_rrd->ptr, &st)) {
32509                 /* check if it is plain file */
32510                 if (!S_ISREG(st.st_mode)) {
32511 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
32512 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
32513                                         "not a regular file:", s->path_rrd);
32514                         return HANDLER_ERROR;
32515                 }
32516         } else {
32517                 int r ;
32518                 /* create a new one */
32519 -               
32520 +
32521                 BUFFER_COPY_STRING_CONST(p->cmd, "create ");
32522                 buffer_append_string_buffer(p->cmd, s->path_rrd);
32523                 buffer_append_string(p->cmd, " --step 60 ");
32524 @@ -220,158 +218,155 @@
32525                 buffer_append_string(p->cmd, "RRA:MIN:0.5:6:700 ");
32526                 buffer_append_string(p->cmd, "RRA:MIN:0.5:24:775 ");
32527                 buffer_append_string(p->cmd, "RRA:MIN:0.5:288:797\n");
32528 -               
32529 +
32530                 if (-1 == (r = write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
32531 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
32532 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
32533                                 "rrdtool-write: failed", strerror(errno));
32534 -                       
32535 +
32536                         return HANDLER_ERROR;
32537                 }
32538 -               
32539 +
32540                 buffer_prepare_copy(p->resp, 4096);
32541                 if (-1 == (r = read(p->read_fd, p->resp->ptr, p->resp->size))) {
32542 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
32543 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
32544                                 "rrdtool-read: failed", strerror(errno));
32545 -                       
32546 +
32547                         return HANDLER_ERROR;
32548                 }
32549 -               
32550 +
32551                 p->resp->used = r;
32552 -               
32553 +
32554                 if (p->resp->ptr[0] != 'O' ||
32555                     p->resp->ptr[1] != 'K') {
32556 -                       log_error_write(srv, __FILE__, __LINE__, "sbb", 
32557 +                       log_error_write(srv, __FILE__, __LINE__, "sbb",
32558                                 "rrdtool-response:", p->cmd, p->resp);
32559 -                       
32560 +
32561                         return HANDLER_ERROR;
32562                 }
32563         }
32564 -       
32565 +
32566         return HANDLER_GO_ON;
32567  }
32568  
32569 -#define PATCH(x) \
32570 -       p->conf.x = s->x;
32571  static int mod_rrd_patch_connection(server *srv, connection *con, plugin_data *p) {
32572         size_t i, j;
32573         plugin_config *s = p->config_storage[0];
32574 -       
32575 -       PATCH(path_rrdtool_bin);
32576 -       PATCH(path_rrd);
32577 -       
32578 +
32579 +       PATCH_OPTION(path_rrdtool_bin);
32580 +       PATCH_OPTION(path_rrd);
32581 +
32582         p->conf.bytes_written_ptr = &(s->bytes_written);
32583         p->conf.bytes_read_ptr = &(s->bytes_read);
32584         p->conf.requests_ptr = &(s->requests);
32585 -       
32586 +
32587         /* skip the first, the global context */
32588         for (i = 1; i < srv->config_context->used; i++) {
32589                 data_config *dc = (data_config *)srv->config_context->data[i];
32590                 s = p->config_storage[i];
32591 -               
32592 +
32593                 /* condition didn't match */
32594                 if (!config_check_cond(srv, con, dc)) continue;
32595 -               
32596 +
32597                 /* merge config */
32598                 for (j = 0; j < dc->value->used; j++) {
32599                         data_unset *du = dc->value->data[j];
32600 -                       
32601 +
32602                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("rrdtool.db-name"))) {
32603 -                               PATCH(path_rrd);
32604 +                               PATCH_OPTION(path_rrd);
32605                                 /* get pointers to double values */
32606 -                               
32607 +
32608                                 p->conf.bytes_written_ptr = &(s->bytes_written);
32609                                 p->conf.bytes_read_ptr = &(s->bytes_read);
32610                                 p->conf.requests_ptr = &(s->requests);
32611                         }
32612                 }
32613         }
32614 -       
32615 +
32616         return 0;
32617  }
32618 -#undef PATCH
32619  
32620  SETDEFAULTS_FUNC(mod_rrd_set_defaults) {
32621         plugin_data *p = p_d;
32622         size_t i;
32623 -       
32624 -       config_values_t cv[] = { 
32625 +
32626 +       config_values_t cv[] = {
32627                 { "rrdtool.binary",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
32628                 { "rrdtool.db-name",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
32629                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
32630         };
32631 -       
32632 +
32633         if (!p) return HANDLER_ERROR;
32634 -       
32635 +
32636         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
32637 -       
32638 +
32639         for (i = 0; i < srv->config_context->used; i++) {
32640                 plugin_config *s;
32641 -               
32642 +
32643                 s = calloc(1, sizeof(plugin_config));
32644                 s->path_rrdtool_bin = buffer_init();
32645                 s->path_rrd = buffer_init();
32646                 s->requests = 0;
32647                 s->bytes_written = 0;
32648                 s->bytes_read = 0;
32649 -               
32650 +
32651                 cv[0].destination = s->path_rrdtool_bin;
32652                 cv[1].destination = s->path_rrd;
32653 -               
32654 +
32655                 p->config_storage[i] = s;
32656 -       
32657 +
32658                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
32659                         return HANDLER_ERROR;
32660                 }
32661 -               
32662 +
32663                 if (i > 0 && !buffer_is_empty(s->path_rrdtool_bin)) {
32664                         /* path_rrdtool_bin is a global option */
32665 -                       
32666 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
32667 +
32668 +                       log_error_write(srv, __FILE__, __LINE__, "s",
32669                                         "rrdtool.binary can only be set as a global option.");
32670 -                       
32671 +
32672                         return HANDLER_ERROR;
32673                 }
32674 -               
32675 +
32676         }
32677 -       
32678 +
32679         p->conf.path_rrdtool_bin = p->config_storage[0]->path_rrdtool_bin;
32680         p->rrdtool_running = 0;
32681 -       
32682 +
32683         /* check for dir */
32684 -       
32685 +
32686         if (buffer_is_empty(p->conf.path_rrdtool_bin)) {
32687 -               log_error_write(srv, __FILE__, __LINE__, "s", 
32688 +               log_error_write(srv, __FILE__, __LINE__, "s",
32689                                 "rrdtool.binary has to be set");
32690                 return HANDLER_ERROR;
32691         }
32692 -       
32693 +
32694         /* open the pipe to rrdtool */
32695         if (mod_rrd_create_pipe(srv, p)) {
32696                 return HANDLER_ERROR;
32697         }
32698 -       
32699 +
32700         p->rrdtool_running = 1;
32701 -               
32702 +
32703         return HANDLER_GO_ON;
32704  }
32705  
32706  TRIGGER_FUNC(mod_rrd_trigger) {
32707         plugin_data *p = p_d;
32708         size_t i;
32709 -       
32710 +
32711         if (!p->rrdtool_running) return HANDLER_GO_ON;
32712         if ((srv->cur_ts % 60) != 0) return HANDLER_GO_ON;
32713 -       
32714 +
32715         for (i = 0; i < srv->config_context->used; i++) {
32716                 plugin_config *s = p->config_storage[i];
32717                 int r;
32718 -               
32719 +
32720                 if (buffer_is_empty(s->path_rrd)) continue;
32721 -       
32722 +
32723                 /* write the data down every minute */
32724 -               
32725 +
32726                 if (HANDLER_GO_ON != mod_rrdtool_create_rrd(srv, p, s)) return HANDLER_ERROR;
32727 -               
32728 +
32729                 BUFFER_COPY_STRING_CONST(p->cmd, "update ");
32730                 buffer_append_string_buffer(p->cmd, s->path_rrd);
32731                 BUFFER_APPEND_STRING_CONST(p->cmd, " N:");
32732 @@ -381,69 +376,69 @@
32733                 BUFFER_APPEND_STRING_CONST(p->cmd, ":");
32734                 buffer_append_long(p->cmd, s->requests);
32735                 BUFFER_APPEND_STRING_CONST(p->cmd, "\n");
32736 -               
32737 +
32738                 if (-1 == (r = write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
32739                         p->rrdtool_running = 0;
32740 -                       
32741 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
32742 +
32743 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
32744                                         "rrdtool-write: failed", strerror(errno));
32745 -                       
32746 +
32747                         return HANDLER_ERROR;
32748                 }
32749 -               
32750 +
32751                 buffer_prepare_copy(p->resp, 4096);
32752                 if (-1 == (r = read(p->read_fd, p->resp->ptr, p->resp->size))) {
32753                         p->rrdtool_running = 0;
32754 -                       
32755 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
32756 +
32757 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
32758                                         "rrdtool-read: failed", strerror(errno));
32759 -                       
32760 +
32761                         return HANDLER_ERROR;
32762                 }
32763 -               
32764 +
32765                 p->resp->used = r;
32766 -               
32767 +
32768                 if (p->resp->ptr[0] != 'O' ||
32769                     p->resp->ptr[1] != 'K') {
32770                         p->rrdtool_running = 0;
32771 -                       
32772 -                       log_error_write(srv, __FILE__, __LINE__, "sbb", 
32773 +
32774 +                       log_error_write(srv, __FILE__, __LINE__, "sbb",
32775                                         "rrdtool-response:", p->cmd, p->resp);
32776 -                       
32777 +
32778                         return HANDLER_ERROR;
32779                 }
32780                 s->requests = 0;
32781                 s->bytes_written = 0;
32782                 s->bytes_read = 0;
32783         }
32784 -       
32785 +
32786         return HANDLER_GO_ON;
32787  }
32788  
32789  REQUESTDONE_FUNC(mod_rrd_account) {
32790         plugin_data *p = p_d;
32791 -       
32792 +
32793         mod_rrd_patch_connection(srv, con, p);
32794 -       
32795 +
32796         *(p->conf.requests_ptr)      += 1;
32797         *(p->conf.bytes_written_ptr) += con->bytes_written;
32798         *(p->conf.bytes_read_ptr)    += con->bytes_read;
32799 -       
32800 +
32801         return HANDLER_GO_ON;
32802  }
32803  
32804  int mod_rrdtool_plugin_init(plugin *p) {
32805         p->version     = LIGHTTPD_VERSION_ID;
32806         p->name        = buffer_init_string("rrd");
32807 -       
32808 +
32809         p->init        = mod_rrd_init;
32810         p->cleanup     = mod_rrd_free;
32811         p->set_defaults= mod_rrd_set_defaults;
32812 -       
32813 +
32814         p->handle_trigger      = mod_rrd_trigger;
32815         p->handle_request_done = mod_rrd_account;
32816 -       
32817 +
32818         p->data        = NULL;
32819 -       
32820 +
32821         return 0;
32822  }
32823 --- ../lighttpd-1.4.11/src/mod_scgi.c   2006-03-04 17:15:26.000000000 +0200
32824 +++ lighttpd-1.4.12/src/mod_scgi.c      2006-07-18 13:03:40.000000000 +0300
32825 @@ -1,5 +1,4 @@
32826  #include <sys/types.h>
32827 -#include <unistd.h>
32828  #include <errno.h>
32829  #include <fcntl.h>
32830  #include <string.h>
32831 @@ -18,6 +17,7 @@
32832  #include "connections.h"
32833  #include "response.h"
32834  #include "joblist.h"
32835 +#include "http_resp.h"
32836  
32837  #include "plugin.h"
32838  
32839 @@ -30,7 +30,9 @@
32840  #endif
32841  
32842  #include "sys-socket.h"
32843 -
32844 +#include "sys-files.h"
32845 +#include "sys-strings.h"
32846 +#include "sys-process.h"
32847  
32848  #ifndef UNIX_PATH_MAX
32849  # define UNIX_PATH_MAX 108
32850 @@ -46,30 +48,29 @@
32851  enum {EOL_UNSET, EOL_N, EOL_RN};
32852  
32853  /*
32854 - * 
32855 + *
32856   * TODO:
32857 - * 
32858 + *
32859   * - add timeout for a connect to a non-scgi process
32860   *   (use state_timestamp + state)
32861 - * 
32862 + *
32863   */
32864  
32865  typedef struct scgi_proc {
32866         size_t id; /* id will be between 1 and max_procs */
32867         buffer *socket; /* config.socket + "-" + id */
32868         unsigned port;  /* config.port + pno */
32869 -       
32870 -       pid_t pid;   /* PID of the spawned process (0 if not spawned locally) */
32871  
32872 +       pid_t pid;   /* PID of the spawned process (0 if not spawned locally) */
32873  
32874         size_t load; /* number of requests waiting on this process */
32875  
32876         time_t last_used; /* see idle_timeout */
32877         size_t requests;  /* see max_requests */
32878         struct scgi_proc *prev, *next; /* see first */
32879 -       
32880 +
32881         time_t disable_ts; /* replace by host->something */
32882 -       
32883 +
32884         int is_local;
32885  
32886         enum { PROC_STATE_UNSET,            /* init-phase */
32887 @@ -78,7 +79,7 @@
32888                         PROC_STATE_KILLED,  /* was killed as we don't have the load anymore */
32889                         PROC_STATE_DIED,    /* marked as dead, should be restarted */
32890                         PROC_STATE_DISABLED /* proc disabled as it resulted in an error */
32891 -       } state; 
32892 +       } state;
32893  } scgi_proc;
32894  
32895  typedef struct {
32896 @@ -86,20 +87,20 @@
32897          * sorted by lowest load
32898          *
32899          * whenever a job is done move it up in the list
32900 -        * until it is sorted, move it down as soon as the 
32901 +        * until it is sorted, move it down as soon as the
32902          * job is started
32903          */
32904 -       scgi_proc *first; 
32905 -       scgi_proc *unused_procs; 
32906 +       scgi_proc *first;
32907 +       scgi_proc *unused_procs;
32908  
32909 -       /* 
32910 +       /*
32911          * spawn at least min_procs, at max_procs.
32912          *
32913 -        * as soon as the load of the first entry 
32914 +        * as soon as the load of the first entry
32915          * is max_load_per_proc we spawn a new one
32916 -        * and add it to the first entry and give it 
32917 +        * and add it to the first entry and give it
32918          * the load
32919 -        * 
32920 +        *
32921          */
32922  
32923         unsigned short min_procs;
32924 @@ -111,44 +112,44 @@
32925  
32926         /*
32927          * kick the process from the list if it was not
32928 -        * used for idle_timeout until min_procs is 
32929 +        * used for idle_timeout until min_procs is
32930          * reached. this helps to get the processlist
32931          * small again we had a small peak load.
32932          *
32933          */
32934 -       
32935 +
32936         unsigned short idle_timeout;
32937 -       
32938 +
32939         /*
32940          * time after a disabled remote connection is tried to be re-enabled
32941 -        * 
32942 -        * 
32943 +        *
32944 +        *
32945          */
32946 -       
32947 +
32948         unsigned short disable_time;
32949  
32950         /*
32951          * same scgi processes get a little bit larger
32952 -        * than wanted. max_requests_per_proc kills a 
32953 +        * than wanted. max_requests_per_proc kills a
32954          * process after a number of handled requests.
32955          *
32956          */
32957         size_t max_requests_per_proc;
32958 -       
32959 +
32960  
32961         /* config */
32962  
32963 -       /* 
32964 -        * host:port 
32965 +       /*
32966 +        * host:port
32967          *
32968 -        * if host is one of the local IP adresses the 
32969 +        * if host is one of the local IP adresses the
32970          * whole connection is local
32971          *
32972          * if tcp/ip should be used host AND port have
32973 -        * to be specified 
32974 -        * 
32975 -        */ 
32976 -       buffer *host; 
32977 +        * to be specified
32978 +        *
32979 +        */
32980 +       buffer *host;
32981         unsigned short port;
32982  
32983         /*
32984 @@ -161,7 +162,7 @@
32985          */
32986         buffer *unixsocket;
32987  
32988 -       /* if socket is local we can start the scgi 
32989 +       /* if socket is local we can start the scgi
32990          * process ourself
32991          *
32992          * bin-path is the path to the binary
32993 @@ -169,19 +170,19 @@
32994          * check min_procs and max_procs for the number
32995          * of process to start-up
32996          */
32997 -       buffer *bin_path; 
32998 -       
32999 -       /* bin-path is set bin-environment is taken to 
33000 +       buffer *bin_path;
33001 +
33002 +       /* bin-path is set bin-environment is taken to
33003          * create the environement before starting the
33004          * FastCGI process
33005 -        * 
33006 +        *
33007          */
33008         array *bin_env;
33009 -       
33010 +
33011         array *bin_env_copy;
33012 -       
33013 +
33014         /*
33015 -        * docroot-translation between URL->phys and the 
33016 +        * docroot-translation between URL->phys and the
33017          * remote host
33018          *
33019          * reasons:
33020 @@ -192,7 +193,7 @@
33021         buffer *docroot;
33022  
33023         /*
33024 -        * check_local tell you if the phys file is stat()ed 
33025 +        * check_local tell you if the phys file is stat()ed
33026          * or not. FastCGI doesn't care if the service is
33027          * remote. If the web-server side doesn't contain
33028          * the scgi-files we should not stat() for them
33029 @@ -202,33 +203,33 @@
33030  
33031         /*
33032          * append PATH_INFO to SCRIPT_FILENAME
33033 -        * 
33034 +        *
33035          * php needs this if cgi.fix_pathinfo is provied
33036 -        * 
33037 +        *
33038          */
33039 -       
33040 +
33041         ssize_t load; /* replace by host->load */
33042  
33043         size_t max_id; /* corresponds most of the time to
33044         num_procs.
33045 -       
33046 +
33047         only if a process is killed max_id waits for the process itself
33048         to die and decrements its afterwards */
33049  } scgi_extension_host;
33050  
33051  /*
33052   * one extension can have multiple hosts assigned
33053 - * one host can spawn additional processes on the same 
33054 + * one host can spawn additional processes on the same
33055   *   socket (if we control it)
33056   *
33057   * ext -> host -> procs
33058   *    1:n     1:n
33059   *
33060 - * if the scgi process is remote that whole goes down 
33061 + * if the scgi process is remote that whole goes down
33062   * to
33063   *
33064   * ext -> host -> procs
33065 - *    1:n     1:1 
33066 + *    1:n     1:1
33067   *
33068   * in case of PHP and FCGI_CHILDREN we have again a procs
33069   * but we don't control it directly.
33070 @@ -239,7 +240,7 @@
33071         buffer *key; /* like .php */
33072  
33073         scgi_extension_host **hosts;
33074 -       
33075 +
33076         size_t used;
33077         size_t size;
33078  } scgi_extension;
33079 @@ -253,14 +254,14 @@
33080  
33081  
33082  typedef struct {
33083 -       scgi_exts *exts; 
33084 -       
33085 +       scgi_exts *exts;
33086 +
33087         int debug;
33088  } plugin_config;
33089  
33090  typedef struct {
33091         char **ptr;
33092 -       
33093 +
33094         size_t size;
33095         size_t used;
33096  } char_array;
33097 @@ -268,52 +269,51 @@
33098  /* generic plugin data, shared between all connections */
33099  typedef struct {
33100         PLUGIN_DATA;
33101 -       
33102 +
33103         buffer *scgi_env;
33104 -       
33105 +
33106         buffer *path;
33107 -       buffer *parse_response;
33108 -       
33109 +
33110 +       http_resp *resp;
33111 +
33112         plugin_config **config_storage;
33113 -       
33114 +
33115         plugin_config conf; /* this is only used as long as no handler_ctx is setup */
33116  } plugin_data;
33117  
33118  /* connection specific data */
33119 -typedef enum { FCGI_STATE_INIT, FCGI_STATE_CONNECT, FCGI_STATE_PREPARE_WRITE, 
33120 -               FCGI_STATE_WRITE, FCGI_STATE_READ 
33121 +typedef enum {
33122 +       SCGI_STATE_INIT,
33123 +       SCGI_STATE_CONNECT,
33124 +       SCGI_STATE_PREPARE_WRITE,
33125 +       SCGI_STATE_WRITE,
33126 +       SCGI_STATE_RESPONSE_HEADER,
33127 +       SCGI_STATE_RESPONSE_CONTENT,
33128 +       SCGI_STATE_ERROR
33129  } scgi_connection_state_t;
33130  
33131  typedef struct {
33132 -       buffer  *response; 
33133 -       size_t   response_len;
33134 -       int      response_type;
33135 -       int      response_padding;
33136 -       
33137         scgi_proc *proc;
33138         scgi_extension_host *host;
33139 -       
33140 +
33141         scgi_connection_state_t state;
33142         time_t   state_timestamp;
33143 -       
33144 +
33145         int      reconnects; /* number of reconnect attempts */
33146 -       
33147 -       read_buffer *rb;
33148 +
33149 +       chunkqueue *rb;
33150         chunkqueue *wb;
33151 -       
33152 -       buffer   *response_header;
33153 -       
33154 +
33155         int       delayed;   /* flag to mark that the connect() is delayed */
33156 -       
33157 +
33158         size_t    request_id;
33159 -       int       fd;        /* fd to the scgi process */
33160 -       int       fde_ndx;   /* index into the fd-event buffer */
33161 +       iosocket  *sock;        /* fd to the scgi process */
33162  
33163         pid_t     pid;
33164         int       got_proc;
33165 -       
33166 +
33167         plugin_config conf;
33168 -       
33169 +
33170         connection *remote_conn;  /* dumb pointer */
33171         plugin_data *plugin_data; /* dumb pointer */
33172  } handler_ctx;
33173 @@ -328,42 +328,30 @@
33174  
33175  static handler_ctx * handler_ctx_init() {
33176         handler_ctx * hctx;
33177 -       
33178 +
33179         hctx = calloc(1, sizeof(*hctx));
33180         assert(hctx);
33181 -       
33182 -       hctx->fde_ndx = -1;
33183 -       
33184 -       hctx->response = buffer_init();
33185 -       hctx->response_header = buffer_init();
33186 -       
33187 +
33188 +       hctx->sock = iosocket_init();;
33189 +
33190         hctx->request_id = 0;
33191 -       hctx->state = FCGI_STATE_INIT;
33192 +       hctx->state = SCGI_STATE_INIT;
33193         hctx->proc = NULL;
33194 -       
33195 -       hctx->response_len = 0;
33196 -       hctx->response_type = 0;
33197 -       hctx->response_padding = 0;
33198 -       hctx->fd = -1;
33199 -       
33200 +
33201         hctx->reconnects = 0;
33202  
33203         hctx->wb = chunkqueue_init();
33204 -       
33205 +       hctx->rb = chunkqueue_init();
33206 +
33207         return hctx;
33208  }
33209  
33210  static void handler_ctx_free(handler_ctx *hctx) {
33211 -       buffer_free(hctx->response);
33212 -       buffer_free(hctx->response_header);
33213 -
33214         chunkqueue_free(hctx->wb);
33215 -       
33216 -       if (hctx->rb) {
33217 -               if (hctx->rb->ptr) free(hctx->rb->ptr);
33218 -               free(hctx->rb);
33219 -       }
33220 -       
33221 +       chunkqueue_free(hctx->rb);
33222 +
33223 +       iosocket_free(hctx->sock);
33224 +
33225         free(hctx);
33226  }
33227  
33228 @@ -372,20 +360,20 @@
33229  
33230         f = calloc(1, sizeof(*f));
33231         f->socket = buffer_init();
33232 -       
33233 +
33234         f->prev = NULL;
33235         f->next = NULL;
33236 -       
33237 +
33238         return f;
33239  }
33240  
33241  void scgi_process_free(scgi_proc *f) {
33242         if (!f) return;
33243 -       
33244 +
33245         scgi_process_free(f->next);
33246 -       
33247 +
33248         buffer_free(f->socket);
33249 -       
33250 +
33251         free(f);
33252  }
33253  
33254 @@ -400,62 +388,62 @@
33255         f->bin_path = buffer_init();
33256         f->bin_env = array_init();
33257         f->bin_env_copy = array_init();
33258 -       
33259 +
33260         return f;
33261  }
33262  
33263  void scgi_host_free(scgi_extension_host *h) {
33264         if (!h) return;
33265 -       
33266 +
33267         buffer_free(h->host);
33268         buffer_free(h->unixsocket);
33269         buffer_free(h->docroot);
33270         buffer_free(h->bin_path);
33271         array_free(h->bin_env);
33272         array_free(h->bin_env_copy);
33273 -       
33274 +
33275         scgi_process_free(h->first);
33276         scgi_process_free(h->unused_procs);
33277 -       
33278 +
33279         free(h);
33280 -       
33281 +
33282  }
33283  
33284  scgi_exts *scgi_extensions_init() {
33285         scgi_exts *f;
33286  
33287         f = calloc(1, sizeof(*f));
33288 -       
33289 +
33290         return f;
33291  }
33292  
33293  void scgi_extensions_free(scgi_exts *f) {
33294         size_t i;
33295 -       
33296 +
33297         if (!f) return;
33298 -       
33299 +
33300         for (i = 0; i < f->used; i++) {
33301                 scgi_extension *fe;
33302                 size_t j;
33303 -               
33304 +
33305                 fe = f->exts[i];
33306 -               
33307 +
33308                 for (j = 0; j < fe->used; j++) {
33309                         scgi_extension_host *h;
33310 -                       
33311 +
33312                         h = fe->hosts[j];
33313 -                       
33314 +
33315                         scgi_host_free(h);
33316                 }
33317 -               
33318 +
33319                 buffer_free(fe->key);
33320                 free(fe->hosts);
33321 -               
33322 +
33323                 free(fe);
33324         }
33325 -       
33326 +
33327         free(f->exts);
33328 -       
33329 +
33330         free(f);
33331  }
33332  
33333 @@ -504,99 +492,103 @@
33334                 assert(fe->hosts);
33335         }
33336  
33337 -       fe->hosts[fe->used++] = fh; 
33338 +       fe->hosts[fe->used++] = fh;
33339  
33340         return 0;
33341 -       
33342 +
33343  }
33344  
33345  INIT_FUNC(mod_scgi_init) {
33346         plugin_data *p;
33347 -       
33348 +
33349         p = calloc(1, sizeof(*p));
33350 -       
33351 +
33352         p->scgi_env = buffer_init();
33353 -       
33354 +
33355         p->path = buffer_init();
33356 -       p->parse_response = buffer_init();
33357 -       
33358 +       p->resp = http_response_init();
33359 +
33360         return p;
33361  }
33362  
33363  
33364  FREE_FUNC(mod_scgi_free) {
33365         plugin_data *p = p_d;
33366 -       
33367 +
33368         UNUSED(srv);
33369  
33370         buffer_free(p->scgi_env);
33371         buffer_free(p->path);
33372 -       buffer_free(p->parse_response);
33373 -       
33374 +       http_response_free(p->resp);
33375 +
33376         if (p->config_storage) {
33377                 size_t i, j, n;
33378                 for (i = 0; i < srv->config_context->used; i++) {
33379                         plugin_config *s = p->config_storage[i];
33380                         scgi_exts *exts;
33381 -                       
33382 +
33383                         if (!s) continue;
33384 -                       
33385 +
33386                         exts = s->exts;
33387  
33388                         for (j = 0; j < exts->used; j++) {
33389                                 scgi_extension *ex;
33390 -                               
33391 +
33392                                 ex = exts->exts[j];
33393 -                               
33394 +
33395                                 for (n = 0; n < ex->used; n++) {
33396                                         scgi_proc *proc;
33397                                         scgi_extension_host *host;
33398 -                                       
33399 +
33400                                         host = ex->hosts[n];
33401 -                                       
33402 +
33403                                         for (proc = host->first; proc; proc = proc->next) {
33404 +#ifndef _WIN32
33405                                                 if (proc->pid != 0) kill(proc->pid, SIGTERM);
33406 -                                               
33407 -                                               if (proc->is_local && 
33408 +#endif
33409 +
33410 +                                               if (proc->is_local &&
33411                                                     !buffer_is_empty(proc->socket)) {
33412                                                         unlink(proc->socket->ptr);
33413                                                 }
33414                                         }
33415 -                                       
33416 +
33417                                         for (proc = host->unused_procs; proc; proc = proc->next) {
33418 +#ifndef _WIN32
33419                                                 if (proc->pid != 0) kill(proc->pid, SIGTERM);
33420 -                                               
33421 -                                               if (proc->is_local && 
33422 +#endif
33423 +
33424 +                                               if (proc->is_local &&
33425                                                     !buffer_is_empty(proc->socket)) {
33426                                                         unlink(proc->socket->ptr);
33427                                                 }
33428                                         }
33429                                 }
33430                         }
33431 -                       
33432 +
33433                         scgi_extensions_free(s->exts);
33434 -                       
33435 +
33436                         free(s);
33437                 }
33438                 free(p->config_storage);
33439         }
33440 -       
33441 +
33442         free(p);
33443 -       
33444 +
33445         return HANDLER_GO_ON;
33446  }
33447  
33448  static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
33449         char *dst;
33450 -       
33451 +
33452         if (!key || !val) return -1;
33453 -       
33454 +
33455         dst = malloc(key_len + val_len + 3);
33456         memcpy(dst, key, key_len);
33457         dst[key_len] = '=';
33458         /* add the \0 from the value */
33459         memcpy(dst + key_len + 1, val, val_len + 1);
33460 -       
33461 +
33462         if (env->size == 0) {
33463                 env->size = 16;
33464                 env->ptr = malloc(env->size * sizeof(*env->ptr));
33465 @@ -604,13 +596,13 @@
33466                 env->size += 16;
33467                 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
33468         }
33469 -       
33470 +
33471         env->ptr[env->used++] = dst;
33472 -       
33473 +
33474         return 0;
33475  }
33476  
33477 -static int scgi_spawn_connection(server *srv, 
33478 +static int scgi_spawn_connection(server *srv,
33479                                  plugin_data *p,
33480                                  scgi_extension_host *host,
33481                                  scgi_proc *proc) {
33482 @@ -622,31 +614,27 @@
33483  #endif
33484         struct sockaddr_in scgi_addr_in;
33485         struct sockaddr *scgi_addr;
33486 -       
33487 +
33488         socklen_t servlen;
33489 -       
33490 +
33491  #ifndef HAVE_FORK
33492         return -1;
33493  #endif
33494 -       
33495 +
33496         if (p->conf.debug) {
33497                 log_error_write(srv, __FILE__, __LINE__, "sdb",
33498                                 "new proc, socket:", proc->port, proc->socket);
33499         }
33500 -               
33501 +
33502         if (!buffer_is_empty(proc->socket)) {
33503                 memset(&scgi_addr, 0, sizeof(scgi_addr));
33504 -               
33505 +
33506  #ifdef HAVE_SYS_UN_H
33507                 scgi_addr_un.sun_family = AF_UNIX;
33508                 strcpy(scgi_addr_un.sun_path, proc->socket->ptr);
33509 -               
33510 -#ifdef SUN_LEN
33511 +
33512                 servlen = SUN_LEN(&scgi_addr_un);
33513 -#else
33514 -               /* stevens says: */
33515 -               servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family);
33516 -#endif
33517 +
33518                 socket_type = AF_UNIX;
33519                 scgi_addr = (struct sockaddr *) &scgi_addr_un;
33520  #else
33521 @@ -656,115 +644,115 @@
33522  #endif
33523         } else {
33524                 scgi_addr_in.sin_family = AF_INET;
33525 -               
33526 +
33527                 if (buffer_is_empty(host->host)) {
33528                         scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
33529                 } else {
33530                         struct hostent *he;
33531 -                       
33532 +
33533                         /* set a usefull default */
33534                         scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
33535 -                       
33536 -                       
33537 +
33538 +
33539                         if (NULL == (he = gethostbyname(host->host->ptr))) {
33540 -                               log_error_write(srv, __FILE__, __LINE__, 
33541 -                                               "sdb", "gethostbyname failed: ", 
33542 +                               log_error_write(srv, __FILE__, __LINE__,
33543 +                                               "sdb", "gethostbyname failed: ",
33544                                                 h_errno, host->host);
33545                                 return -1;
33546                         }
33547 -                       
33548 +
33549                         if (he->h_addrtype != AF_INET) {
33550                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
33551                                 return -1;
33552                         }
33553 -                       
33554 +
33555                         if (he->h_length != sizeof(struct in_addr)) {
33556                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
33557                                 return -1;
33558                         }
33559 -                       
33560 +
33561                         memcpy(&(scgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
33562 -                       
33563 +
33564                 }
33565                 scgi_addr_in.sin_port = htons(proc->port);
33566                 servlen = sizeof(scgi_addr_in);
33567 -               
33568 +
33569                 socket_type = AF_INET;
33570                 scgi_addr = (struct sockaddr *) &scgi_addr_in;
33571         }
33572 -       
33573 +
33574         if (-1 == (scgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
33575 -               log_error_write(srv, __FILE__, __LINE__, "ss", 
33576 +               log_error_write(srv, __FILE__, __LINE__, "ss",
33577                                 "failed:", strerror(errno));
33578                 return -1;
33579         }
33580 -       
33581 +
33582         if (-1 == connect(scgi_fd, scgi_addr, servlen)) {
33583                 /* server is not up, spawn in  */
33584                 pid_t child;
33585                 int val;
33586 -               
33587 +
33588                 if (!buffer_is_empty(proc->socket)) {
33589                         unlink(proc->socket->ptr);
33590                 }
33591 -               
33592 +
33593                 close(scgi_fd);
33594 -               
33595 +
33596                 /* reopen socket */
33597                 if (-1 == (scgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
33598 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
33599 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
33600                                 "socket failed:", strerror(errno));
33601                         return -1;
33602                 }
33603 -               
33604 +
33605                 val = 1;
33606                 if (setsockopt(scgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
33607 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
33608 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
33609                                         "socketsockopt failed:", strerror(errno));
33610                         return -1;
33611                 }
33612 -               
33613 +
33614                 /* create socket */
33615                 if (-1 == bind(scgi_fd, scgi_addr, servlen)) {
33616 -                       log_error_write(srv, __FILE__, __LINE__, "sbds", 
33617 -                               "bind failed for:", 
33618 -                               proc->socket, 
33619 -                               proc->port, 
33620 +                       log_error_write(srv, __FILE__, __LINE__, "sbds",
33621 +                               "bind failed for:",
33622 +                               proc->socket,
33623 +                               proc->port,
33624                                 strerror(errno));
33625                         return -1;
33626                 }
33627 -               
33628 +
33629                 if (-1 == listen(scgi_fd, 1024)) {
33630 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
33631 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
33632                                 "listen failed:", strerror(errno));
33633                         return -1;
33634                 }
33635 -               
33636 -#ifdef HAVE_FORK       
33637 +
33638 +#ifdef HAVE_FORK
33639                 switch ((child = fork())) {
33640                 case 0: {
33641                         buffer *b;
33642                         size_t i = 0;
33643                         int fd = 0;
33644                         char_array env;
33645 -                       
33646 -                       
33647 +
33648 +
33649                         /* create environment */
33650                         env.ptr = NULL;
33651                         env.size = 0;
33652                         env.used = 0;
33653 -                       
33654 +
33655                         /* we don't need the client socket */
33656                         for (fd = 3; fd < 256; fd++) {
33657                                 if (fd != 2 && fd != scgi_fd) close(fd);
33658                         }
33659 -                       
33660 +
33661                         /* build clean environment */
33662                         if (host->bin_env_copy->used) {
33663                                 for (i = 0; i < host->bin_env_copy->used; i++) {
33664                                         data_string *ds = (data_string *)host->bin_env_copy->data[i];
33665                                         char *ge;
33666 -                                       
33667 +
33668                                         if (NULL != (ge = getenv(ds->value->ptr))) {
33669                                                 env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge));
33670                                         }
33671 @@ -772,44 +760,44 @@
33672                         } else {
33673                                 for (i = 0; environ[i]; i++) {
33674                                         char *eq;
33675 -                                       
33676 +
33677                                         if (NULL != (eq = strchr(environ[i], '='))) {
33678                                                 env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));
33679                                         }
33680                                 }
33681                         }
33682 -                       
33683 +
33684                         /* create environment */
33685                         for (i = 0; i < host->bin_env->used; i++) {
33686                                 data_string *ds = (data_string *)host->bin_env->data[i];
33687 -                               
33688 +
33689                                 env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
33690                         }
33691 -                       
33692 +
33693                         for (i = 0; i < env.used; i++) {
33694                                 /* search for PHP_FCGI_CHILDREN */
33695                                 if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break;
33696                         }
33697 -                       
33698 +
33699                         /* not found, add a default */
33700                         if (i == env.used) {
33701                                 env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1"));
33702                         }
33703 -                       
33704 +
33705                         env.ptr[env.used] = NULL;
33706 -                       
33707 +
33708                         b = buffer_init();
33709                         buffer_copy_string(b, "exec ");
33710                         buffer_append_string_buffer(b, host->bin_path);
33711 -                       
33712 +
33713                         /* exec the cgi */
33714                         execle("/bin/sh", "sh", "-c", b->ptr, NULL, env.ptr);
33715 -                       
33716 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
33717 +
33718 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
33719                                         "execl failed for:", host->bin_path, strerror(errno));
33720 -                       
33721 +
33722                         exit(errno);
33723 -                       
33724 +
33725                         break;
33726                 }
33727                 case -1:
33728 @@ -817,32 +805,32 @@
33729                         break;
33730                 default:
33731                         /* father */
33732 -                       
33733 +
33734                         /* wait */
33735                         select(0, NULL, NULL, NULL, &tv);
33736 -                       
33737 +
33738                         switch (waitpid(child, &status, WNOHANG)) {
33739                         case 0:
33740                                 /* child still running after timeout, good */
33741                                 break;
33742                         case -1:
33743                                 /* no PID found ? should never happen */
33744 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
33745 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
33746                                                 "pid not found:", strerror(errno));
33747                                 return -1;
33748                         default:
33749                                 /* the child should not terminate at all */
33750                                 if (WIFEXITED(status)) {
33751 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
33752 -                                                       "child exited (is this a SCGI binary ?):", 
33753 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
33754 +                                                       "child exited (is this a SCGI binary ?):",
33755                                                         WEXITSTATUS(status));
33756                                 } else if (WIFSIGNALED(status)) {
33757 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
33758 -                                                       "child signaled:", 
33759 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
33760 +                                                       "child signaled:",
33761                                                         WTERMSIG(status));
33762                                 } else {
33763 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
33764 -                                                       "child died somehow:", 
33765 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
33766 +                                                       "child died somehow:",
33767                                                         status);
33768                                 }
33769                                 return -1;
33770 @@ -852,26 +840,26 @@
33771                         proc->pid = child;
33772                         proc->last_used = srv->cur_ts;
33773                         proc->is_local = 1;
33774 -                                               
33775 +
33776                         break;
33777                 }
33778  #endif
33779         } else {
33780                 proc->is_local = 0;
33781                 proc->pid = 0;
33782 -               
33783 +
33784                 if (p->conf.debug) {
33785                         log_error_write(srv, __FILE__, __LINE__, "sb",
33786                                         "(debug) socket is already used, won't spawn:",
33787                                         proc->socket);
33788                 }
33789         }
33790 -       
33791 +
33792         proc->state = PROC_STATE_RUNNING;
33793         host->active_procs++;
33794 -       
33795 +
33796         close(scgi_fd);
33797 -       
33798 +
33799         return 0;
33800  }
33801  
33802 @@ -880,89 +868,89 @@
33803         plugin_data *p = p_d;
33804         data_unset *du;
33805         size_t i = 0;
33806 -       
33807 -       config_values_t cv[] = { 
33808 +
33809 +       config_values_t cv[] = {
33810                 { "scgi.server",              NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
33811                 { "scgi.debug",               NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
33812                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
33813         };
33814 -       
33815 +
33816         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
33817 -       
33818 +
33819         for (i = 0; i < srv->config_context->used; i++) {
33820                 plugin_config *s;
33821                 array *ca;
33822 -               
33823 +
33824                 s = malloc(sizeof(plugin_config));
33825                 s->exts          = scgi_extensions_init();
33826                 s->debug         = 0;
33827 -               
33828 +
33829                 cv[0].destination = s->exts;
33830                 cv[1].destination = &(s->debug);
33831 -               
33832 +
33833                 p->config_storage[i] = s;
33834                 ca = ((data_config *)srv->config_context->data[i])->value;
33835 -       
33836 +
33837                 if (0 != config_insert_values_global(srv, ca, cv)) {
33838                         return HANDLER_ERROR;
33839                 }
33840 -               
33841 -               /* 
33842 +
33843 +               /*
33844                  * <key> = ( ... )
33845                  */
33846 -               
33847 +
33848                 if (NULL != (du = array_get_element(ca, "scgi.server"))) {
33849                         size_t j;
33850                         data_array *da = (data_array *)du;
33851 -                       
33852 +
33853                         if (du->type != TYPE_ARRAY) {
33854 -                               log_error_write(srv, __FILE__, __LINE__, "sss", 
33855 +                               log_error_write(srv, __FILE__, __LINE__, "sss",
33856                                                 "unexpected type for key: ", "scgi.server", "array of strings");
33857 -                               
33858 +
33859                                 return HANDLER_ERROR;
33860                         }
33861 -                       
33862 -                       
33863 -                       /* 
33864 -                        * scgi.server = ( "<ext>" => ( ... ), 
33865 +
33866 +
33867 +                       /*
33868 +                        * scgi.server = ( "<ext>" => ( ... ),
33869                          *                    "<ext>" => ( ... ) )
33870                          */
33871 -                       
33872 +
33873                         for (j = 0; j < da->value->used; j++) {
33874                                 size_t n;
33875                                 data_array *da_ext = (data_array *)da->value->data[j];
33876 -                               
33877 +
33878                                 if (da->value->data[j]->type != TYPE_ARRAY) {
33879 -                                       log_error_write(srv, __FILE__, __LINE__, "sssbs", 
33880 -                                                       "unexpected type for key: ", "scgi.server", 
33881 +                                       log_error_write(srv, __FILE__, __LINE__, "sssbs",
33882 +                                                       "unexpected type for key: ", "scgi.server",
33883                                                         "[", da->value->data[j]->key, "](string)");
33884 -                                       
33885 +
33886                                         return HANDLER_ERROR;
33887                                 }
33888 -                               
33889 -                               /* 
33890 -                                * da_ext->key == name of the extension 
33891 +
33892 +                               /*
33893 +                                * da_ext->key == name of the extension
33894                                  */
33895 -                               
33896 -                               /* 
33897 -                                * scgi.server = ( "<ext>" => 
33898 -                                *                     ( "<host>" => ( ... ), 
33899 +
33900 +                               /*
33901 +                                * scgi.server = ( "<ext>" =>
33902 +                                *                     ( "<host>" => ( ... ),
33903                                  *                       "<host>" => ( ... )
33904 -                                *                     ), 
33905 +                                *                     ),
33906                                  *                    "<ext>" => ... )
33907                                  */
33908 -                                       
33909 +
33910                                 for (n = 0; n < da_ext->value->used; n++) {
33911                                         data_array *da_host = (data_array *)da_ext->value->data[n];
33912 -                                       
33913 +
33914                                         scgi_extension_host *df;
33915 -                                       
33916 -                                       config_values_t fcv[] = { 
33917 +
33918 +                                       config_values_t fcv[] = {
33919                                                 { "host",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
33920                                                 { "docroot",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
33921                                                 { "socket",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
33922                                                 { "bin-path",          NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
33923 -                                               
33924 +
33925                                                 { "check-local",       NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 4 */
33926                                                 { "port",              NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 5 */
33927                                                 { "min-procs-not-working",         NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 7 this is broken for now */
33928 @@ -970,37 +958,37 @@
33929                                                 { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 8 */
33930                                                 { "idle-timeout",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 9 */
33931                                                 { "disable-time",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 10 */
33932 -                                               
33933 +
33934                                                 { "bin-environment",   NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },        /* 11 */
33935                                                 { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },     /* 12 */
33936 -                                               
33937 -                                               
33938 +
33939 +
33940                                                 { NULL,                NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
33941                                         };
33942 -                                       
33943 +
33944                                         if (da_host->type != TYPE_ARRAY) {
33945 -                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS", 
33946 -                                                               "unexpected type for key:", 
33947 -                                                               "scgi.server", 
33948 +                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS",
33949 +                                                               "unexpected type for key:",
33950 +                                                               "scgi.server",
33951                                                                 "[", da_host->key, "](string)");
33952 -                                               
33953 +
33954                                                 return HANDLER_ERROR;
33955                                         }
33956 -                                       
33957 +
33958                                         df = scgi_host_init();
33959 -                                       
33960 +
33961                                         df->check_local  = 1;
33962                                         df->min_procs    = 4;
33963                                         df->max_procs    = 4;
33964                                         df->max_load_per_proc = 1;
33965                                         df->idle_timeout = 60;
33966                                         df->disable_time = 60;
33967 -                                       
33968 +
33969                                         fcv[0].destination = df->host;
33970                                         fcv[1].destination = df->docroot;
33971                                         fcv[2].destination = df->unixsocket;
33972                                         fcv[3].destination = df->bin_path;
33973 -                                       
33974 +
33975                                         fcv[4].destination = &(df->check_local);
33976                                         fcv[5].destination = &(df->port);
33977                                         fcv[6].destination = &(df->min_procs);
33978 @@ -1008,47 +996,47 @@
33979                                         fcv[8].destination = &(df->max_load_per_proc);
33980                                         fcv[9].destination = &(df->idle_timeout);
33981                                         fcv[10].destination = &(df->disable_time);
33982 -                                       
33983 +
33984                                         fcv[11].destination = df->bin_env;
33985                                         fcv[12].destination = df->bin_env_copy;
33986 -                                       
33987 -                                       
33988 +
33989 +
33990                                         if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
33991                                                 return HANDLER_ERROR;
33992                                         }
33993 -                                                       
33994 -                                       if ((!buffer_is_empty(df->host) || df->port) && 
33995 +
33996 +                                       if ((!buffer_is_empty(df->host) || df->port) &&
33997                                             !buffer_is_empty(df->unixsocket)) {
33998 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
33999 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
34000                                                                 "either host+port or socket");
34001 -                                               
34002 +
34003                                                 return HANDLER_ERROR;
34004                                         }
34005 -                                       
34006 +
34007                                         if (!buffer_is_empty(df->unixsocket)) {
34008                                                 /* unix domain socket */
34009 -                                               
34010 +
34011                                                 if (df->unixsocket->used > UNIX_PATH_MAX - 2) {
34012 -                                                       log_error_write(srv, __FILE__, __LINE__, "s", 
34013 +                                                       log_error_write(srv, __FILE__, __LINE__, "s",
34014                                                                         "path of the unixdomain socket is too large");
34015                                                         return HANDLER_ERROR;
34016                                                 }
34017                                         } else {
34018                                                 /* tcp/ip */
34019 -                                               
34020 -                                               if (buffer_is_empty(df->host) && 
34021 +
34022 +                                               if (buffer_is_empty(df->host) &&
34023                                                     buffer_is_empty(df->bin_path)) {
34024 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbbbs", 
34025 -                                                                       "missing key (string):", 
34026 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbbbs",
34027 +                                                                       "missing key (string):",
34028                                                                         da->key,
34029                                                                         da_ext->key,
34030                                                                         da_host->key,
34031                                                                         "host");
34032 -                                                       
34033 +
34034                                                         return HANDLER_ERROR;
34035                                                 } else if (df->port == 0) {
34036 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbbbs", 
34037 -                                                                       "missing key (short):", 
34038 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbbbs",
34039 +                                                                       "missing key (short):",
34040                                                                         da->key,
34041                                                                         da_ext->key,
34042                                                                         da_host->key,
34043 @@ -1056,14 +1044,14 @@
34044                                                         return HANDLER_ERROR;
34045                                                 }
34046                                         }
34047 -                                               
34048 -                                       if (!buffer_is_empty(df->bin_path)) { 
34049 +
34050 +                                       if (!buffer_is_empty(df->bin_path)) {
34051                                                 /* a local socket + self spawning */
34052                                                 size_t pno;
34053 -                                               
34054 +
34055                                                 if (df->min_procs > df->max_procs) df->max_procs = df->min_procs;
34056                                                 if (df->max_load_per_proc < 1) df->max_load_per_proc = 0;
34057 -                                               
34058 +
34059                                                 if (s->debug) {
34060                                                         log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
34061                                                                         "--- scgi spawning local",
34062 @@ -1073,7 +1061,7 @@
34063                                                                         "\n\tmin-procs:", df->min_procs,
34064                                                                         "\n\tmax-procs:", df->max_procs);
34065                                                 }
34066 -                                               
34067 +
34068                                                 for (pno = 0; pno < df->min_procs; pno++) {
34069                                                         scgi_proc *proc;
34070  
34071 @@ -1088,7 +1076,7 @@
34072                                                                 buffer_append_string(proc->socket, "-");
34073                                                                 buffer_append_long(proc->socket, pno);
34074                                                         }
34075 -                                                       
34076 +
34077                                                         if (s->debug) {
34078                                                                 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
34079                                                                                 "--- scgi spawning",
34080 @@ -1096,53 +1084,53 @@
34081                                                                                 "\n\tsocket", df->unixsocket,
34082                                                                                 "\n\tcurrent:", pno, "/", df->min_procs);
34083                                                         }
34084 -                                                       
34085 +
34086                                                         if (scgi_spawn_connection(srv, p, df, proc)) {
34087                                                                 log_error_write(srv, __FILE__, __LINE__, "s",
34088                                                                                 "[ERROR]: spawning fcgi failed.");
34089                                                                 return HANDLER_ERROR;
34090                                                         }
34091 -                                                       
34092 +
34093                                                         proc->next = df->first;
34094                                                         if (df->first)  df->first->prev = proc;
34095 -                                                       
34096 +
34097                                                         df->first = proc;
34098                                                 }
34099                                         } else {
34100                                                 scgi_proc *fp;
34101 -                                               
34102 +
34103                                                 fp = scgi_process_init();
34104                                                 fp->id = df->num_procs++;
34105                                                 df->max_id++;
34106                                                 df->active_procs++;
34107                                                 fp->state = PROC_STATE_RUNNING;
34108 -                                               
34109 +
34110                                                 if (buffer_is_empty(df->unixsocket)) {
34111                                                         fp->port = df->port;
34112                                                 } else {
34113                                                         buffer_copy_string_buffer(fp->socket, df->unixsocket);
34114                                                 }
34115 -                                               
34116 +
34117                                                 df->first = fp;
34118 -                                               
34119 +
34120                                                 df->min_procs = 1;
34121                                                 df->max_procs = 1;
34122                                         }
34123 -                                       
34124 +
34125                                         /* if extension already exists, take it */
34126                                         scgi_extension_insert(s->exts, da_ext->key, df);
34127                                 }
34128                         }
34129                 }
34130         }
34131 -       
34132 +
34133         return HANDLER_GO_ON;
34134  }
34135  
34136  static int scgi_set_state(server *srv, handler_ctx *hctx, scgi_connection_state_t state) {
34137         hctx->state = state;
34138         hctx->state_timestamp = srv->cur_ts;
34139 -       
34140 +
34141         return 0;
34142  }
34143  
34144 @@ -1150,35 +1138,35 @@
34145  void scgi_connection_cleanup(server *srv, handler_ctx *hctx) {
34146         plugin_data *p;
34147         connection  *con;
34148 -       
34149 +
34150         if (NULL == hctx) return;
34151 -       
34152 +
34153         p    = hctx->plugin_data;
34154         con  = hctx->remote_conn;
34155 -       
34156 +
34157         if (con->mode != p->id) {
34158 -               WP();
34159                 return;
34160         }
34161 -       
34162 -       if (hctx->fd != -1) {
34163 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
34164 -               fdevent_unregister(srv->ev, hctx->fd);
34165 -               close(hctx->fd);
34166 +
34167 +       if (hctx->sock->fd != -1) {
34168 +               fdevent_event_del(srv->ev, hctx->sock);
34169 +               fdevent_unregister(srv->ev, hctx->sock);
34170 +               closesocket(hctx->sock->fd);
34171 +               hctx->sock->fd = -1;
34172                 srv->cur_fds--;
34173         }
34174 -       
34175 +
34176         if (hctx->host && hctx->proc) {
34177                 hctx->host->load--;
34178 -               
34179 +
34180                 if (hctx->got_proc) {
34181                         /* after the connect the process gets a load */
34182                         hctx->proc->load--;
34183 -                       
34184 +
34185                         if (p->conf.debug) {
34186                                 log_error_write(srv, __FILE__, __LINE__, "sddb",
34187 -                                               "release proc:", 
34188 -                                               hctx->fd,
34189 +                                               "release proc:",
34190 +                                               hctx->sock->fd,
34191                                                 hctx->proc->pid, hctx->proc->socket);
34192                         }
34193                 }
34194 @@ -1186,87 +1174,87 @@
34195                 scgi_proclist_sort_down(srv, hctx->host, hctx->proc);
34196         }
34197  
34198 -       
34199 +
34200         handler_ctx_free(hctx);
34201 -       con->plugin_ctx[p->id] = NULL;  
34202 +       con->plugin_ctx[p->id] = NULL;
34203  }
34204  
34205  static int scgi_reconnect(server *srv, handler_ctx *hctx) {
34206         plugin_data *p    = hctx->plugin_data;
34207 -       
34208 -       /* child died 
34209 -        * 
34210 -        * 1. 
34211 -        * 
34212 +
34213 +       /* child died
34214 +        *
34215 +        * 1.
34216 +        *
34217          * connect was ok, connection was accepted
34218          * but the php accept loop checks after the accept if it should die or not.
34219 -        * 
34220 -        * if yes we can only detect it at a write() 
34221 -        * 
34222 +        *
34223 +        * if yes we can only detect it at a write()
34224 +        *
34225          * next step is resetting this attemp and setup a connection again
34226 -        * 
34227 +        *
34228          * if we have more then 5 reconnects for the same request, die
34229 -        * 
34230 -        * 2. 
34231 -        * 
34232 +        *
34233 +        * 2.
34234 +        *
34235          * we have a connection but the child died by some other reason
34236 -        * 
34237 +        *
34238          */
34239 -       
34240 -       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
34241 -       fdevent_unregister(srv->ev, hctx->fd);
34242 -       close(hctx->fd);
34243 +
34244 +       fdevent_event_del(srv->ev, hctx->sock);
34245 +       fdevent_unregister(srv->ev, hctx->sock);
34246 +       closesocket(hctx->sock->fd);
34247         srv->cur_fds--;
34248 -       
34249 -       scgi_set_state(srv, hctx, FCGI_STATE_INIT);
34250 -       
34251 +
34252 +       scgi_set_state(srv, hctx, SCGI_STATE_INIT);
34253 +
34254         hctx->request_id = 0;
34255         hctx->reconnects++;
34256 -       
34257 +
34258         if (p->conf.debug) {
34259                 log_error_write(srv, __FILE__, __LINE__, "sddb",
34260 -                               "release proc:", 
34261 -                               hctx->fd,
34262 +                               "release proc:",
34263 +                               hctx->sock->fd,
34264                                 hctx->proc->pid, hctx->proc->socket);
34265         }
34266 -       
34267 +
34268         hctx->proc->load--;
34269         scgi_proclist_sort_down(srv, hctx->host, hctx->proc);
34270 -       
34271 +
34272         return 0;
34273  }
34274  
34275  
34276  static handler_t scgi_connection_reset(server *srv, connection *con, void *p_d) {
34277         plugin_data *p = p_d;
34278 -       
34279 +
34280         scgi_connection_cleanup(srv, con->plugin_ctx[p->id]);
34281 -       
34282 +
34283         return HANDLER_GO_ON;
34284  }
34285  
34286  
34287  static int scgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
34288         size_t len;
34289 -       
34290 +
34291         if (!key || !val) return -1;
34292 -       
34293 +
34294         len = key_len + val_len + 2;
34295 -       
34296 +
34297         buffer_prepare_append(env, len);
34298  
34299 -       /* include the NUL */   
34300 +       /* include the NUL */
34301         memcpy(env->ptr + env->used, key, key_len + 1);
34302         env->used += key_len + 1;
34303         memcpy(env->ptr + env->used, val, val_len + 1);
34304         env->used += val_len + 1;
34305 -       
34306 +
34307         return 0;
34308  }
34309  
34310  
34311  /**
34312 - * 
34313 + *
34314   * returns
34315   *   -1 error
34316   *    0 connected
34317 @@ -1280,24 +1268,21 @@
34318         struct sockaddr_un scgi_addr_un;
34319  #endif
34320         socklen_t servlen;
34321 -       
34322 +
34323         scgi_extension_host *host = hctx->host;
34324         scgi_proc *proc   = hctx->proc;
34325 -       int scgi_fd       = hctx->fd;
34326 -       
34327 +       int scgi_fd       = hctx->sock->fd;
34328 +
34329         memset(&scgi_addr, 0, sizeof(scgi_addr));
34330 -       
34331 +
34332         if (!buffer_is_empty(proc->socket)) {
34333  #ifdef HAVE_SYS_UN_H
34334                 /* use the unix domain socket */
34335                 scgi_addr_un.sun_family = AF_UNIX;
34336                 strcpy(scgi_addr_un.sun_path, proc->socket->ptr);
34337 -#ifdef SUN_LEN
34338 +               
34339                 servlen = SUN_LEN(&scgi_addr_un);
34340 -#else
34341 -               /* stevens says: */
34342 -               servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family);
34343 -#endif
34344 +
34345                 scgi_addr = (struct sockaddr *) &scgi_addr_un;
34346  #else
34347                 return -1;
34348 @@ -1305,105 +1290,105 @@
34349         } else {
34350                 scgi_addr_in.sin_family = AF_INET;
34351                 if (0 == inet_aton(host->host->ptr, &(scgi_addr_in.sin_addr))) {
34352 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
34353 -                                       "converting IP-adress failed for", host->host, 
34354 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
34355 +                                       "converting IP-adress failed for", host->host,
34356                                         "\nBe sure to specify an IP address here");
34357 -                       
34358 +
34359                         return -1;
34360                 }
34361                 scgi_addr_in.sin_port = htons(proc->port);
34362                 servlen = sizeof(scgi_addr_in);
34363 -               
34364 +
34365                 scgi_addr = (struct sockaddr *) &scgi_addr_in;
34366         }
34367 -       
34368 +
34369         if (-1 == connect(scgi_fd, scgi_addr, servlen)) {
34370 -               if (errno == EINPROGRESS || 
34371 +               if (errno == EINPROGRESS ||
34372                     errno == EALREADY ||
34373                     errno == EINTR) {
34374                         if (hctx->conf.debug) {
34375 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
34376 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
34377                                                 "connect delayed, will continue later:", scgi_fd);
34378                         }
34379 -                       
34380 +
34381                         return 1;
34382                 } else {
34383 -                       log_error_write(srv, __FILE__, __LINE__, "sdsddb", 
34384 -                                       "connect failed:", scgi_fd, 
34385 +                       log_error_write(srv, __FILE__, __LINE__, "sdsddb",
34386 +                                       "connect failed:", scgi_fd,
34387                                         strerror(errno), errno,
34388                                         proc->port, proc->socket);
34389  
34390                         if (errno == EAGAIN) {
34391                                 /* this is Linux only */
34392 -                               
34393 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
34394 +
34395 +                               log_error_write(srv, __FILE__, __LINE__, "s",
34396                                                 "If this happend on Linux: You have been run out of local ports. "
34397                                                 "Check the manual, section Performance how to handle this.");
34398 -                       } 
34399 -                       
34400 +                       }
34401 +
34402                         return -1;
34403                 }
34404         }
34405         if (hctx->conf.debug > 1) {
34406 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
34407 +               log_error_write(srv, __FILE__, __LINE__, "sd",
34408                                 "connect succeeded: ", scgi_fd);
34409         }
34410  
34411  
34412 -       
34413 +
34414         return 0;
34415  }
34416  
34417  static int scgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
34418         size_t i;
34419 -       
34420 +
34421         for (i = 0; i < con->request.headers->used; i++) {
34422                 data_string *ds;
34423 -               
34424 +
34425                 ds = (data_string *)con->request.headers->data[i];
34426 -               
34427 +
34428                 if (ds->value->used && ds->key->used) {
34429                         size_t j;
34430                         buffer_reset(srv->tmp_buf);
34431 -                       
34432 +
34433                         if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
34434                                 BUFFER_COPY_STRING_CONST(srv->tmp_buf, "HTTP_");
34435                                 srv->tmp_buf->used--;
34436                         }
34437 -                       
34438 +
34439                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
34440                         for (j = 0; j < ds->key->used - 1; j++) {
34441 -                               srv->tmp_buf->ptr[srv->tmp_buf->used++] = 
34442 -                                       light_isalpha(ds->key->ptr[j]) ? 
34443 +                               srv->tmp_buf->ptr[srv->tmp_buf->used++] =
34444 +                                       light_isalpha(ds->key->ptr[j]) ?
34445                                         ds->key->ptr[j] & ~32 : '_';
34446                         }
34447                         srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
34448 -                       
34449 +
34450                         scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
34451                 }
34452         }
34453 -       
34454 +
34455         for (i = 0; i < con->environment->used; i++) {
34456                 data_string *ds;
34457 -               
34458 +
34459                 ds = (data_string *)con->environment->data[i];
34460 -               
34461 +
34462                 if (ds->value->used && ds->key->used) {
34463                         size_t j;
34464                         buffer_reset(srv->tmp_buf);
34465 -                       
34466 +
34467                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
34468                         for (j = 0; j < ds->key->used - 1; j++) {
34469 -                               srv->tmp_buf->ptr[srv->tmp_buf->used++] = 
34470 -                                       isalpha((unsigned char)ds->key->ptr[j]) ? 
34471 +                               srv->tmp_buf->ptr[srv->tmp_buf->used++] =
34472 +                                       isalpha((unsigned char)ds->key->ptr[j]) ?
34473                                         toupper((unsigned char)ds->key->ptr[j]) : '_';
34474                         }
34475                         srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
34476 -                       
34477 +
34478                         scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
34479                 }
34480         }
34481 -       
34482 +
34483         return 0;
34484  }
34485  
34486 @@ -1415,20 +1400,20 @@
34487         char b2[INET6_ADDRSTRLEN + 1];
34488  #endif
34489         buffer *b;
34490 -       
34491 +
34492         plugin_data *p    = hctx->plugin_data;
34493         scgi_extension_host *host= hctx->host;
34494  
34495         connection *con   = hctx->remote_conn;
34496         server_socket *srv_sock = con->srv_socket;
34497 -       
34498 +
34499         sock_addr our_addr;
34500         socklen_t our_addr_len;
34501 -       
34502 +
34503         buffer_prepare_copy(p->scgi_env, 1024);
34504  
34505         /* CGI-SPEC 6.1.2, FastCGI spec 6.3 and SCGI spec */
34506 -               
34507 +
34508         /* request.content_length < SSIZE_MAX, see request.c */
34509         ltostr(buf, con->request.content_length);
34510         scgi_env_add(p->scgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
34511 @@ -1436,13 +1421,13 @@
34512  
34513  
34514         scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
34515 -       
34516 +
34517         if (con->server_name->used) {
34518                 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
34519         } else {
34520  #ifdef HAVE_IPV6
34521 -               s = inet_ntop(srv_sock->addr.plain.sa_family, 
34522 -                             srv_sock->addr.plain.sa_family == AF_INET6 ? 
34523 +               s = inet_ntop(srv_sock->addr.plain.sa_family,
34524 +                             srv_sock->addr.plain.sa_family == AF_INET6 ?
34525                               (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
34526                               (const void *) &(srv_sock->addr.ipv4.sin_addr),
34527                               b2, sizeof(b2)-1);
34528 @@ -1451,47 +1436,47 @@
34529  #endif
34530                 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
34531         }
34532 -       
34533 +
34534         scgi_env_add(p->scgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
34535 -       
34536 -       ltostr(buf, 
34537 +
34538 +       ltostr(buf,
34539  #ifdef HAVE_IPV6
34540                ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
34541  #else
34542                ntohs(srv_sock->addr.ipv4.sin_port)
34543  #endif
34544                );
34545 -       
34546 +
34547         scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
34548 -       
34549 +
34550         /* get the server-side of the connection to the client */
34551         our_addr_len = sizeof(our_addr);
34552 -       
34553 -       if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
34554 +
34555 +       if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
34556                 s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
34557         } else {
34558                 s = inet_ntop_cache_get_ip(srv, &(our_addr));
34559         }
34560         scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
34561 -       
34562 -       ltostr(buf, 
34563 +
34564 +       ltostr(buf,
34565  #ifdef HAVE_IPV6
34566                ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
34567  #else
34568                ntohs(con->dst_addr.ipv4.sin_port)
34569  #endif
34570                );
34571 -       
34572 +
34573         scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
34574 -       
34575 +
34576         s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
34577         scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
34578 -       
34579 +
34580         if (!buffer_is_empty(con->authed_user)) {
34581                 scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_USER"),
34582                              CONST_BUF_LEN(con->authed_user));
34583         }
34584 -       
34585 +
34586  
34587         /*
34588          * SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to
34589 @@ -1500,12 +1485,12 @@
34590          */
34591  
34592         scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
34593 -               
34594 +
34595         if (!buffer_is_empty(con->request.pathinfo)) {
34596                 scgi_env_add(p->scgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
34597 -               
34598 +
34599                 /* PATH_TRANSLATED is only defined if PATH_INFO is set */
34600 -               
34601 +
34602                 if (!buffer_is_empty(host->docroot)) {
34603                         buffer_copy_string_buffer(p->path, host->docroot);
34604                 } else {
34605 @@ -1526,19 +1511,19 @@
34606          */
34607  
34608         if (!buffer_is_empty(host->docroot)) {
34609 -               /* 
34610 -                * rewrite SCRIPT_FILENAME 
34611 -                * 
34612 +               /*
34613 +                * rewrite SCRIPT_FILENAME
34614 +                *
34615                  */
34616 -               
34617 +
34618                 buffer_copy_string_buffer(p->path, host->docroot);
34619                 buffer_append_string_buffer(p->path, con->uri.path);
34620 -               
34621 +
34622                 scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
34623                 scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot));
34624         } else {
34625                 buffer_copy_string_buffer(p->path, con->physical.path);
34626 -               
34627 +
34628                 scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
34629                 scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
34630         }
34631 @@ -1551,30 +1536,30 @@
34632         } else {
34633                 scgi_env_add(p->scgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
34634         }
34635 -       
34636 +
34637         s = get_http_method_name(con->request.http_method);
34638         scgi_env_add(p->scgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
34639         scgi_env_add(p->scgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
34640         s = get_http_version_name(con->request.http_version);
34641         scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
34642 -       
34643 +
34644  #ifdef USE_OPENSSL
34645         if (srv_sock->is_ssl) {
34646                 scgi_env_add(p->scgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
34647         }
34648  #endif
34649 -       
34650 +
34651         scgi_env_add_request_headers(srv, con, p);
34652  
34653         b = chunkqueue_get_append_buffer(hctx->wb);
34654 -       
34655 +
34656         buffer_append_long(b, p->scgi_env->used);
34657         buffer_append_string_len(b, CONST_STR_LEN(":"));
34658         buffer_append_string_len(b, (const char *)p->scgi_env->ptr, p->scgi_env->used);
34659         buffer_append_string_len(b, CONST_STR_LEN(","));
34660  
34661         hctx->wb->bytes_in += b->used - 1;
34662 -       
34663 +
34664         if (con->request.content_length) {
34665                 chunkqueue *req_cq = con->request_content_queue;
34666                 chunk *req_c;
34667 @@ -1587,7 +1572,7 @@
34668  
34669                         /* we announce toWrite octects
34670                          * now take all the request_content chunk that we need to fill this request
34671 -                        * */   
34672 +                        * */
34673  
34674                         switch (req_c->type) {
34675                         case FILE_CHUNK:
34676 @@ -1615,293 +1600,170 @@
34677  
34678                                 req_c->offset += weHave;
34679                                 req_cq->bytes_out += weHave;
34680 -                               
34681 +
34682                                 hctx->wb->bytes_in += weHave;
34683  
34684                                 break;
34685                         default:
34686                                 break;
34687                         }
34688 -                       
34689 +
34690                         offset += weHave;
34691                 }
34692         }
34693 -       
34694 +
34695  #if 0
34696         for (i = 0; i < hctx->write_buffer->used; i++) {
34697                 fprintf(stderr, "%02x ", hctx->write_buffer->ptr[i]);
34698                 if ((i+1) % 16 == 0) {
34699                         size_t j;
34700                         for (j = i-15; j <= i; j++) {
34701 -                               fprintf(stderr, "%c", 
34702 +                               fprintf(stderr, "%c",
34703                                         isprint((unsigned char)hctx->write_buffer->ptr[j]) ? hctx->write_buffer->ptr[j] : '.');
34704                         }
34705                         fprintf(stderr, "\n");
34706                 }
34707         }
34708  #endif
34709 -       
34710 -       return 0;
34711 -}
34712  
34713 -static int scgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in, int eol) {
34714 -       char *ns;
34715 -       const char *s;
34716 -       int line = 0;
34717 -       
34718 -       UNUSED(srv);
34719 -       
34720 -       buffer_copy_string_buffer(p->parse_response, in);
34721 -       
34722 -       for (s = p->parse_response->ptr; 
34723 -            NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n'))); 
34724 -            s = ns + (eol == EOL_RN ? 2 : 1), line++) {
34725 -               const char *key, *value;
34726 -               int key_len;
34727 -               data_string *ds;
34728 -               
34729 -               ns[0] = '\0';
34730 -               
34731 -               if (line == 0 && 
34732 -                   0 == strncmp(s, "HTTP/1.", 7)) {
34733 -                       /* non-parsed header ... we parse them anyway */
34734 -                       
34735 -                       if ((s[7] == '1' ||
34736 -                            s[7] == '0') &&
34737 -                           s[8] == ' ') {
34738 -                               int status;
34739 -                               /* after the space should be a status code for us */
34740 -                               
34741 -                               status = strtol(s+9, NULL, 10);
34742 -                               
34743 -                               if (con->http_status >= 100 &&
34744 -                                   con->http_status < 1000) {
34745 -                                       /* we expected 3 digits and didn't got them */
34746 -                                       con->parsed_response |= HTTP_STATUS;
34747 -                                       con->http_status = status;
34748 -                               }
34749 -                       }
34750 -               } else {
34751 -               
34752 -                       key = s;
34753 -                       if (NULL == (value = strchr(s, ':'))) {
34754 -                               /* we expect: "<key>: <value>\r\n" */
34755 -                               continue;
34756 -                       }
34757 -                       
34758 -                       key_len = value - key;
34759 -                       value += 1;
34760 -                       
34761 -                       /* skip LWS */
34762 -                       while (*value == ' ' || *value == '\t') value++;
34763 -                       
34764 -                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
34765 -                               ds = data_response_init();
34766 -                       }
34767 -                       buffer_copy_string_len(ds->key, key, key_len);
34768 -                       buffer_copy_string(ds->value, value);
34769 -                       
34770 -                       array_insert_unique(con->response.headers, (data_unset *)ds);
34771 -                       
34772 -                       switch(key_len) {
34773 -                       case 4:
34774 -                               if (0 == strncasecmp(key, "Date", key_len)) {
34775 -                                       con->parsed_response |= HTTP_DATE;
34776 -                               }
34777 -                               break;
34778 -                       case 6:
34779 -                               if (0 == strncasecmp(key, "Status", key_len)) {
34780 -                                       con->http_status = strtol(value, NULL, 10);
34781 -                                       con->parsed_response |= HTTP_STATUS;
34782 -                               }
34783 -                               break;
34784 -                       case 8:
34785 -                               if (0 == strncasecmp(key, "Location", key_len)) {
34786 -                                       con->parsed_response |= HTTP_LOCATION;
34787 -                               }
34788 -                               break;
34789 -                       case 10:
34790 -                               if (0 == strncasecmp(key, "Connection", key_len)) {
34791 -                                       con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
34792 -                                       con->parsed_response |= HTTP_CONNECTION;
34793 -                               }
34794 -                               break;
34795 -                       case 14:
34796 -                               if (0 == strncasecmp(key, "Content-Length", key_len)) {
34797 -                                       con->response.content_length = strtol(value, NULL, 10);
34798 -                                       con->parsed_response |= HTTP_CONTENT_LENGTH;
34799 -                               }
34800 -                               break;
34801 -                       default:
34802 -                               break;
34803 -                       }
34804 -               }
34805 -       }
34806 -       
34807 -       /* CGI/1.1 rev 03 - 7.2.1.2 */
34808 -       if ((con->parsed_response & HTTP_LOCATION) &&
34809 -           !(con->parsed_response & HTTP_STATUS)) {
34810 -               con->http_status = 302;
34811 -       }
34812 -       
34813         return 0;
34814  }
34815  
34816 -
34817  static int scgi_demux_response(server *srv, handler_ctx *hctx) {
34818         plugin_data *p    = hctx->plugin_data;
34819         connection  *con  = hctx->remote_conn;
34820 -       
34821 -       while(1) {
34822 -               int n;
34823 -               
34824 -               buffer_prepare_copy(hctx->response, 1024);
34825 -               if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {
34826 -                       if (errno == EAGAIN || errno == EINTR) {
34827 -                               /* would block, wait for signal */
34828 -                               return 0;
34829 -                       }
34830 -                       /* error */
34831 -                       log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd);
34832 -                       return -1;
34833 -               }
34834 -               
34835 -               if (n == 0) {
34836 -                       /* read finished */
34837 -                       
34838 -                       con->file_finished = 1;
34839 -                       
34840 -                       /* send final chunk */
34841 -                       http_chunk_append_mem(srv, con, NULL, 0);
34842 -                       joblist_append(srv, con);
34843 -                       
34844 +       chunk *c;
34845 +
34846 +       switch(srv->network_backend_read(srv, con, hctx->sock, hctx->rb)) {
34847 +       case NETWORK_STATUS_SUCCESS:
34848 +               /* we got content */
34849 +               break;
34850 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
34851 +               /* the ioctl will return WAIT_FOR_EVENT on a read */
34852 +               if (0 == con->file_started) return -1;
34853 +       case NETWORK_STATUS_CONNECTION_CLOSE:
34854 +               /* we are done, get out of here */
34855 +               con->file_finished = 1;
34856 +
34857 +               /* close the chunk-queue with a empty chunk */
34858 +
34859 +               return 1;
34860 +       default:
34861 +               /* oops */
34862 +               return -1;
34863 +       }
34864 +
34865 +       /* looks like we got some content
34866 +       *
34867 +       * split off the header from the incoming stream
34868 +       */
34869 +
34870 +       if (hctx->state == SCGI_STATE_RESPONSE_HEADER) {
34871 +               size_t i;
34872 +               int have_content_length = 0;
34873 +
34874 +               http_response_reset(p->resp);
34875 +
34876 +               /* the response header is not fully received yet,
34877 +               *
34878 +               * extract the http-response header from the rb-cq
34879 +               */
34880 +               switch (http_response_parse_cq(hctx->rb, p->resp)) {
34881 +               case PARSE_ERROR:
34882 +                       /* parsing failed */
34883 +
34884 +                       con->http_status = 502; /* Bad Gateway */
34885                         return 1;
34886 -               }
34887 -               
34888 -               hctx->response->ptr[n] = '\0';
34889 -               hctx->response->used = n+1;
34890 -               
34891 -               /* split header from body */
34892 -               
34893 -               if (con->file_started == 0) {
34894 -                       char *c;
34895 -                       int in_header = 0;
34896 -                       int header_end = 0;
34897 -                       int cp, eol = EOL_UNSET;
34898 -                       size_t used = 0;
34899 -                       
34900 -                       buffer_append_string_buffer(hctx->response_header, hctx->response);
34901 -                       
34902 -                       /* nph (non-parsed headers) */
34903 -                       if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;
34904 -                       
34905 -                       /* search for the \r\n\r\n or \n\n in the string */
34906 -                       for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) {
34907 -                               if (*c == ':') in_header = 1;
34908 -                               else if (*c == '\n') {
34909 -                                       if (in_header == 0) {
34910 -                                               /* got a response without a response header */
34911 -                                               
34912 -                                               c = NULL;
34913 -                                               header_end = 1;
34914 -                                               break;
34915 -                                       }
34916 -                                       
34917 -                                       if (eol == EOL_UNSET) eol = EOL_N;
34918 -                                       
34919 -                                       if (*(c+1) == '\n') {
34920 -                                               header_end = 1;
34921 -                                               break;
34922 -                                       }
34923 -                                       
34924 -                               } else if (used > 1 && *c == '\r' && *(c+1) == '\n') {
34925 -                                       if (in_header == 0) {
34926 -                                               /* got a response without a response header */
34927 -                                               
34928 -                                               c = NULL;
34929 -                                               header_end = 1;
34930 -                                               break;
34931 -                                       }
34932 -                                       
34933 -                                       if (eol == EOL_UNSET) eol = EOL_RN;
34934 -                                       
34935 -                                       if (used > 3 &&
34936 -                                           *(c+2) == '\r' && 
34937 -                                           *(c+3) == '\n') {
34938 -                                               header_end = 1;
34939 -                                               break;
34940 -                                       }
34941 -                                       
34942 -                                       /* skip the \n */
34943 -                                       c++;
34944 -                                       cp++;
34945 -                                       used--;
34946 +               case PARSE_NEED_MORE:
34947 +                       return 0;
34948 +               case PARSE_SUCCESS:
34949 +                       con->http_status = p->resp->status;
34950 +
34951 +                       chunkqueue_remove_finished_chunks(hctx->rb);
34952 +
34953 +                       /* copy the http-headers */
34954 +                       for (i = 0; i < p->resp->headers->used; i++) {
34955 +                               const char *ign[] = { "Status", "Connection", NULL };
34956 +                               size_t j;
34957 +                               data_string *ds;
34958 +
34959 +                               data_string *header = (data_string *)p->resp->headers->data[i];
34960 +
34961 +                               /* some headers are ignored by default */
34962 +                               for (j = 0; ign[j]; j++) {
34963 +                                       if (0 == strcasecmp(ign[j], header->key->ptr)) break;
34964                                 }
34965 -                       }
34966 -                       
34967 -                       if (header_end) {
34968 -                               if (c == NULL) {
34969 -                                       /* no header, but a body */
34970 -                                       
34971 -                                       if (con->request.http_version == HTTP_VERSION_1_1) {
34972 -                                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
34973 -                                       }
34974 -                                       
34975 -                                       http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
34976 -                                       joblist_append(srv, con);
34977 -                               } else {
34978 -                                       size_t hlen = c - hctx->response_header->ptr + (eol == EOL_RN ? 4 : 2);
34979 -                                       size_t blen = hctx->response_header->used - hlen - 1;
34980 -                               
34981 -                                       /* a small hack: terminate after at the second \r */
34982 -                                       hctx->response_header->used = hlen + 1 - (eol == EOL_RN ? 2 : 1);
34983 -                                       hctx->response_header->ptr[hlen - (eol == EOL_RN ? 2 : 1)] = '\0';
34984 -                               
34985 -                                       /* parse the response header */
34986 -                                       scgi_response_parse(srv, con, p, hctx->response_header, eol);
34987 -                                       
34988 -                                       /* enable chunked-transfer-encoding */
34989 -                                       if (con->request.http_version == HTTP_VERSION_1_1 &&
34990 -                                           !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
34991 -                                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
34992 -                                       }
34993 -                                       
34994 -                                       if ((hctx->response->used != hlen) && blen > 0) {
34995 -                                               http_chunk_append_mem(srv, con, c + (eol == EOL_RN ? 4: 2), blen + 1);
34996 -                                               joblist_append(srv, con);
34997 -                                       }
34998 +                               if (ign[j]) continue;
34999 +
35000 +                               if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
35001 +                                       /* CGI/1.1 rev 03 - 7.2.1.2 */
35002 +                                       if (con->http_status == 0) con->http_status = 302;
35003 +                               } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
35004 +                                       have_content_length = 1;
35005                                 }
35006                                 
35007 -                               con->file_started = 1;
35008 +                               if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
35009 +                                       ds = data_response_init();
35010 +                               }
35011 +                               buffer_copy_string_buffer(ds->key, header->key);
35012 +                               buffer_copy_string_buffer(ds->value, header->value);
35013 +
35014 +                               array_insert_unique(con->response.headers, (data_unset *)ds);
35015                         }
35016 -               } else {
35017 -                       http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
35018 -                       joblist_append(srv, con);
35019 +
35020 +                       con->file_started = 1;
35021 +
35022 +                       if (con->request.http_version == HTTP_VERSION_1_1 &&
35023 +                           !have_content_length) {
35024 +                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
35025 +                       }
35026 +
35027 +                       hctx->state = SCGI_STATE_RESPONSE_CONTENT;
35028 +                       break;
35029                 }
35030 -               
35031 -#if 0          
35032 -               log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr);
35033 -#endif
35034         }
35035 -       
35036 +
35037 +       /* FIXME: pass the response-header to the other plugins to
35038 +       * setup the filter-queue
35039 +       *
35040 +       * - use next-queue instead of con->write_queue
35041 +       */
35042 +
35043 +       assert(hctx->state == SCGI_STATE_RESPONSE_CONTENT);
35044 +
35045 +       /* FIXME: if we have a content-length or chunked-encoding
35046 +       * handle it.
35047 +       *
35048 +       * for now we wait for EOF on the socket */
35049 +
35050 +       /* copy the content to the next cq */
35051 +       for (c = hctx->rb->first; c; c = c->next) {
35052 +               http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
35053 +
35054 +               c->offset = c->mem->used - 1;
35055 +       }
35056 +
35057 +       chunkqueue_remove_finished_chunks(hctx->rb);
35058 +       joblist_append(srv, con);
35059 +
35060         return 0;
35061  }
35062  
35063  
35064  int scgi_proclist_sort_up(server *srv, scgi_extension_host *host, scgi_proc *proc) {
35065         scgi_proc *p;
35066 -       
35067 +
35068         UNUSED(srv);
35069 -       
35070 -       /* we have been the smallest of the current list 
35071 -        * and we want to insert the node sorted as soon 
35072 +
35073 +       /* we have been the smallest of the current list
35074 +        * and we want to insert the node sorted as soon
35075          * possible
35076          *
35077 -        * 1 0 0 0 1 1 1 
35078 -        * |      ^ 
35079 +        * 1 0 0 0 1 1 1
35080 +        * |      ^
35081          * |      |
35082          * +------+
35083 -        * 
35084 +        *
35085          */
35086  
35087         /* nothing to sort, only one element */
35088 @@ -1909,9 +1771,9 @@
35089  
35090         for (p = proc; p->next && p->next->load < proc->load; p = p->next);
35091  
35092 -       /* no need to move something 
35093 +       /* no need to move something
35094          *
35095 -        * 1 2 2 2 3 3 3 
35096 +        * 1 2 2 2 3 3 3
35097          * ^
35098          * |
35099          * +
35100 @@ -1930,16 +1792,16 @@
35101  
35102         if (proc->prev) proc->prev->next = proc->next;
35103         if (proc->next) proc->next->prev = proc->prev;
35104 -       
35105 +
35106         /* proc should be right of p */
35107 -       
35108 +
35109         proc->next = p->next;
35110         proc->prev = p;
35111         if (p->next) p->next->prev = proc;
35112         p->next = proc;
35113  #if 0
35114         for(p = host->first; p; p = p->next) {
35115 -               log_error_write(srv, __FILE__, __LINE__, "dd", 
35116 +               log_error_write(srv, __FILE__, __LINE__, "dd",
35117                                 p->pid, p->load);
35118         }
35119  #else
35120 @@ -1951,21 +1813,21 @@
35121  
35122  int scgi_proclist_sort_down(server *srv, scgi_extension_host *host, scgi_proc *proc) {
35123         scgi_proc *p;
35124 -       
35125 +
35126         UNUSED(srv);
35127 -       
35128 -       /* we have been the smallest of the current list 
35129 -        * and we want to insert the node sorted as soon 
35130 +
35131 +       /* we have been the smallest of the current list
35132 +        * and we want to insert the node sorted as soon
35133          * possible
35134          *
35135 -        *  0 0 0 0 1 0 1 
35136 +        *  0 0 0 0 1 0 1
35137          * ^          |
35138          * |          |
35139          * +----------+
35140          *
35141          *
35142          * the basic is idea is:
35143 -        * - the last active scgi process should be still 
35144 +        * - the last active scgi process should be still
35145          *   in ram and is not swapped out yet
35146          * - processes that are not reused will be killed
35147          *   after some time by the trigger-handler
35148 @@ -1975,7 +1837,7 @@
35149          *   ice-cold processes are propably unused since more
35150          *   than 'unused-timeout', are swaped out and won't be
35151          *   reused in the next seconds anyway.
35152 -        * 
35153 +        *
35154          */
35155  
35156         /* nothing to sort, only one element */
35157 @@ -1984,16 +1846,16 @@
35158         for (p = host->first; p != proc && p->load < proc->load; p = p->next);
35159  
35160  
35161 -       /* no need to move something 
35162 +       /* no need to move something
35163          *
35164 -        * 1 2 2 2 3 3 3 
35165 +        * 1 2 2 2 3 3 3
35166          * ^
35167          * |
35168          * +
35169          *
35170          */
35171         if (p == proc) return 0;
35172 -       
35173 +
35174         /* we have to move left. If we are already the first element
35175          * we are done */
35176         if (host->first == proc) return 0;
35177 @@ -2009,9 +1871,9 @@
35178         p->prev = proc;
35179  
35180         if (proc->prev == NULL) host->first = proc;
35181 -#if 0  
35182 +#if 0
35183         for(p = host->first; p; p = p->next) {
35184 -               log_error_write(srv, __FILE__, __LINE__, "dd", 
35185 +               log_error_write(srv, __FILE__, __LINE__, "dd",
35186                                 p->pid, p->load);
35187         }
35188  #else
35189 @@ -2023,41 +1885,42 @@
35190  
35191  static int scgi_restart_dead_procs(server *srv, plugin_data *p, scgi_extension_host *host) {
35192         scgi_proc *proc;
35193 -       
35194 +
35195         for (proc = host->first; proc; proc = proc->next) {
35196                 if (p->conf.debug) {
35197 -                       log_error_write(srv, __FILE__, __LINE__,  "sbdbdddd", 
35198 -                                       "proc:", 
35199 -                                       host->host, proc->port, 
35200 +                       log_error_write(srv, __FILE__, __LINE__,  "sbdbdddd",
35201 +                                       "proc:",
35202 +                                       host->host, proc->port,
35203                                         proc->socket,
35204                                         proc->state,
35205                                         proc->is_local,
35206                                         proc->load,
35207                                         proc->pid);
35208                 }
35209 -               
35210 +
35211                 if (0 == proc->is_local) {
35212 -                       /* 
35213 -                        * external servers might get disabled 
35214 -                        * 
35215 -                        * enable the server again, perhaps it is back again 
35216 +                       /*
35217 +                        * external servers might get disabled
35218 +                        *
35219 +                        * enable the server again, perhaps it is back again
35220                          */
35221 -                       
35222 +
35223                         if ((proc->state == PROC_STATE_DISABLED) &&
35224                             (srv->cur_ts - proc->disable_ts > host->disable_time)) {
35225                                 proc->state = PROC_STATE_RUNNING;
35226                                 host->active_procs++;
35227 -                               
35228 -                               log_error_write(srv, __FILE__, __LINE__,  "sbdb", 
35229 -                                               "fcgi-server re-enabled:", 
35230 -                                               host->host, host->port, 
35231 +
35232 +                               log_error_write(srv, __FILE__, __LINE__,  "sbdb",
35233 +                                               "fcgi-server re-enabled:",
35234 +                                               host->host, host->port,
35235                                                 host->unixsocket);
35236                         }
35237                 } else {
35238                         /* the child should not terminate at all */
35239                         int status;
35240 -                       
35241 +
35242                         if (proc->state == PROC_STATE_DIED_WAIT_FOR_PID) {
35243 +#ifndef _WIN32
35244                                 switch(waitpid(proc->pid, &status, WNOHANG)) {
35245                                 case 0:
35246                                         /* child is still alive */
35247 @@ -2067,33 +1930,34 @@
35248                                 default:
35249                                         if (WIFEXITED(status)) {
35250  #if 0
35251 -                                               log_error_write(srv, __FILE__, __LINE__, "sdsd", 
35252 +                                               log_error_write(srv, __FILE__, __LINE__, "sdsd",
35253                                                                 "child exited, pid:", proc->pid,
35254                                                                 "status:", WEXITSTATUS(status));
35255  #endif
35256                                         } else if (WIFSIGNALED(status)) {
35257 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
35258 -                                                               "child signaled:", 
35259 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
35260 +                                                               "child signaled:",
35261                                                                 WTERMSIG(status));
35262                                         } else {
35263 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
35264 -                                                               "child died somehow:", 
35265 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
35266 +                                                               "child died somehow:",
35267                                                                 status);
35268                                         }
35269 -                                       
35270 +
35271                                         proc->state = PROC_STATE_DIED;
35272                                         break;
35273                                 }
35274 +#endif
35275                         }
35276 -                       
35277 -                       /* 
35278 +
35279 +                       /*
35280                          * local servers might died, but we restart them
35281 -                        * 
35282 +                        *
35283                          */
35284                         if (proc->state == PROC_STATE_DIED &&
35285                             proc->load == 0) {
35286                                 /* restart the child */
35287 -                               
35288 +
35289                                 if (p->conf.debug) {
35290                                         log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
35291                                                         "--- scgi spawning",
35292 @@ -2101,18 +1965,18 @@
35293                                                         "\n\tsocket", host->unixsocket,
35294                                                         "\n\tcurrent:", 1, "/", host->min_procs);
35295                                 }
35296 -                               
35297 +
35298                                 if (scgi_spawn_connection(srv, p, host, proc)) {
35299                                         log_error_write(srv, __FILE__, __LINE__, "s",
35300                                                         "ERROR: spawning fcgi failed.");
35301                                         return HANDLER_ERROR;
35302                                 }
35303 -                               
35304 +
35305                                 scgi_proclist_sort_down(srv, host, proc);
35306                         }
35307                 }
35308         }
35309 -       
35310 +
35311         return 0;
35312  }
35313  
35314 @@ -2121,13 +1985,13 @@
35315         plugin_data *p    = hctx->plugin_data;
35316         scgi_extension_host *host= hctx->host;
35317         connection *con   = hctx->remote_conn;
35318 -       
35319 +
35320         int ret;
35321  
35322 -       /* sanity check */      
35323 +       /* sanity check */
35324         if (!host ||
35325             ((!host->host->used || !host->port) && !host->unixsocket->used)) {
35326 -               log_error_write(srv, __FILE__, __LINE__, "sxddd", 
35327 +               log_error_write(srv, __FILE__, __LINE__, "sxddd",
35328                                 "write-req: error",
35329                                 host,
35330                                 host->host->used,
35331 @@ -2135,259 +1999,260 @@
35332                                 host->unixsocket->used);
35333                 return HANDLER_ERROR;
35334         }
35335 -       
35336 +
35337  
35338         switch(hctx->state) {
35339 -       case FCGI_STATE_INIT:
35340 +       case SCGI_STATE_INIT:
35341                 ret = host->unixsocket->used ? AF_UNIX : AF_INET;
35342 -               
35343 -               if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
35344 +
35345 +               if (-1 == (hctx->sock->fd = socket(ret, SOCK_STREAM, 0))) {
35346                         if (errno == EMFILE ||
35347                             errno == EINTR) {
35348 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
35349 -                                               "wait for fd at connection:", con->fd);
35350 -                               
35351 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
35352 +                                               "wait for fd at connection:", con->sock->fd);
35353 +
35354                                 return HANDLER_WAIT_FOR_FD;
35355                         }
35356 -                       
35357 -                       log_error_write(srv, __FILE__, __LINE__, "ssdd", 
35358 +
35359 +                       log_error_write(srv, __FILE__, __LINE__, "ssdd",
35360                                         "socket failed:", strerror(errno), srv->cur_fds, srv->max_fds);
35361                         return HANDLER_ERROR;
35362                 }
35363 -               hctx->fde_ndx = -1;
35364 -               
35365 +               hctx->sock->fde_ndx = -1;
35366 +
35367                 srv->cur_fds++;
35368 -               
35369 -               fdevent_register(srv->ev, hctx->fd, scgi_handle_fdevent, hctx);
35370 -               
35371 -               if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
35372 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
35373 +
35374 +               fdevent_register(srv->ev, hctx->sock, scgi_handle_fdevent, hctx);
35375 +
35376 +               if (-1 == fdevent_fcntl_set(srv->ev, hctx->sock)) {
35377 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
35378                                         "fcntl failed: ", strerror(errno));
35379 -                       
35380 +
35381                         return HANDLER_ERROR;
35382                 }
35383 -               
35384 +
35385                 /* fall through */
35386 -       case FCGI_STATE_CONNECT:
35387 -               if (hctx->state == FCGI_STATE_INIT) {
35388 -                       for (hctx->proc = hctx->host->first; 
35389 -                            hctx->proc && hctx->proc->state != PROC_STATE_RUNNING; 
35390 +       case SCGI_STATE_CONNECT:
35391 +               if (hctx->state == SCGI_STATE_INIT) {
35392 +                       for (hctx->proc = hctx->host->first;
35393 +                            hctx->proc && hctx->proc->state != PROC_STATE_RUNNING;
35394                              hctx->proc = hctx->proc->next);
35395 -                       
35396 +
35397                         /* all childs are dead */
35398                         if (hctx->proc == NULL) {
35399 -                               hctx->fde_ndx = -1;
35400 -                               
35401 +                               hctx->sock->fde_ndx = -1;
35402 +
35403                                 return HANDLER_ERROR;
35404                         }
35405 -                       
35406 +
35407                         if (hctx->proc->is_local) {
35408                                 hctx->pid = hctx->proc->pid;
35409                         }
35410 -                       
35411 +
35412                         switch (scgi_establish_connection(srv, hctx)) {
35413                         case 1:
35414 -                               scgi_set_state(srv, hctx, FCGI_STATE_CONNECT);
35415 -                               
35416 +                               scgi_set_state(srv, hctx, SCGI_STATE_CONNECT);
35417 +
35418                                 /* connection is in progress, wait for an event and call getsockopt() below */
35419 -                               
35420 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
35421 -                               
35422 +
35423 +                               fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
35424 +
35425                                 return HANDLER_WAIT_FOR_EVENT;
35426                         case -1:
35427                                 /* if ECONNREFUSED choose another connection -> FIXME */
35428 -                               hctx->fde_ndx = -1;
35429 -                               
35430 +                               hctx->sock->fde_ndx = -1;
35431 +
35432                                 return HANDLER_ERROR;
35433                         default:
35434                                 /* everything is ok, go on */
35435                                 break;
35436                         }
35437  
35438 -                       
35439 +
35440                 } else {
35441                         int socket_error;
35442                         socklen_t socket_error_len = sizeof(socket_error);
35443 -                       
35444 +
35445                         /* try to finish the connect() */
35446 -                       if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
35447 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
35448 +                       if (0 != getsockopt(hctx->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
35449 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
35450                                                 "getsockopt failed:", strerror(errno));
35451 -                               
35452 +
35453                                 return HANDLER_ERROR;
35454                         }
35455                         if (socket_error != 0) {
35456                                 if (!hctx->proc->is_local || p->conf.debug) {
35457                                         /* local procs get restarted */
35458 -                                       
35459 +
35460                                         log_error_write(srv, __FILE__, __LINE__, "ss",
35461 -                                                       "establishing connection failed:", strerror(socket_error), 
35462 +                                                       "establishing connection failed:", strerror(socket_error),
35463                                                         "port:", hctx->proc->port);
35464                                 }
35465 -                               
35466 +
35467                                 return HANDLER_ERROR;
35468                         }
35469                 }
35470 -               
35471 +
35472                 /* ok, we have the connection */
35473 -               
35474 +
35475                 hctx->proc->load++;
35476                 hctx->proc->last_used = srv->cur_ts;
35477                 hctx->got_proc = 1;
35478 -               
35479 +
35480                 if (p->conf.debug) {
35481                         log_error_write(srv, __FILE__, __LINE__, "sddbdd",
35482 -                                       "got proc:", 
35483 -                                       hctx->fd,
35484 -                                       hctx->proc->pid, 
35485 -                                       hctx->proc->socket, 
35486 +                                       "got proc:",
35487 +                                       hctx->sock->fd,
35488 +                                       hctx->proc->pid,
35489 +                                       hctx->proc->socket,
35490                                         hctx->proc->port,
35491                                         hctx->proc->load);
35492                 }
35493  
35494                 /* move the proc-list entry down the list */
35495                 scgi_proclist_sort_up(srv, hctx->host, hctx->proc);
35496 -               
35497 -               scgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
35498 +
35499 +               scgi_set_state(srv, hctx, SCGI_STATE_PREPARE_WRITE);
35500                 /* fall through */
35501 -       case FCGI_STATE_PREPARE_WRITE:
35502 +       case SCGI_STATE_PREPARE_WRITE:
35503                 scgi_create_env(srv, hctx);
35504 -               
35505 -               scgi_set_state(srv, hctx, FCGI_STATE_WRITE);
35506 -               
35507 +
35508 +               scgi_set_state(srv, hctx, SCGI_STATE_WRITE);
35509 +
35510                 /* fall through */
35511 -       case FCGI_STATE_WRITE:
35512 -               ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); 
35513 +       case SCGI_STATE_WRITE:
35514 +               ret = srv->network_backend_write(srv, con, hctx->sock, hctx->wb);
35515  
35516                 chunkqueue_remove_finished_chunks(hctx->wb);
35517 -       
35518 +
35519                 if (-1 == ret) {
35520                         if (errno == ENOTCONN) {
35521 -                               /* the connection got dropped after accept() 
35522 -                                * 
35523 -                                * this is most of the time a PHP which dies 
35524 +                               /* the connection got dropped after accept()
35525 +                                *
35526 +                                * this is most of the time a PHP which dies
35527                                  * after PHP_FCGI_MAX_REQUESTS
35528 -                                * 
35529 -                                */ 
35530 +                                *
35531 +                                */
35532                                 if (hctx->wb->bytes_out == 0 &&
35533                                     hctx->reconnects < 5) {
35534 -                                       usleep(10000); /* take away the load of the webserver 
35535 -                                                       * to let the php a chance to restart 
35536 +#ifndef _WIN32
35537 +                                       usleep(10000); /* take away the load of the webserver
35538 +                                                       * to let the php a chance to restart
35539                                                         */
35540 -                                       
35541 +#endif
35542                                         scgi_reconnect(srv, hctx);
35543 -                               
35544 +
35545                                         return HANDLER_WAIT_FOR_FD;
35546                                 }
35547 -                               
35548 +
35549                                 /* not reconnected ... why
35550 -                                * 
35551 +                                *
35552                                  * far@#lighttpd report this for FreeBSD
35553 -                                * 
35554 +                                *
35555                                  */
35556 -                               
35557 -                               log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
35558 +
35559 +                               log_error_write(srv, __FILE__, __LINE__, "ssosd",
35560                                                 "[REPORT ME] connection was dropped after accept(). reconnect() denied:",
35561                                                 "write-offset:", hctx->wb->bytes_out,
35562                                                 "reconnect attempts:", hctx->reconnects);
35563 -                               
35564 +
35565                                 return HANDLER_ERROR;
35566                         }
35567 -                       
35568 +
35569                         if ((errno != EAGAIN) &&
35570                             (errno != EINTR)) {
35571 -                               
35572 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", 
35573 +
35574 +                               log_error_write(srv, __FILE__, __LINE__, "ssd",
35575                                                 "write failed:", strerror(errno), errno);
35576 -                               
35577 +
35578                                 return HANDLER_ERROR;
35579                         } else {
35580 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
35581 -                               
35582 +                               fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
35583 +
35584                                 return HANDLER_WAIT_FOR_EVENT;
35585                         }
35586                 }
35587 -               
35588 +
35589                 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
35590                         /* we don't need the out event anymore */
35591 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
35592 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
35593 -                       scgi_set_state(srv, hctx, FCGI_STATE_READ);
35594 +                       fdevent_event_del(srv->ev, hctx->sock);
35595 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
35596 +                       scgi_set_state(srv, hctx, SCGI_STATE_RESPONSE_HEADER);
35597                 } else {
35598 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
35599 -                       
35600 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
35601 +
35602                         return HANDLER_WAIT_FOR_EVENT;
35603                 }
35604 -               
35605 +
35606                 break;
35607 -       case FCGI_STATE_READ:
35608 +       case SCGI_STATE_RESPONSE_HEADER:
35609                 /* waiting for a response */
35610                 break;
35611         default:
35612                 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
35613                 return HANDLER_ERROR;
35614         }
35615 -       
35616 +
35617         return HANDLER_WAIT_FOR_EVENT;
35618  }
35619  
35620  SUBREQUEST_FUNC(mod_scgi_handle_subrequest) {
35621         plugin_data *p = p_d;
35622 -       
35623 +
35624         handler_ctx *hctx = con->plugin_ctx[p->id];
35625         scgi_proc *proc;
35626         scgi_extension_host *host;
35627 -       
35628 +
35629         if (NULL == hctx) return HANDLER_GO_ON;
35630 -       
35631 +
35632         /* not my job */
35633         if (con->mode != p->id) return HANDLER_GO_ON;
35634 -       
35635 +
35636         /* ok, create the request */
35637         switch(scgi_write_request(srv, hctx)) {
35638         case HANDLER_ERROR:
35639                 proc = hctx->proc;
35640                 host = hctx->host;
35641 -               
35642 -               if (proc && 
35643 +
35644 +               if (proc &&
35645                     0 == proc->is_local &&
35646                     proc->state != PROC_STATE_DISABLED) {
35647                         /* only disable remote servers as we don't manage them*/
35648 -                       
35649 -                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", "fcgi-server disabled:", 
35650 +
35651 +                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", "fcgi-server disabled:",
35652                                         host->host,
35653                                         proc->port,
35654                                         proc->socket);
35655 -                       
35656 +
35657                         /* disable this server */
35658                         proc->disable_ts = srv->cur_ts;
35659                         proc->state = PROC_STATE_DISABLED;
35660                         host->active_procs--;
35661                 }
35662 -               
35663 -               if (hctx->state == FCGI_STATE_INIT ||
35664 -                   hctx->state == FCGI_STATE_CONNECT) {
35665 -                       /* connect() or getsockopt() failed, 
35666 -                        * restart the request-handling 
35667 +
35668 +               if (hctx->state == SCGI_STATE_INIT ||
35669 +                   hctx->state == SCGI_STATE_CONNECT) {
35670 +                       /* connect() or getsockopt() failed,
35671 +                        * restart the request-handling
35672                          */
35673                         if (proc && proc->is_local) {
35674  
35675                                 if (p->conf.debug) {
35676 -                                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", "connect() to scgi failed, restarting the request-handling:", 
35677 +                                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", "connect() to scgi failed, restarting the request-handling:",
35678                                                         host->host,
35679                                                         proc->port,
35680                                                         proc->socket);
35681                                 }
35682  
35683 -                               /* 
35684 +                               /*
35685                                  * several hctx might reference the same proc
35686 -                                * 
35687 +                                *
35688                                  * Only one of them should mark the proc as dead all the other
35689                                  * ones should just take a new one.
35690 -                                * 
35691 +                                *
35692                                  * If a new proc was started with the old struct this might lead
35693                                  * the mark a perfect proc as dead otherwise
35694 -                                * 
35695 +                                *
35696                                  */
35697                                 if (proc->state == PROC_STATE_RUNNING &&
35698                                     hctx->pid == proc->pid) {
35699 @@ -2395,25 +2260,25 @@
35700                                 }
35701                         }
35702                         scgi_restart_dead_procs(srv, p, host);
35703 -                       
35704 +
35705                         scgi_connection_cleanup(srv, hctx);
35706 -                       
35707 +
35708                         buffer_reset(con->physical.path);
35709                         con->mode = DIRECT;
35710                         joblist_append(srv, con);
35711 -                       
35712 -                       /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop 
35713 -                        * and hope that the childs will be restarted 
35714 -                        * 
35715 +
35716 +                       /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
35717 +                        * and hope that the childs will be restarted
35718 +                        *
35719                          */
35720                         return HANDLER_WAIT_FOR_FD;
35721                 } else {
35722                         scgi_connection_cleanup(srv, hctx);
35723 -                       
35724 +
35725                         buffer_reset(con->physical.path);
35726                         con->mode = DIRECT;
35727                         con->http_status = 503;
35728 -                       
35729 +
35730                         return HANDLER_FINISHED;
35731                 }
35732         case HANDLER_WAIT_FOR_EVENT:
35733 @@ -2433,23 +2298,23 @@
35734  static handler_t scgi_connection_close(server *srv, handler_ctx *hctx) {
35735         plugin_data *p;
35736         connection  *con;
35737 -       
35738 +
35739         if (NULL == hctx) return HANDLER_GO_ON;
35740 -       
35741 +
35742         p    = hctx->plugin_data;
35743         con  = hctx->remote_conn;
35744 -       
35745 +
35746         if (con->mode != p->id) return HANDLER_GO_ON;
35747 -       
35748 -       log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
35749 -                       "emergency exit: scgi:", 
35750 -                       "connection-fd:", con->fd,
35751 -                       "fcgi-fd:", hctx->fd);
35752 -       
35753 -       
35754 -       
35755 +
35756 +       log_error_write(srv, __FILE__, __LINE__, "ssdsd",
35757 +                       "emergency exit: scgi:",
35758 +                       "connection-fd:", con->sock->fd,
35759 +                       "fcgi-fd:", hctx->sock->fd);
35760 +
35761 +
35762 +
35763         scgi_connection_cleanup(srv, hctx);
35764 -       
35765 +
35766         return HANDLER_FINISHED;
35767  }
35768  
35769 @@ -2459,27 +2324,28 @@
35770         handler_ctx *hctx = ctx;
35771         connection  *con  = hctx->remote_conn;
35772         plugin_data *p    = hctx->plugin_data;
35773 -       
35774 +
35775         scgi_proc *proc   = hctx->proc;
35776         scgi_extension_host *host= hctx->host;
35777  
35778         if ((revents & FDEVENT_IN) &&
35779 -           hctx->state == FCGI_STATE_READ) {
35780 +           (hctx->state == SCGI_STATE_RESPONSE_HEADER ||
35781 +            hctx->state == SCGI_STATE_RESPONSE_CONTENT)) {
35782                 switch (scgi_demux_response(srv, hctx)) {
35783                 case 0:
35784                         break;
35785                 case 1:
35786                         /* we are done */
35787                         scgi_connection_cleanup(srv, hctx);
35788 -                       
35789 +
35790                         joblist_append(srv, con);
35791                         return HANDLER_FINISHED;
35792                 case -1:
35793                         if (proc->pid && proc->state != PROC_STATE_DIED) {
35794                                 int status;
35795 -                               
35796 +
35797                                 /* only fetch the zombie if it is not already done */
35798 -                               
35799 +#ifndef _WIN32
35800                                 switch(waitpid(proc->pid, &status, WNOHANG)) {
35801                                 case 0:
35802                                         /* child is still alive */
35803 @@ -2489,19 +2355,19 @@
35804                                 default:
35805                                         /* the child should not terminate at all */
35806                                         if (WIFEXITED(status)) {
35807 -                                               log_error_write(srv, __FILE__, __LINE__, "sdsd", 
35808 +                                               log_error_write(srv, __FILE__, __LINE__, "sdsd",
35809                                                                 "child exited, pid:", proc->pid,
35810                                                                 "status:", WEXITSTATUS(status));
35811                                         } else if (WIFSIGNALED(status)) {
35812 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
35813 -                                                               "child signaled:", 
35814 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
35815 +                                                               "child signaled:",
35816                                                                 WTERMSIG(status));
35817                                         } else {
35818 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
35819 -                                                               "child died somehow:", 
35820 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
35821 +                                                               "child died somehow:",
35822                                                                 status);
35823                                         }
35824 -                                       
35825 +
35826                                         if (p->conf.debug) {
35827                                                 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
35828                                                                 "--- scgi spawning",
35829 @@ -2509,40 +2375,41 @@
35830                                                                 "\n\tsocket", host->unixsocket,
35831                                                                 "\n\tcurrent:", 1, "/", host->min_procs);
35832                                         }
35833 -                                       
35834 +
35835                                         if (scgi_spawn_connection(srv, p, host, proc)) {
35836                                                 /* child died */
35837                                                 proc->state = PROC_STATE_DIED;
35838                                         } else {
35839                                                 scgi_proclist_sort_down(srv, host, proc);
35840                                         }
35841 -                                       
35842 +
35843                                         break;
35844                                 }
35845 +#endif
35846                         }
35847  
35848                         if (con->file_started == 0) {
35849                                 /* nothing has been send out yet, try to use another child */
35850 -                               
35851 +
35852                                 if (hctx->wb->bytes_out == 0 &&
35853                                     hctx->reconnects < 5) {
35854                                         scgi_reconnect(srv, hctx);
35855 -                                       
35856 -                                       log_error_write(srv, __FILE__, __LINE__, "sdsdsd", 
35857 +
35858 +                                       log_error_write(srv, __FILE__, __LINE__, "sdsdsd",
35859                                                 "response not sent, request not sent, reconnection.",
35860 -                                               "connection-fd:", con->fd,
35861 -                                               "fcgi-fd:", hctx->fd);
35862 -                                       
35863 +                                               "connection-fd:", con->sock->fd,
35864 +                                               "fcgi-fd:", hctx->sock->fd);
35865 +
35866                                         return HANDLER_WAIT_FOR_FD;
35867                                 }
35868 -                               
35869 -                               log_error_write(srv, __FILE__, __LINE__, "sdsdsd", 
35870 +
35871 +                               log_error_write(srv, __FILE__, __LINE__, "sosdsd",
35872                                                 "response not sent, request sent:", hctx->wb->bytes_out,
35873 -                                               "connection-fd:", con->fd,
35874 -                                               "fcgi-fd:", hctx->fd);
35875 -                               
35876 +                                               "connection-fd:", con->sock->fd,
35877 +                                               "fcgi-fd:", hctx->sock->fd);
35878 +
35879                                 scgi_connection_cleanup(srv, hctx);
35880 -                               
35881 +
35882                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
35883                                 buffer_reset(con->physical.path);
35884                                 con->http_status = 500;
35885 @@ -2550,76 +2417,77 @@
35886                         } else {
35887                                 /* response might have been already started, kill the connection */
35888                                 scgi_connection_cleanup(srv, hctx);
35889 -                               
35890 -                               log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
35891 +
35892 +                               log_error_write(srv, __FILE__, __LINE__, "ssdsd",
35893                                                 "response already sent out, termination connection",
35894 -                                               "connection-fd:", con->fd,
35895 -                                               "fcgi-fd:", hctx->fd);
35896 -                               
35897 +                                               "connection-fd:", con->sock->fd,
35898 +                                               "fcgi-fd:", hctx->sock->fd);
35899 +
35900                                 connection_set_state(srv, con, CON_STATE_ERROR);
35901                         }
35902  
35903                         /* */
35904 -                       
35905 -                       
35906 +
35907 +
35908                         joblist_append(srv, con);
35909                         return HANDLER_FINISHED;
35910                 }
35911         }
35912 -       
35913 +
35914         if (revents & FDEVENT_OUT) {
35915 -               if (hctx->state == FCGI_STATE_CONNECT ||
35916 -                   hctx->state == FCGI_STATE_WRITE) {
35917 +               if (hctx->state == SCGI_STATE_CONNECT ||
35918 +                   hctx->state == SCGI_STATE_WRITE) {
35919                         /* we are allowed to send something out
35920 -                        * 
35921 +                        *
35922                          * 1. in a unfinished connect() call
35923                          * 2. in a unfinished write() call (long POST request)
35924                          */
35925                         return mod_scgi_handle_subrequest(srv, con, p);
35926                 } else {
35927 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
35928 -                                       "got a FDEVENT_OUT and didn't know why:", 
35929 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
35930 +                                       "got a FDEVENT_OUT and didn't know why:",
35931                                         hctx->state);
35932                 }
35933         }
35934 -       
35935 +
35936         /* perhaps this issue is already handled */
35937         if (revents & FDEVENT_HUP) {
35938 -               if (hctx->state == FCGI_STATE_CONNECT) {
35939 +               if (hctx->state == SCGI_STATE_CONNECT) {
35940                         /* getoptsock will catch this one (right ?)
35941 -                        * 
35942 -                        * if we are in connect we might get a EINPROGRESS 
35943 -                        * in the first call and a FDEVENT_HUP in the 
35944 +                        *
35945 +                        * if we are in connect we might get a EINPROGRESS
35946 +                        * in the first call and a FDEVENT_HUP in the
35947                          * second round
35948 -                        * 
35949 +                        *
35950                          * FIXME: as it is a bit ugly.
35951 -                        * 
35952 +                        *
35953                          */
35954                         return mod_scgi_handle_subrequest(srv, con, p);
35955 -               } else if (hctx->state == FCGI_STATE_READ &&
35956 +               } else if ((hctx->state == SCGI_STATE_RESPONSE_HEADER ||
35957 +                           hctx->state == SCGI_STATE_RESPONSE_CONTENT ) &&
35958                            hctx->proc->port == 0) {
35959                         /* FIXME:
35960 -                        * 
35961 +                        *
35962                          * ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket
35963                          * even if the FCGI_FIN packet is not received yet
35964                          */
35965                 } else {
35966 -                       log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd", 
35967 -                                       "error: unexpected close of scgi connection for", 
35968 +                       log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
35969 +                                       "error: unexpected close of scgi connection for",
35970                                         con->uri.path,
35971 -                                       "(no scgi process on host: ", 
35972 +                                       "(no scgi process on host: ",
35973                                         host->host,
35974 -                                       ", port: ", 
35975 +                                       ", port: ",
35976                                         host->port,
35977                                         " ?)",
35978                                         hctx->state);
35979 -                       
35980 +
35981                         connection_set_state(srv, con, CON_STATE_ERROR);
35982                         scgi_connection_close(srv, hctx);
35983                         joblist_append(srv, con);
35984                 }
35985         } else if (revents & FDEVENT_ERR) {
35986 -               log_error_write(srv, __FILE__, __LINE__, "s", 
35987 +               log_error_write(srv, __FILE__, __LINE__, "s",
35988                                 "fcgi: got a FDEVENT_ERR. Don't know why.");
35989                 /* kill all connections to the scgi process */
35990  
35991 @@ -2628,42 +2496,39 @@
35992                 scgi_connection_close(srv, hctx);
35993                 joblist_append(srv, con);
35994         }
35995 -       
35996 +
35997         return HANDLER_FINISHED;
35998  }
35999 -#define PATCH(x) \
36000 -       p->conf.x = s->x;
36001 +
36002  static int scgi_patch_connection(server *srv, connection *con, plugin_data *p) {
36003         size_t i, j;
36004         plugin_config *s = p->config_storage[0];
36005 -       
36006 -       PATCH(exts);
36007 -       PATCH(debug);
36008 -       
36009 +
36010 +       PATCH_OPTION(exts);
36011 +       PATCH_OPTION(debug);
36012 +
36013         /* skip the first, the global context */
36014         for (i = 1; i < srv->config_context->used; i++) {
36015                 data_config *dc = (data_config *)srv->config_context->data[i];
36016                 s = p->config_storage[i];
36017 -               
36018 +
36019                 /* condition didn't match */
36020                 if (!config_check_cond(srv, con, dc)) continue;
36021 -               
36022 +
36023                 /* merge config */
36024                 for (j = 0; j < dc->value->used; j++) {
36025                         data_unset *du = dc->value->data[j];
36026 -                       
36027 +
36028                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.server"))) {
36029 -                               PATCH(exts);
36030 +                               PATCH_OPTION(exts);
36031                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.debug"))) {
36032 -                               PATCH(debug);
36033 +                               PATCH_OPTION(debug);
36034                         }
36035                 }
36036         }
36037 -       
36038 +
36039         return 0;
36040  }
36041 -#undef PATCH
36042 -
36043  
36044  static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
36045         plugin_data *p = p_d;
36046 @@ -2673,30 +2538,30 @@
36047         size_t k;
36048         buffer *fn;
36049         scgi_extension *extension = NULL;
36050 -       
36051 +
36052         /* Possibly, we processed already this request */
36053         if (con->file_started == 1) return HANDLER_GO_ON;
36054 -       
36055 +
36056         fn = uri_path_handler ? con->uri.path : con->physical.path;
36057  
36058         if (buffer_is_empty(fn)) return HANDLER_GO_ON;
36059  
36060         s_len = fn->used - 1;
36061 -       
36062 +
36063         scgi_patch_connection(srv, con, p);
36064  
36065         /* check if extension matches */
36066         for (k = 0; k < p->conf.exts->used; k++) {
36067                 size_t ct_len;
36068 -               
36069 +
36070                 extension = p->conf.exts->exts[k];
36071 -               
36072 +
36073                 if (extension->key->used == 0) continue;
36074 -               
36075 +
36076                 ct_len = extension->key->used - 1;
36077 -               
36078 +
36079                 if (s_len < ct_len) continue;
36080 -               
36081 +
36082                 /* check extension in the form "/scgi_pattern" */
36083                 if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
36084                         break;
36085 @@ -2710,17 +2575,17 @@
36086         if (k == p->conf.exts->used) {
36087                 return HANDLER_GO_ON;
36088         }
36089 -       
36090 +
36091         /* get best server */
36092         for (k = 0, ndx = -1; k < extension->used; k++) {
36093                 scgi_extension_host *host = extension->hosts[k];
36094 -               
36095 +
36096                 /* we should have at least one proc that can do somthing */
36097                 if (host->active_procs == 0) continue;
36098  
36099                 if (used == -1 || host->load < used) {
36100                         used = host->load;
36101 -                       
36102 +
36103                         ndx = k;
36104                 }
36105         }
36106 @@ -2728,12 +2593,12 @@
36107         /* found a server */
36108         if (ndx != -1) {
36109                 scgi_extension_host *host = extension->hosts[ndx];
36110 -               
36111 -               /* 
36112 -                * if check-local is disabled, use the uri.path handler 
36113 -                * 
36114 +
36115 +               /*
36116 +                * if check-local is disabled, use the uri.path handler
36117 +                *
36118                  */
36119 -               
36120 +
36121                 /* init handler-context */
36122                 if (uri_path_handler) {
36123                         if (host->check_local == 0) {
36124 @@ -2741,7 +2606,7 @@
36125                                 char *pathinfo;
36126  
36127                                 hctx = handler_ctx_init();
36128 -                               
36129 +
36130                                 hctx->remote_conn      = con;
36131                                 hctx->plugin_data      = p;
36132                                 hctx->host             = host;
36133 @@ -2749,45 +2614,45 @@
36134  
36135                                 hctx->conf.exts        = p->conf.exts;
36136                                 hctx->conf.debug       = p->conf.debug;
36137 -                               
36138 +
36139                                 con->plugin_ctx[p->id] = hctx;
36140 -                               
36141 +
36142                                 host->load++;
36143 -                               
36144 +
36145                                 con->mode = p->id;
36146  
36147                                 if (con->conf.log_request_handling) {
36148                                         log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_scgi");
36149                                 }
36150  
36151 -                               /* the prefix is the SCRIPT_NAME, 
36152 +                               /* the prefix is the SCRIPT_NAME,
36153                                  * everthing from start to the next slash
36154                                  * this is important for check-local = "disable"
36155 -                                * 
36156 +                                *
36157                                  * if prefix = /admin.fcgi
36158 -                                * 
36159 +                                *
36160                                  * /admin.fcgi/foo/bar
36161 -                                * 
36162 +                                *
36163                                  * SCRIPT_NAME = /admin.fcgi
36164                                  * PATH_INFO   = /foo/bar
36165 -                                * 
36166 +                                *
36167                                  * if prefix = /fcgi-bin/
36168 -                                * 
36169 +                                *
36170                                  * /fcgi-bin/foo/bar
36171 -                                * 
36172 +                                *
36173                                  * SCRIPT_NAME = /fcgi-bin/foo
36174                                  * PATH_INFO   = /bar
36175 -                                * 
36176 +                                *
36177                                  */
36178 -                               
36179 +
36180                                 /* the rewrite is only done for /prefix/? matches */
36181                                 if (extension->key->ptr[0] == '/' &&
36182                                     con->uri.path->used > extension->key->used &&
36183                                     NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
36184 -                                       /* rewrite uri.path and pathinfo */ 
36185 -                                       
36186 +                                       /* rewrite uri.path and pathinfo */
36187 +
36188                                         buffer_copy_string(con->request.pathinfo, pathinfo);
36189 -                                       
36190 +
36191                                         con->uri.path->used -= con->request.pathinfo->used - 1;
36192                                         con->uri.path->ptr[con->uri.path->used - 1] = '\0';
36193                                 }
36194 @@ -2796,21 +2661,21 @@
36195                 } else {
36196                         handler_ctx *hctx;
36197                         hctx = handler_ctx_init();
36198 -                       
36199 +
36200                         hctx->remote_conn      = con;
36201                         hctx->plugin_data      = p;
36202                         hctx->host             = host;
36203                         hctx->proc             = NULL;
36204 -                       
36205 +
36206                         hctx->conf.exts        = p->conf.exts;
36207                         hctx->conf.debug       = p->conf.debug;
36208 -                       
36209 +
36210                         con->plugin_ctx[p->id] = hctx;
36211 -                       
36212 +
36213                         host->load++;
36214 -                       
36215 +
36216                         con->mode = p->id;
36217 -                       
36218 +
36219                         if (con->conf.log_request_handling) {
36220                                 log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
36221                         }
36222 @@ -2821,11 +2686,11 @@
36223                 /* no handler found */
36224                 buffer_reset(con->physical.path);
36225                 con->http_status = 500;
36226 -               
36227 -               log_error_write(srv, __FILE__, __LINE__,  "sb", 
36228 -                               "no fcgi-handler found for:", 
36229 +
36230 +               log_error_write(srv, __FILE__, __LINE__,  "sb",
36231 +                               "no fcgi-handler found for:",
36232                                 fn);
36233 -               
36234 +
36235                 return HANDLER_FINISHED;
36236         }
36237         return HANDLER_GO_ON;
36238 @@ -2844,21 +2709,22 @@
36239  JOBLIST_FUNC(mod_scgi_handle_joblist) {
36240         plugin_data *p = p_d;
36241         handler_ctx *hctx = con->plugin_ctx[p->id];
36242 -       
36243 +
36244         if (hctx == NULL) return HANDLER_GO_ON;
36245  
36246 -       if (hctx->fd != -1) {
36247 +       if (hctx->sock->fd != -1) {
36248                 switch (hctx->state) {
36249 -               case FCGI_STATE_READ:
36250 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
36251 -                       
36252 +               case SCGI_STATE_RESPONSE_HEADER:
36253 +               case SCGI_STATE_RESPONSE_CONTENT:
36254 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
36255 +
36256                         break;
36257 -               case FCGI_STATE_CONNECT:
36258 -               case FCGI_STATE_WRITE:
36259 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
36260 -                       
36261 +               case SCGI_STATE_CONNECT:
36262 +               case SCGI_STATE_WRITE:
36263 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
36264 +
36265                         break;
36266 -               case FCGI_STATE_INIT:
36267 +               case SCGI_STATE_INIT:
36268                         /* at reconnect */
36269                         break;
36270                 default:
36271 @@ -2873,21 +2739,21 @@
36272  
36273  static handler_t scgi_connection_close_callback(server *srv, connection *con, void *p_d) {
36274         plugin_data *p = p_d;
36275 -       
36276 +
36277         return scgi_connection_close(srv, con->plugin_ctx[p->id]);
36278  }
36279  
36280  TRIGGER_FUNC(mod_scgi_handle_trigger) {
36281         plugin_data *p = p_d;
36282         size_t i, j, n;
36283 -       
36284 -       
36285 +
36286 +
36287         /* perhaps we should kill a connect attempt after 10-15 seconds
36288 -        * 
36289 +        *
36290          * currently we wait for the TCP timeout which is on Linux 180 seconds
36291 -        * 
36292 -        * 
36293 -        * 
36294 +        *
36295 +        *
36296 +        *
36297          */
36298  
36299         /* check all childs if they are still up */
36300 @@ -2904,47 +2770,47 @@
36301                         scgi_extension *ex;
36302  
36303                         ex = exts->exts[j];
36304 -                       
36305 +
36306                         for (n = 0; n < ex->used; n++) {
36307 -                               
36308 +
36309                                 scgi_proc *proc;
36310                                 unsigned long sum_load = 0;
36311                                 scgi_extension_host *host;
36312 -                               
36313 +
36314                                 host = ex->hosts[n];
36315 -                               
36316 +
36317                                 scgi_restart_dead_procs(srv, p, host);
36318 -                               
36319 +
36320                                 for (proc = host->first; proc; proc = proc->next) {
36321                                         sum_load += proc->load;
36322                                 }
36323 -                               
36324 +
36325                                 if (host->num_procs &&
36326                                     host->num_procs < host->max_procs &&
36327                                     (sum_load / host->num_procs) > host->max_load_per_proc) {
36328                                         /* overload, spawn new child */
36329                                         scgi_proc *fp = NULL;
36330 -                                       
36331 +
36332                                         if (p->conf.debug) {
36333 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
36334 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
36335                                                                 "overload detected, spawning a new child");
36336                                         }
36337 -                                       
36338 +
36339                                         for (fp = host->unused_procs; fp && fp->pid != 0; fp = fp->next);
36340 -                                       
36341 +
36342                                         if (fp) {
36343                                                 if (fp == host->unused_procs) host->unused_procs = fp->next;
36344 -                                               
36345 +
36346                                                 if (fp->next) fp->next->prev = NULL;
36347 -                                               
36348 +
36349                                                 host->max_id++;
36350                                         } else {
36351                                                 fp = scgi_process_init();
36352                                                 fp->id = host->max_id++;
36353                                         }
36354 -                                       
36355 +
36356                                         host->num_procs++;
36357 -                                       
36358 +
36359                                         if (buffer_is_empty(host->unixsocket)) {
36360                                                 fp->port = host->port + fp->id;
36361                                         } else {
36362 @@ -2952,13 +2818,13 @@
36363                                                 buffer_append_string(fp->socket, "-");
36364                                                 buffer_append_long(fp->socket, fp->id);
36365                                         }
36366 -                                       
36367 +
36368                                         if (scgi_spawn_connection(srv, p, host, fp)) {
36369                                                 log_error_write(srv, __FILE__, __LINE__, "s",
36370                                                                 "ERROR: spawning fcgi failed.");
36371                                                 return HANDLER_ERROR;
36372                                         }
36373 -                                       
36374 +
36375                                         fp->prev = NULL;
36376                                         fp->next = host->first;
36377                                         if (host->first) {
36378 @@ -2966,56 +2832,57 @@
36379                                         }
36380                                         host->first = fp;
36381                                 }
36382 -                               
36383 +
36384                                 for (proc = host->first; proc; proc = proc->next) {
36385                                         if (proc->load != 0) break;
36386                                         if (host->num_procs <= host->min_procs) break;
36387                                         if (proc->pid == 0) continue;
36388 -                                       
36389 +#ifndef _WIN32
36390                                         if (srv->cur_ts - proc->last_used > host->idle_timeout) {
36391                                                 /* a proc is idling for a long time now,
36392                                                  * terminated it */
36393 -                                               
36394 +
36395                                                 if (p->conf.debug) {
36396 -                                                       log_error_write(srv, __FILE__, __LINE__, "ssbsd", 
36397 -                                                                       "idle-timeout reached, terminating child:", 
36398 -                                                                       "socket:", proc->socket, 
36399 +                                                       log_error_write(srv, __FILE__, __LINE__, "ssbsd",
36400 +                                                                       "idle-timeout reached, terminating child:",
36401 +                                                                       "socket:", proc->socket,
36402                                                                         "pid", proc->pid);
36403                                                 }
36404 -                                               
36405 -                                               
36406 +
36407 +
36408                                                 if (proc->next) proc->next->prev = proc->prev;
36409                                                 if (proc->prev) proc->prev->next = proc->next;
36410 -                                               
36411 +
36412                                                 if (proc->prev == NULL) host->first = proc->next;
36413 -                                               
36414 +
36415                                                 proc->prev = NULL;
36416                                                 proc->next = host->unused_procs;
36417 -                                               
36418 +
36419                                                 if (host->unused_procs) host->unused_procs->prev = proc;
36420                                                 host->unused_procs = proc;
36421 -                                               
36422 +
36423                                                 kill(proc->pid, SIGTERM);
36424 -                                               
36425 +
36426                                                 proc->state = PROC_STATE_KILLED;
36427 -                                               
36428 -                                               log_error_write(srv, __FILE__, __LINE__, "ssbsd", 
36429 -                                                                       "killed:", 
36430 -                                                                       "socket:", proc->socket, 
36431 +
36432 +                                               log_error_write(srv, __FILE__, __LINE__, "ssbsd",
36433 +                                                                       "killed:",
36434 +                                                                       "socket:", proc->socket,
36435                                                                         "pid", proc->pid);
36436 -                                               
36437 +
36438                                                 host->num_procs--;
36439 -                                               
36440 +
36441                                                 /* proc is now in unused, let the next second handle the next process */
36442                                                 break;
36443 -                                       }       
36444 +                                       }
36445 +#endif
36446                                 }
36447 -                               
36448 +
36449                                 for (proc = host->unused_procs; proc; proc = proc->next) {
36450                                         int status;
36451 -                                       
36452 +
36453                                         if (proc->pid == 0) continue;
36454 -                                       
36455 +#ifndef _WIN32
36456                                         switch (waitpid(proc->pid, &status, WNOHANG)) {
36457                                         case 0:
36458                                                 /* child still running after timeout, good */
36459 @@ -3023,10 +2890,10 @@
36460                                         case -1:
36461                                                 if (errno != EINTR) {
36462                                                         /* no PID found ? should never happen */
36463 -                                                       log_error_write(srv, __FILE__, __LINE__, "sddss", 
36464 +                                                       log_error_write(srv, __FILE__, __LINE__, "sddss",
36465                                                                         "pid ", proc->pid, proc->state,
36466                                                                         "not found:", strerror(errno));
36467 -                                                       
36468 +
36469  #if 0
36470                                                         if (errno == ECHILD) {
36471                                                                 /* someone else has cleaned up for us */
36472 @@ -3040,25 +2907,26 @@
36473                                                 /* the child should not terminate at all */
36474                                                 if (WIFEXITED(status)) {
36475                                                         if (proc->state != PROC_STATE_KILLED) {
36476 -                                                               log_error_write(srv, __FILE__, __LINE__, "sdb", 
36477 -                                                                               "child exited:", 
36478 +                                                               log_error_write(srv, __FILE__, __LINE__, "sdb",
36479 +                                                                               "child exited:",
36480                                                                                 WEXITSTATUS(status), proc->socket);
36481                                                         }
36482                                                 } else if (WIFSIGNALED(status)) {
36483                                                         if (WTERMSIG(status) != SIGTERM) {
36484 -                                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
36485 -                                                                               "child signaled:", 
36486 +                                                               log_error_write(srv, __FILE__, __LINE__, "sd",
36487 +                                                                               "child signaled:",
36488                                                                                 WTERMSIG(status));
36489                                                         }
36490                                                 } else {
36491 -                                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
36492 -                                                                       "child died somehow:", 
36493 +                                                       log_error_write(srv, __FILE__, __LINE__, "sd",
36494 +                                                                       "child died somehow:",
36495                                                                         status);
36496                                                 }
36497                                                 proc->pid = 0;
36498                                                 proc->state = PROC_STATE_UNSET;
36499                                                 host->max_id--;
36500                                         }
36501 +#endif
36502                                 }
36503                         }
36504                 }
36505 @@ -3082,8 +2950,8 @@
36506         p->handle_subrequest       = mod_scgi_handle_subrequest;
36507         p->handle_joblist          = mod_scgi_handle_joblist;
36508         p->handle_trigger          = mod_scgi_handle_trigger;
36509 -       
36510 +
36511         p->data         = NULL;
36512 -       
36513 +
36514         return 0;
36515  }
36516 --- ../lighttpd-1.4.11/src/mod_secure_download.c        2005-12-14 14:37:29.000000000 +0200
36517 +++ lighttpd-1.4.12/src/mod_secure_download.c   2006-07-16 00:26:03.000000000 +0300
36518 @@ -25,7 +25,7 @@
36519  #ifdef USE_OPENSSL
36520  #define IN const
36521  #else
36522 -#define IN 
36523 +#define IN
36524  #endif
36525  #define OUT
36526  
36527 @@ -36,28 +36,28 @@
36528         buffer *doc_root;
36529         buffer *secret;
36530         buffer *uri_prefix;
36531 -       
36532 +
36533         unsigned short timeout;
36534  } plugin_config;
36535  
36536  typedef struct {
36537         PLUGIN_DATA;
36538 -       
36539 +
36540         buffer *md5;
36541 -       
36542 +
36543         plugin_config **config_storage;
36544 -       
36545 -       plugin_config conf; 
36546 +
36547 +       plugin_config conf;
36548  } plugin_data;
36549  
36550  /* init the plugin data */
36551  INIT_FUNC(mod_secdownload_init) {
36552         plugin_data *p;
36553 -       
36554 +
36555         p = calloc(1, sizeof(*p));
36556 -       
36557 +
36558         p->md5 = buffer_init();
36559 -       
36560 +
36561         return p;
36562  }
36563  
36564 @@ -65,27 +65,27 @@
36565  FREE_FUNC(mod_secdownload_free) {
36566         plugin_data *p = p_d;
36567         UNUSED(srv);
36568 -       
36569 +
36570         if (!p) return HANDLER_GO_ON;
36571 -       
36572 +
36573         if (p->config_storage) {
36574                 size_t i;
36575                 for (i = 0; i < srv->config_context->used; i++) {
36576                         plugin_config *s = p->config_storage[i];
36577 -                       
36578 +
36579                         buffer_free(s->secret);
36580                         buffer_free(s->doc_root);
36581                         buffer_free(s->uri_prefix);
36582 -                       
36583 +
36584                         free(s);
36585                 }
36586                 free(p->config_storage);
36587         }
36588 -       
36589 +
36590         buffer_free(p->md5);
36591 -       
36592 +
36593         free(p);
36594 -       
36595 +
36596         return HANDLER_GO_ON;
36597  }
36598  
36599 @@ -94,107 +94,103 @@
36600  SETDEFAULTS_FUNC(mod_secdownload_set_defaults) {
36601         plugin_data *p = p_d;
36602         size_t i = 0;
36603 -       
36604 -       config_values_t cv[] = { 
36605 +
36606 +       config_values_t cv[] = {
36607                 { "secdownload.secret",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
36608                 { "secdownload.document-root",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
36609                 { "secdownload.uri-prefix",        NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
36610                 { "secdownload.timeout",           NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 3 */
36611                 { NULL,                            NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
36612         };
36613 -       
36614 +
36615         if (!p) return HANDLER_ERROR;
36616 -       
36617 +
36618         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
36619 -       
36620 +
36621         for (i = 0; i < srv->config_context->used; i++) {
36622                 plugin_config *s;
36623 -               
36624 +
36625                 s = calloc(1, sizeof(plugin_config));
36626                 s->secret        = buffer_init();
36627                 s->doc_root      = buffer_init();
36628                 s->uri_prefix    = buffer_init();
36629                 s->timeout       = 60;
36630 -               
36631 +
36632                 cv[0].destination = s->secret;
36633                 cv[1].destination = s->doc_root;
36634                 cv[2].destination = s->uri_prefix;
36635                 cv[3].destination = &(s->timeout);
36636 -               
36637 +
36638                 p->config_storage[i] = s;
36639 -       
36640 +
36641                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
36642                         return HANDLER_ERROR;
36643                 }
36644         }
36645 -       
36646 +
36647         return HANDLER_GO_ON;
36648  }
36649  
36650  /**
36651   * checks if the supplied string is a MD5 string
36652 - * 
36653 + *
36654   * @param str a possible MD5 string
36655   * @return if the supplied string is a valid MD5 string 1 is returned otherwise 0
36656   */
36657  
36658  int is_hex_len(const char *str, size_t len) {
36659         size_t i;
36660 -       
36661 +
36662         if (NULL == str) return 0;
36663 -       
36664 +
36665         for (i = 0; i < len && *str; i++, str++) {
36666                 /* illegal characters */
36667                 if (!((*str >= '0' && *str <= '9') ||
36668                       (*str >= 'a' && *str <= 'f') ||
36669 -                     (*str >= 'A' && *str <= 'F')) 
36670 +                     (*str >= 'A' && *str <= 'F'))
36671                     ) {
36672                         return 0;
36673                 }
36674         }
36675 -       
36676 +
36677         return i == len;
36678  }
36679  
36680 -#define PATCH(x) \
36681 -       p->conf.x = s->x;
36682  static int mod_secdownload_patch_connection(server *srv, connection *con, plugin_data *p) {
36683         size_t i, j;
36684         plugin_config *s = p->config_storage[0];
36685 -       
36686 -       PATCH(secret);
36687 -       PATCH(doc_root);
36688 -       PATCH(uri_prefix);
36689 -       PATCH(timeout);
36690 -       
36691 +
36692 +       PATCH_OPTION(secret);
36693 +       PATCH_OPTION(doc_root);
36694 +       PATCH_OPTION(uri_prefix);
36695 +       PATCH_OPTION(timeout);
36696 +
36697         /* skip the first, the global context */
36698         for (i = 1; i < srv->config_context->used; i++) {
36699                 data_config *dc = (data_config *)srv->config_context->data[i];
36700                 s = p->config_storage[i];
36701 -               
36702 +
36703                 /* condition didn't match */
36704                 if (!config_check_cond(srv, con, dc)) continue;
36705 -               
36706 +
36707                 /* merge config */
36708                 for (j = 0; j < dc->value->used; j++) {
36709                         data_unset *du = dc->value->data[j];
36710 -                       
36711 +
36712                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.secret"))) {
36713 -                               PATCH(secret);
36714 +                               PATCH_OPTION(secret);
36715                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.document-root"))) {
36716 -                               PATCH(doc_root);
36717 +                               PATCH_OPTION(doc_root);
36718                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.uri-prefix"))) {
36719 -                               PATCH(uri_prefix);
36720 +                               PATCH_OPTION(uri_prefix);
36721                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.timeout"))) {
36722 -                               PATCH(timeout);
36723 +                               PATCH_OPTION(timeout);
36724                         }
36725                 }
36726         }
36727 -       
36728 +
36729         return 0;
36730  }
36731 -#undef PATCH
36732 -
36733  
36734  URIHANDLER_FUNC(mod_secdownload_uri_handler) {
36735         plugin_data *p = p_d;
36736 @@ -203,88 +199,88 @@
36737         const char *rel_uri, *ts_str, *md5_str;
36738         time_t ts = 0;
36739         size_t i;
36740 -       
36741 +
36742         if (con->uri.path->used == 0) return HANDLER_GO_ON;
36743 -       
36744 +
36745         mod_secdownload_patch_connection(srv, con, p);
36746  
36747         if (buffer_is_empty(p->conf.uri_prefix)) return HANDLER_GO_ON;
36748 -       
36749 +
36750         if (buffer_is_empty(p->conf.secret)) {
36751                 log_error_write(srv, __FILE__, __LINE__, "s",
36752                                 "secdownload.secret has to be set");
36753                 return HANDLER_ERROR;
36754         }
36755 -       
36756 +
36757         if (buffer_is_empty(p->conf.doc_root)) {
36758                 log_error_write(srv, __FILE__, __LINE__, "s",
36759                                 "secdownload.document-root has to be set");
36760                 return HANDLER_ERROR;
36761         }
36762 -       
36763 -       /* 
36764 +
36765 +       /*
36766          *  /<uri-prefix>[a-f0-9]{32}/[a-f0-9]{8}/<rel-path>
36767          */
36768 -       
36769 +
36770         if (0 != strncmp(con->uri.path->ptr, p->conf.uri_prefix->ptr, p->conf.uri_prefix->used - 1)) return HANDLER_GO_ON;
36771 -       
36772 +
36773         md5_str = con->uri.path->ptr + p->conf.uri_prefix->used - 1;
36774 -       
36775 +
36776         if (!is_hex_len(md5_str, 32)) return HANDLER_GO_ON;
36777         if (*(md5_str + 32) != '/') return HANDLER_GO_ON;
36778 -       
36779 +
36780         ts_str = md5_str + 32 + 1;
36781 -       
36782 +
36783         if (!is_hex_len(ts_str, 8)) return HANDLER_GO_ON;
36784         if (*(ts_str + 8) != '/') return HANDLER_GO_ON;
36785 -       
36786 +
36787         for (i = 0; i < 8; i++) {
36788                 ts = (ts << 4) + hex2int(*(ts_str + i));
36789         }
36790 -       
36791 +
36792         /* timed-out */
36793 -       if (srv->cur_ts - ts > p->conf.timeout || 
36794 +       if (srv->cur_ts - ts > p->conf.timeout ||
36795             srv->cur_ts - ts < -p->conf.timeout) {
36796                 con->http_status = 408;
36797 -               
36798 +
36799                 return HANDLER_FINISHED;
36800         }
36801 -       
36802 +
36803         rel_uri = ts_str + 8;
36804 -       
36805 -       /* checking MD5 
36806 -        * 
36807 +
36808 +       /* checking MD5
36809 +        *
36810          * <secret><rel-path><timestamp-hex>
36811          */
36812 -       
36813 +
36814         buffer_copy_string_buffer(p->md5, p->conf.secret);
36815         buffer_append_string(p->md5, rel_uri);
36816         buffer_append_string_len(p->md5, ts_str, 8);
36817 -       
36818 +
36819         MD5_Init(&Md5Ctx);
36820         MD5_Update(&Md5Ctx, (unsigned char *)p->md5->ptr, p->md5->used - 1);
36821         MD5_Final(HA1, &Md5Ctx);
36822 -       
36823 +
36824         buffer_copy_string_hex(p->md5, (char *)HA1, 16);
36825 -       
36826 +
36827         if (0 != strncmp(md5_str, p->md5->ptr, 32)) {
36828                 con->http_status = 403;
36829 -               
36830 -               log_error_write(srv, __FILE__, __LINE__, "sss", 
36831 +
36832 +               log_error_write(srv, __FILE__, __LINE__, "sss",
36833                                 "md5 invalid:",
36834                                 md5_str, p->md5->ptr);
36835 -               
36836 +
36837                 return HANDLER_FINISHED;
36838         }
36839 -       
36840 +
36841         /* starting with the last / we should have relative-path to the docroot
36842          */
36843 -       
36844 +
36845         buffer_copy_string_buffer(con->physical.doc_root, p->conf.doc_root);
36846         buffer_copy_string(con->physical.rel_path, rel_uri);
36847         buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
36848         buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
36849 -       
36850 +
36851         return HANDLER_GO_ON;
36852  }
36853  
36854 @@ -293,13 +289,13 @@
36855  int mod_secdownload_plugin_init(plugin *p) {
36856         p->version     = LIGHTTPD_VERSION_ID;
36857         p->name        = buffer_init_string("secdownload");
36858 -       
36859 +
36860         p->init        = mod_secdownload_init;
36861         p->handle_physical  = mod_secdownload_uri_handler;
36862         p->set_defaults  = mod_secdownload_set_defaults;
36863         p->cleanup     = mod_secdownload_free;
36864 -       
36865 +
36866         p->data        = NULL;
36867 -       
36868 +
36869         return 0;
36870  }
36871 --- ../lighttpd-1.4.11/src/mod_setenv.c 2006-01-14 20:33:12.000000000 +0200
36872 +++ lighttpd-1.4.12/src/mod_setenv.c    2006-07-16 00:26:04.000000000 +0300
36873 @@ -18,25 +18,25 @@
36874  typedef struct {
36875         array *request_header;
36876         array *response_header;
36877 -       
36878 +
36879         array *environment;
36880  } plugin_config;
36881  
36882  typedef struct {
36883         PLUGIN_DATA;
36884 -       
36885 +
36886         plugin_config **config_storage;
36887 -       
36888 -       plugin_config conf; 
36889 +
36890 +       plugin_config conf;
36891  } plugin_data;
36892  
36893  static handler_ctx * handler_ctx_init() {
36894         handler_ctx * hctx;
36895 -       
36896 +
36897         hctx = calloc(1, sizeof(*hctx));
36898 -       
36899 +
36900         hctx->handled = 0;
36901 -       
36902 +
36903         return hctx;
36904  }
36905  
36906 @@ -48,36 +48,36 @@
36907  /* init the plugin data */
36908  INIT_FUNC(mod_setenv_init) {
36909         plugin_data *p;
36910 -       
36911 +
36912         p = calloc(1, sizeof(*p));
36913 -       
36914 +
36915         return p;
36916  }
36917  
36918  /* detroy the plugin data */
36919  FREE_FUNC(mod_setenv_free) {
36920         plugin_data *p = p_d;
36921 -       
36922 +
36923         UNUSED(srv);
36924  
36925         if (!p) return HANDLER_GO_ON;
36926 -       
36927 +
36928         if (p->config_storage) {
36929                 size_t i;
36930                 for (i = 0; i < srv->config_context->used; i++) {
36931                         plugin_config *s = p->config_storage[i];
36932 -                       
36933 +
36934                         array_free(s->request_header);
36935                         array_free(s->response_header);
36936                         array_free(s->environment);
36937 -                       
36938 +
36939                         free(s);
36940                 }
36941                 free(p->config_storage);
36942         }
36943 -       
36944 +
36945         free(p);
36946 -       
36947 +
36948         return HANDLER_GO_ON;
36949  }
36950  
36951 @@ -86,86 +86,83 @@
36952  SETDEFAULTS_FUNC(mod_setenv_set_defaults) {
36953         plugin_data *p = p_d;
36954         size_t i = 0;
36955 -       
36956 -       config_values_t cv[] = { 
36957 +
36958 +       config_values_t cv[] = {
36959                 { "setenv.add-request-header",  NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
36960                 { "setenv.add-response-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
36961                 { "setenv.add-environment",     NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
36962                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
36963         };
36964 -       
36965 +
36966         if (!p) return HANDLER_ERROR;
36967 -       
36968 +
36969         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
36970 -       
36971 +
36972         for (i = 0; i < srv->config_context->used; i++) {
36973                 plugin_config *s;
36974 -               
36975 +
36976                 s = calloc(1, sizeof(plugin_config));
36977                 s->request_header   = array_init();
36978                 s->response_header  = array_init();
36979                 s->environment      = array_init();
36980 -               
36981 +
36982                 cv[0].destination = s->request_header;
36983                 cv[1].destination = s->response_header;
36984                 cv[2].destination = s->environment;
36985 -               
36986 +
36987                 p->config_storage[i] = s;
36988 -       
36989 +
36990                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
36991                         return HANDLER_ERROR;
36992                 }
36993         }
36994 -       
36995 +
36996         return HANDLER_GO_ON;
36997  }
36998  
36999 -#define PATCH(x) \
37000 -       p->conf.x = s->x;
37001  static int mod_setenv_patch_connection(server *srv, connection *con, plugin_data *p) {
37002         size_t i, j;
37003         plugin_config *s = p->config_storage[0];
37004 -       
37005 -       PATCH(request_header);
37006 -       PATCH(response_header);
37007 -       PATCH(environment);
37008 -       
37009 +
37010 +       PATCH_OPTION(request_header);
37011 +       PATCH_OPTION(response_header);
37012 +       PATCH_OPTION(environment);
37013 +
37014         /* skip the first, the global context */
37015         for (i = 1; i < srv->config_context->used; i++) {
37016                 data_config *dc = (data_config *)srv->config_context->data[i];
37017                 s = p->config_storage[i];
37018 -               
37019 +
37020                 /* condition didn't match */
37021                 if (!config_check_cond(srv, con, dc)) continue;
37022 -               
37023 +
37024                 /* merge config */
37025                 for (j = 0; j < dc->value->used; j++) {
37026                         data_unset *du = dc->value->data[j];
37027 -                       
37028 +
37029                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-request-header"))) {
37030 -                               PATCH(request_header);
37031 +                               PATCH_OPTION(request_header);
37032                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-response-header"))) {
37033 -                               PATCH(response_header);
37034 +                               PATCH_OPTION(response_header);
37035                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-environment"))) {
37036 -                               PATCH(environment);
37037 +                               PATCH_OPTION(environment);
37038                         }
37039                 }
37040         }
37041 -       
37042 +
37043         return 0;
37044  }
37045 -#undef PATCH
37046  
37047  URIHANDLER_FUNC(mod_setenv_uri_handler) {
37048         plugin_data *p = p_d;
37049         size_t k;
37050         handler_ctx *hctx;
37051 -       
37052 +
37053         if (con->plugin_ctx[p->id]) {
37054                 hctx = con->plugin_ctx[p->id];
37055         } else {
37056                 hctx = handler_ctx_init();
37057 -                               
37058 +
37059                 con->plugin_ctx[p->id] = hctx;
37060         }
37061  
37062 @@ -180,52 +177,52 @@
37063         for (k = 0; k < p->conf.request_header->used; k++) {
37064                 data_string *ds = (data_string *)p->conf.request_header->data[k];
37065                 data_string *ds_dst;
37066 -               
37067 +
37068                 if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
37069                         ds_dst = data_string_init();
37070                 }
37071 -               
37072 +
37073                 buffer_copy_string_buffer(ds_dst->key, ds->key);
37074                 buffer_copy_string_buffer(ds_dst->value, ds->value);
37075 -               
37076 +
37077                 array_insert_unique(con->request.headers, (data_unset *)ds_dst);
37078         }
37079 -       
37080 +
37081         for (k = 0; k < p->conf.environment->used; k++) {
37082                 data_string *ds = (data_string *)p->conf.environment->data[k];
37083                 data_string *ds_dst;
37084 -               
37085 +
37086                 if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
37087                         ds_dst = data_string_init();
37088                 }
37089 -               
37090 +
37091                 buffer_copy_string_buffer(ds_dst->key, ds->key);
37092                 buffer_copy_string_buffer(ds_dst->value, ds->value);
37093 -               
37094 +
37095                 array_insert_unique(con->environment, (data_unset *)ds_dst);
37096         }
37097 -       
37098 +
37099         for (k = 0; k < p->conf.response_header->used; k++) {
37100                 data_string *ds = (data_string *)p->conf.response_header->data[k];
37101 -               
37102 +
37103                 response_header_insert(srv, con, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
37104         }
37105 -       
37106 +
37107         /* not found */
37108         return HANDLER_GO_ON;
37109  }
37110  
37111  REQUESTDONE_FUNC(mod_setenv_reset) {
37112         plugin_data *p = p_d;
37113 -       
37114 +
37115         UNUSED(srv);
37116 -       
37117 +
37118         if (con->plugin_ctx[p->id]) {
37119                 handler_ctx_free(con->plugin_ctx[p->id]);
37120                 con->plugin_ctx[p->id] = NULL;
37121         }
37122  
37123 -       return HANDLER_GO_ON;   
37124 +       return HANDLER_GO_ON;
37125  }
37126  
37127  /* this function is called at dlopen() time and inits the callbacks */
37128 @@ -233,15 +230,15 @@
37129  int mod_setenv_plugin_init(plugin *p) {
37130         p->version     = LIGHTTPD_VERSION_ID;
37131         p->name        = buffer_init_string("setenv");
37132 -       
37133 +
37134         p->init        = mod_setenv_init;
37135         p->handle_uri_clean  = mod_setenv_uri_handler;
37136         p->set_defaults  = mod_setenv_set_defaults;
37137         p->cleanup     = mod_setenv_free;
37138 -       
37139 +
37140         p->handle_request_done  = mod_setenv_reset;
37141  
37142         p->data        = NULL;
37143 -       
37144 +
37145         return 0;
37146  }
37147 --- ../lighttpd-1.4.11/src/mod_simple_vhost.c   2005-11-18 15:16:13.000000000 +0200
37148 +++ lighttpd-1.4.12/src/mod_simple_vhost.c      2006-07-16 00:26:04.000000000 +0300
37149 @@ -10,6 +10,8 @@
37150  
37151  #include "plugin.h"
37152  
37153 +#include "sys-files.h"
37154 +
37155  #ifdef HAVE_CONFIG_H
37156  #include "config.h"
37157  #endif
37158 @@ -18,7 +20,7 @@
37159         buffer *server_root;
37160         buffer *default_host;
37161         buffer *document_root;
37162 -       
37163 +
37164         buffer *docroot_cache_key;
37165         buffer *docroot_cache_value;
37166         buffer *docroot_cache_servername;
37167 @@ -28,138 +30,138 @@
37168  
37169  typedef struct {
37170         PLUGIN_DATA;
37171 -       
37172 +
37173         buffer *doc_root;
37174 -       
37175 +
37176         plugin_config **config_storage;
37177 -       plugin_config conf; 
37178 +       plugin_config conf;
37179  } plugin_data;
37180  
37181  INIT_FUNC(mod_simple_vhost_init) {
37182         plugin_data *p;
37183 -       
37184 +
37185         p = calloc(1, sizeof(*p));
37186 -       
37187 +
37188         p->doc_root = buffer_init();
37189 -       
37190 +
37191         return p;
37192  }
37193  
37194  FREE_FUNC(mod_simple_vhost_free) {
37195         plugin_data *p = p_d;
37196 -       
37197 +
37198         UNUSED(srv);
37199  
37200         if (!p) return HANDLER_GO_ON;
37201 -       
37202 +
37203         if (p->config_storage) {
37204                 size_t i;
37205                 for (i = 0; i < srv->config_context->used; i++) {
37206                         plugin_config *s = p->config_storage[i];
37207 -                       
37208 +
37209                         buffer_free(s->document_root);
37210                         buffer_free(s->default_host);
37211                         buffer_free(s->server_root);
37212 -                       
37213 +
37214                         buffer_free(s->docroot_cache_key);
37215                         buffer_free(s->docroot_cache_value);
37216                         buffer_free(s->docroot_cache_servername);
37217 -                       
37218 +
37219                         free(s);
37220                 }
37221 -       
37222 +
37223                 free(p->config_storage);
37224         }
37225 -       
37226 +
37227         buffer_free(p->doc_root);
37228 -       
37229 +
37230         free(p);
37231 -       
37232 +
37233         return HANDLER_GO_ON;
37234  }
37235  
37236  SETDEFAULTS_FUNC(mod_simple_vhost_set_defaults) {
37237         plugin_data *p = p_d;
37238         size_t i;
37239 -       
37240 -       config_values_t cv[] = { 
37241 +
37242 +       config_values_t cv[] = {
37243                 { "simple-vhost.server-root",       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
37244                 { "simple-vhost.default-host",      NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
37245                 { "simple-vhost.document-root",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
37246                 { "simple-vhost.debug",             NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
37247                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
37248         };
37249 -       
37250 +
37251         if (!p) return HANDLER_ERROR;
37252 -       
37253 +
37254         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37255 -       
37256 +
37257         for (i = 0; i < srv->config_context->used; i++) {
37258                 plugin_config *s;
37259 -               
37260 +
37261                 s = calloc(1, sizeof(plugin_config));
37262 -               
37263 +
37264                 s->server_root = buffer_init();
37265                 s->default_host = buffer_init();
37266                 s->document_root = buffer_init();
37267 -               
37268 +
37269                 s->docroot_cache_key = buffer_init();
37270                 s->docroot_cache_value = buffer_init();
37271                 s->docroot_cache_servername = buffer_init();
37272  
37273                 s->debug = 0;
37274 -               
37275 +
37276                 cv[0].destination = s->server_root;
37277                 cv[1].destination = s->default_host;
37278                 cv[2].destination = s->document_root;
37279                 cv[3].destination = &(s->debug);
37280 -               
37281 -               
37282 +
37283 +
37284                 p->config_storage[i] = s;
37285 -               
37286 +
37287                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
37288                         return HANDLER_ERROR;
37289                 }
37290         }
37291 -       
37292 +
37293         return HANDLER_GO_ON;
37294  }
37295  
37296  static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *out, buffer *host) {
37297         stat_cache_entry *sce = NULL;
37298 -       
37299 +
37300         buffer_prepare_copy(out, 128);
37301  
37302         if (p->conf.server_root->used) {
37303                 buffer_copy_string_buffer(out, p->conf.server_root);
37304 -               
37305 +
37306                 if (host->used) {
37307                         /* a hostname has to start with a alpha-numerical character
37308                          * and must not contain a slash "/"
37309                          */
37310                         char *dp;
37311 -                       
37312 -                       BUFFER_APPEND_SLASH(out);
37313 -                       
37314 +
37315 +                       PATHNAME_APPEND_SLASH(out);
37316 +
37317                         if (NULL == (dp = strchr(host->ptr, ':'))) {
37318                                 buffer_append_string_buffer(out, host);
37319                         } else {
37320                                 buffer_append_string_len(out, host->ptr, dp - host->ptr);
37321                         }
37322                 }
37323 -               BUFFER_APPEND_SLASH(out);
37324 -               
37325 +               PATHNAME_APPEND_SLASH(out);
37326 +
37327                 if (p->conf.document_root->used > 2 && p->conf.document_root->ptr[0] == '/') {
37328                         buffer_append_string_len(out, p->conf.document_root->ptr + 1, p->conf.document_root->used - 2);
37329                 } else {
37330                         buffer_append_string_buffer(out, p->conf.document_root);
37331 -                       BUFFER_APPEND_SLASH(out);
37332 +                       PATHNAME_APPEND_SLASH(out);
37333                 }
37334         } else {
37335                 buffer_copy_string_buffer(out, con->conf.document_root);
37336 -               BUFFER_APPEND_SLASH(out);
37337 +               PATHNAME_APPEND_SLASH(out);
37338         }
37339 -       
37340 +
37341         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, out, &sce)) {
37342                 if (p->conf.debug) {
37343                         log_error_write(srv, __FILE__, __LINE__, "sb",
37344 @@ -169,57 +171,53 @@
37345         } else if (!S_ISDIR(sce->st.st_mode)) {
37346                 return -1;
37347         }
37348 -       
37349 +
37350         return 0;
37351  }
37352  
37353 -
37354 -#define PATCH(x) \
37355 -       p->conf.x = s->x;
37356  static int mod_simple_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
37357         size_t i, j;
37358         plugin_config *s = p->config_storage[0];
37359 -       
37360 -       PATCH(server_root);
37361 -       PATCH(default_host);
37362 -       PATCH(document_root);
37363 -       
37364 -       PATCH(docroot_cache_key);
37365 -       PATCH(docroot_cache_value);
37366 -       PATCH(docroot_cache_servername);
37367  
37368 -       PATCH(debug);
37369 -       
37370 +       PATCH_OPTION(server_root);
37371 +       PATCH_OPTION(default_host);
37372 +       PATCH_OPTION(document_root);
37373 +
37374 +       PATCH_OPTION(docroot_cache_key);
37375 +       PATCH_OPTION(docroot_cache_value);
37376 +       PATCH_OPTION(docroot_cache_servername);
37377 +
37378 +       PATCH_OPTION(debug);
37379 +
37380         /* skip the first, the global context */
37381         for (i = 1; i < srv->config_context->used; i++) {
37382                 data_config *dc = (data_config *)srv->config_context->data[i];
37383                 s = p->config_storage[i];
37384 -               
37385 +
37386                 /* condition didn't match */
37387                 if (!config_check_cond(srv, con, dc)) continue;
37388 -               
37389 +
37390                 /* merge config */
37391                 for (j = 0; j < dc->value->used; j++) {
37392                         data_unset *du = dc->value->data[j];
37393 -                       
37394 +
37395                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.server-root"))) {
37396 -                               PATCH(server_root);
37397 -                               PATCH(docroot_cache_key);
37398 -                               PATCH(docroot_cache_value);
37399 -                               PATCH(docroot_cache_servername);
37400 +                               PATCH_OPTION(server_root);
37401 +                               PATCH_OPTION(docroot_cache_key);
37402 +                               PATCH_OPTION(docroot_cache_value);
37403 +                               PATCH_OPTION(docroot_cache_servername);
37404                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.default-host"))) {
37405 -                               PATCH(default_host);
37406 +                               PATCH_OPTION(default_host);
37407                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.document-root"))) {
37408 -                               PATCH(document_root);
37409 +                               PATCH_OPTION(document_root);
37410                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.debug"))) {
37411 -                               PATCH(debug);
37412 +                               PATCH_OPTION(debug);
37413                         }
37414                 }
37415         }
37416 -       
37417 +
37418         return 0;
37419  }
37420 -#undef PATCH
37421  
37422  static handler_t mod_simple_vhost_docroot(server *srv, connection *con, void *p_data) {
37423         plugin_data *p = p_data;
37424 @@ -227,12 +225,12 @@
37425         /*
37426          * cache the last successfull translation from hostname (authority) to docroot
37427          * - this saves us a stat() call
37428 -        * 
37429 +        *
37430          */
37431 -       
37432 +
37433         mod_simple_vhost_patch_connection(srv, con, p);
37434 -       
37435 -       if (p->conf.docroot_cache_key->used && 
37436 +
37437 +       if (p->conf.docroot_cache_key->used &&
37438             con->uri.authority->used &&
37439             buffer_is_equal(p->conf.docroot_cache_key, con->uri.authority)) {
37440                 /* cache hit */
37441 @@ -243,8 +241,8 @@
37442                 if ((con->uri.authority->used == 0) ||
37443                     build_doc_root(srv, con, p, p->doc_root, con->uri.authority)) {
37444                         /* not found, fallback the default-host */
37445 -                       if (build_doc_root(srv, con, p, 
37446 -                                          p->doc_root, 
37447 +                       if (build_doc_root(srv, con, p,
37448 +                                          p->doc_root,
37449                                            p->conf.default_host)) {
37450                                 return HANDLER_GO_ON;
37451                         } else {
37452 @@ -253,15 +251,15 @@
37453                 } else {
37454                         buffer_copy_string_buffer(con->server_name, con->uri.authority);
37455                 }
37456 -               
37457 +
37458                 /* copy to cache */
37459                 buffer_copy_string_buffer(p->conf.docroot_cache_key,        con->uri.authority);
37460                 buffer_copy_string_buffer(p->conf.docroot_cache_value,      p->doc_root);
37461                 buffer_copy_string_buffer(p->conf.docroot_cache_servername, con->server_name);
37462 -               
37463 +
37464                 buffer_copy_string_buffer(con->physical.doc_root, p->doc_root);
37465         }
37466 -       
37467 +
37468         return HANDLER_GO_ON;
37469  }
37470  
37471 @@ -269,13 +267,13 @@
37472  int mod_simple_vhost_plugin_init(plugin *p) {
37473         p->version     = LIGHTTPD_VERSION_ID;
37474         p->name        = buffer_init_string("simple_vhost");
37475 -       
37476 +
37477         p->init        = mod_simple_vhost_init;
37478         p->set_defaults = mod_simple_vhost_set_defaults;
37479         p->handle_docroot  = mod_simple_vhost_docroot;
37480         p->cleanup     = mod_simple_vhost_free;
37481 -       
37482 +
37483         p->data        = NULL;
37484 -       
37485 +
37486         return 0;
37487  }
37488 --- ../lighttpd-1.4.11/src/mod_skeleton.c       2005-10-02 18:30:51.000000000 +0300
37489 +++ lighttpd-1.4.12/src/mod_skeleton.c  2006-07-16 00:26:03.000000000 +0300
37490 @@ -14,13 +14,13 @@
37491  
37492  /**
37493   * this is a skeleton for a lighttpd plugin
37494 - * 
37495 + *
37496   * just replaces every occurance of 'skeleton' by your plugin name
37497 - * 
37498 + *
37499   * e.g. in vim:
37500 - * 
37501 + *
37502   *   :%s/skeleton/myhandler/
37503 - * 
37504 + *
37505   */
37506  
37507  
37508 @@ -33,12 +33,12 @@
37509  
37510  typedef struct {
37511         PLUGIN_DATA;
37512 -       
37513 +
37514         buffer *match_buf;
37515 -       
37516 +
37517         plugin_config **config_storage;
37518 -       
37519 -       plugin_config conf; 
37520 +
37521 +       plugin_config conf;
37522  } plugin_data;
37523  
37524  typedef struct {
37525 @@ -47,36 +47,36 @@
37526  
37527  static handler_ctx * handler_ctx_init() {
37528         handler_ctx * hctx;
37529 -       
37530 +
37531         hctx = calloc(1, sizeof(*hctx));
37532 -       
37533 +
37534         return hctx;
37535  }
37536  
37537  static void handler_ctx_free(handler_ctx *hctx) {
37538 -       
37539 +
37540         free(hctx);
37541  }
37542  
37543  /* init the plugin data */
37544  INIT_FUNC(mod_skeleton_init) {
37545         plugin_data *p;
37546 -       
37547 +
37548         p = calloc(1, sizeof(*p));
37549 -       
37550 +
37551         p->match_buf = buffer_init();
37552 -       
37553 +
37554         return p;
37555  }
37556  
37557  /* detroy the plugin data */
37558  FREE_FUNC(mod_skeleton_free) {
37559         plugin_data *p = p_d;
37560 -       
37561 +
37562         UNUSED(srv);
37563  
37564         if (!p) return HANDLER_GO_ON;
37565 -       
37566 +
37567         if (p->config_storage) {
37568                 size_t i;
37569  
37570 @@ -84,18 +84,18 @@
37571                         plugin_config *s = p->config_storage[i];
37572  
37573                         if (!s) continue;
37574 -                       
37575 +
37576                         array_free(s->match);
37577 -                       
37578 +
37579                         free(s);
37580                 }
37581                 free(p->config_storage);
37582         }
37583 -       
37584 +
37585         buffer_free(p->match_buf);
37586 -       
37587 +
37588         free(p);
37589 -       
37590 +
37591         return HANDLER_GO_ON;
37592  }
37593  
37594 @@ -104,91 +104,88 @@
37595  SETDEFAULTS_FUNC(mod_skeleton_set_defaults) {
37596         plugin_data *p = p_d;
37597         size_t i = 0;
37598 -       
37599 -       config_values_t cv[] = { 
37600 +
37601 +       config_values_t cv[] = {
37602                 { "skeleton.array",             NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
37603                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
37604         };
37605 -       
37606 +
37607         if (!p) return HANDLER_ERROR;
37608 -       
37609 +
37610         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37611 -       
37612 +
37613         for (i = 0; i < srv->config_context->used; i++) {
37614                 plugin_config *s;
37615 -               
37616 +
37617                 s = calloc(1, sizeof(plugin_config));
37618                 s->match    = array_init();
37619 -               
37620 +
37621                 cv[0].destination = s->match;
37622 -               
37623 +
37624                 p->config_storage[i] = s;
37625 -       
37626 +
37627                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
37628                         return HANDLER_ERROR;
37629                 }
37630         }
37631 -       
37632 +
37633         return HANDLER_GO_ON;
37634  }
37635  
37636 -#define PATCH(x) \
37637 -       p->conf.x = s->x;
37638  static int mod_skeleton_patch_connection(server *srv, connection *con, plugin_data *p) {
37639         size_t i, j;
37640         plugin_config *s = p->config_storage[0];
37641 -       
37642 -       PATCH(match);
37643 -       
37644 +
37645 +       PATCH_OPTION(match);
37646 +
37647         /* skip the first, the global context */
37648         for (i = 1; i < srv->config_context->used; i++) {
37649                 data_config *dc = (data_config *)srv->config_context->data[i];
37650                 s = p->config_storage[i];
37651 -               
37652 +
37653                 /* condition didn't match */
37654                 if (!config_check_cond(srv, con, dc)) continue;
37655 -               
37656 +
37657                 /* merge config */
37658                 for (j = 0; j < dc->value->used; j++) {
37659                         data_unset *du = dc->value->data[j];
37660 -                       
37661 +
37662                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("skeleton.array"))) {
37663 -                               PATCH(match);
37664 +                               PATCH_OPTION(match);
37665                         }
37666                 }
37667         }
37668 -       
37669 +
37670         return 0;
37671  }
37672 -#undef PATCH
37673  
37674  URIHANDLER_FUNC(mod_skeleton_uri_handler) {
37675         plugin_data *p = p_d;
37676         int s_len;
37677         size_t k, i;
37678 -       
37679 +
37680         UNUSED(srv);
37681  
37682         if (con->uri.path->used == 0) return HANDLER_GO_ON;
37683 -       
37684 +
37685         mod_skeleton_patch_connection(srv, con, p);
37686  
37687         s_len = con->uri.path->used - 1;
37688 -       
37689 +
37690         for (k = 0; k < p->conf.match->used; k++) {
37691                 data_string *ds = (data_string *)p->conf.match->data[k];
37692                 int ct_len = ds->value->used - 1;
37693 -               
37694 +
37695                 if (ct_len > s_len) continue;
37696                 if (ds->value->used == 0) continue;
37697 -               
37698 +
37699                 if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
37700                         con->http_status = 403;
37701 -       
37702 +
37703                         return HANDLER_FINISHED;
37704                 }
37705         }
37706 -       
37707 +
37708         /* not found */
37709         return HANDLER_GO_ON;
37710  }
37711 @@ -198,13 +195,13 @@
37712  int mod_skeleton_plugin_init(plugin *p) {
37713         p->version     = LIGHTTPD_VERSION_ID;
37714         p->name        = buffer_init_string("skeleton");
37715 -       
37716 +
37717         p->init        = mod_skeleton_init;
37718         p->handle_uri_clean  = mod_skeleton_uri_handler;
37719         p->set_defaults  = mod_skeleton_set_defaults;
37720         p->cleanup     = mod_skeleton_free;
37721 -       
37722 +
37723         p->data        = NULL;
37724 -       
37725 +
37726         return 0;
37727  }
37728 --- ../lighttpd-1.4.11/src/mod_sql_vhost_core.c 1970-01-01 03:00:00.000000000 +0300
37729 +++ lighttpd-1.4.12/src/mod_sql_vhost_core.c    2006-07-20 00:57:20.000000000 +0300
37730 @@ -0,0 +1,211 @@
37731 +#include <stdio.h>
37732 +#include <errno.h>
37733 +#include <fcntl.h>
37734 +#include <string.h>
37735 +
37736 +#ifdef HAVE_CONFIG_H
37737 +#include "config.h"
37738 +#endif
37739 +
37740 +#include "plugin.h"
37741 +#include "log.h"
37742 +
37743 +#include "stat_cache.h"
37744 +
37745 +#include "mod_sql_vhost_core.h"
37746 +
37747 +#define plugin_data mod_sql_vhost_core_plugin_data
37748 +#define plugin_config mod_sql_vhost_core_plugin_config
37749 +
37750 +/* init the plugin data */
37751 +INIT_FUNC(mod_sql_vhost_core_init) {
37752 +       plugin_data *p;
37753 +
37754 +       p = calloc(1, sizeof(*p));
37755 +
37756 +       p->docroot = buffer_init();
37757 +       p->host = buffer_init();
37758 +
37759 +       return p;
37760 +}
37761 +
37762 +/* cleanup the plugin data */
37763 +SERVER_FUNC(mod_sql_vhost_core_cleanup) {
37764 +       plugin_data *p = p_d;
37765 +
37766 +       UNUSED(srv);
37767 +
37768 +       if (!p) return HANDLER_GO_ON;
37769 +
37770 +       if (p->config_storage) {
37771 +               size_t i;
37772 +               for (i = 0; i < srv->config_context->used; i++) {
37773 +                       plugin_config *s = p->config_storage[i];
37774 +
37775 +                       if (!s) continue;
37776 +
37777 +                       buffer_free(s->db);
37778 +                       buffer_free(s->user);
37779 +                       buffer_free(s->pass);
37780 +                       buffer_free(s->sock);
37781 +                       buffer_free(s->backend);
37782 +                       buffer_free(s->hostname);
37783 +                       buffer_free(s->select_vhost);
37784 +
37785 +                       free(s);
37786 +               }
37787 +               free(p->config_storage);
37788 +       }
37789 +       buffer_free(p->docroot);
37790 +       buffer_free(p->host);
37791 +
37792 +       free(p);
37793 +
37794 +       return HANDLER_GO_ON;
37795 +}
37796 +
37797 +/* set configuration values */
37798 +SERVER_FUNC(mod_sql_vhost_core_set_defaults) {
37799 +       plugin_data *p = p_d;
37800 +
37801 +       size_t i = 0;
37802 +
37803 +       config_values_t cv[] = {
37804 +               { "sql-vhost.db",       NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 0 * e.g. vhost */
37805 +               { "sql-vhost.user",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 1 * lighty */
37806 +               { "sql-vhost.pass",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 2 * secrect */
37807 +               { "sql-vhost.sock",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 3 * /tmp/mysql.sock */
37808 +               { "sql-vhost.select-vhost", NULL, T_CONFIG_STRING,      T_CONFIG_SCOPE_SERVER }, /* 4 * SELECT ... FROM hosts WHERE hostname = ? */
37809 +               { "sql-vhost.hostname", NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 5 * 127.0.0.1 */
37810 +               { "sql-vhost.port",     NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_SERVER }, /* 6 * 3306 */
37811 +               { "sql-vhost.backend",  NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 7 * mysql */
37812 +
37813 +               /* backward compat */
37814 +               { "mysql-vhost.db",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 8 == 0 */
37815 +               { "mysql-vhost.user",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 9 == 1 */
37816 +               { "mysql-vhost.pass",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 10 == 2 */
37817 +               { "mysql-vhost.sock",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 11 == 3 */
37818 +               { "mysql-vhost.sql",    NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 12 == 4 */
37819 +               { "mysql-vhost.hostname", NULL, T_CONFIG_STRING,T_CONFIG_SCOPE_SERVER }, /* 13 == 5 */
37820 +               { "mysql-vhost.port",   NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_SERVER }, /* 14 == 6 */
37821 +
37822 +                { NULL,                        NULL, T_CONFIG_UNSET,   T_CONFIG_SCOPE_UNSET }
37823 +        };
37824 +
37825 +       p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37826 +
37827 +       for (i = 0; i < srv->config_context->used; i++) {
37828 +               plugin_config *s;
37829 +
37830 +               s = calloc(1, sizeof(plugin_config));
37831 +               s->db = buffer_init();
37832 +               s->user = buffer_init();
37833 +               s->pass = buffer_init();
37834 +               s->sock = buffer_init();
37835 +               s->hostname = buffer_init();
37836 +               s->backend = buffer_init();
37837 +               s->port   = 0;               /* default port for mysql */
37838 +               s->select_vhost = buffer_init();
37839 +               s->backend_data = NULL;
37840 +
37841 +               cv[0].destination = s->db;
37842 +               cv[1].destination = s->user;
37843 +               cv[2].destination = s->pass;
37844 +               cv[3].destination = s->sock;
37845 +               cv[4].destination = s->select_vhost;
37846 +               cv[5].destination = s->hostname;
37847 +               cv[6].destination = &(s->port);
37848 +               cv[7].destination = s->backend;
37849 +
37850 +               /* backend compat */
37851 +               cv[8].destination = cv[0].destination;
37852 +               cv[9].destination = cv[1].destination;
37853 +               cv[10].destination = cv[2].destination;
37854 +               cv[11].destination = cv[3].destination;
37855 +               cv[12].destination = cv[4].destination;
37856 +               cv[13].destination = cv[5].destination;
37857 +               cv[14].destination = cv[6].destination;
37858 +
37859 +               p->config_storage[i] = s;
37860 +
37861 +               if (config_insert_values_global(srv,
37862 +                       ((data_config *)srv->config_context->data[i])->value,
37863 +                       cv)) return HANDLER_ERROR;
37864 +
37865 +               /* we only parse the config, the backend plugin will patch itself into the plugin-struct */
37866 +       }
37867 +
37868 +        return HANDLER_GO_ON;
37869 +}
37870 +
37871 +static int mod_sql_vhost_core_patch_connection(server *srv, connection *con, plugin_data *p) {
37872 +       size_t i;
37873 +       plugin_config *s = p->config_storage[0];
37874 +
37875 +       PATCH_OPTION(backend_data);
37876 +       PATCH_OPTION(get_vhost);
37877 +
37878 +       /* skip the first, the global context */
37879 +       for (i = 1; i < srv->config_context->used; i++) {
37880 +               data_config *dc = (data_config *)srv->config_context->data[i];
37881 +               s = p->config_storage[i];
37882 +
37883 +               /* condition didn't match */
37884 +               if (!config_check_cond(srv, con, dc)) continue;
37885 +
37886 +               if (s->backend_data) {
37887 +                       PATCH_OPTION(backend_data);
37888 +                       PATCH_OPTION(get_vhost);
37889 +               }
37890 +       }
37891 +
37892 +       return 0;
37893 +}
37894 +
37895 +/* handle document root request */
37896 +CONNECTION_FUNC(mod_sql_vhost_core_handle_docroot) {
37897 +       plugin_data *p = p_d;
37898 +       stat_cache_entry *sce;
37899 +
37900 +       /* no host specified? */
37901 +       if (!con->uri.authority->used) return HANDLER_GO_ON;
37902 +
37903 +       mod_sql_vhost_core_patch_connection(srv, con, p);
37904 +
37905 +       /* do we have backend ? */
37906 +       if (!p->conf.get_vhost) return HANDLER_GO_ON;
37907 +
37908 +       /* ask the backend for the data */
37909 +       if (0 != p->conf.get_vhost(srv, con, p->conf.backend_data, p->docroot, p->host)) {
37910 +               return HANDLER_GO_ON;
37911 +       }
37912 +
37913 +       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->docroot, &sce)) {
37914 +               log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->docroot);
37915 +               return HANDLER_GO_ON;
37916 +       }
37917 +        if (!S_ISDIR(sce->st.st_mode)) {
37918 +               log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", p->docroot);
37919 +               return HANDLER_GO_ON;
37920 +       }
37921 +
37922 +       buffer_copy_string_buffer(con->server_name, p->host);
37923 +       buffer_copy_string_buffer(con->physical.doc_root, p->docroot);
37924 +
37925 +       return HANDLER_GO_ON;
37926 +}
37927 +
37928 +/* this function is called at dlopen() time and inits the callbacks */
37929 +int mod_sql_vhost_core_plugin_init(plugin *p) {
37930 +       p->version     = LIGHTTPD_VERSION_ID;
37931 +       p->name                         = buffer_init_string("mod_sql_vhost_core");
37932 +
37933 +       p->init                         = mod_sql_vhost_core_init;
37934 +       p->cleanup                      = mod_sql_vhost_core_cleanup;
37935 +
37936 +       p->set_defaults                 = mod_sql_vhost_core_set_defaults;
37937 +       p->handle_docroot               = mod_sql_vhost_core_handle_docroot;
37938 +
37939 +       return 0;
37940 +}
37941 +
37942 --- ../lighttpd-1.4.11/src/mod_sql_vhost_core.h 1970-01-01 03:00:00.000000000 +0300
37943 +++ lighttpd-1.4.12/src/mod_sql_vhost_core.h    2006-07-16 00:26:04.000000000 +0300
37944 @@ -0,0 +1,49 @@
37945 +#ifndef _MOD_SQL_VHOST_CORE_H_
37946 +#define _MOD_SQL_VHOST_CORE_H_
37947 +
37948 +#include "buffer.h"
37949 +#include "plugin.h"
37950 +
37951 +#define SQLVHOST_BACKEND_GETVHOST_PARAMS \
37952 +       (server *srv, connection *con, void *p_d, buffer *docroot, buffer *host)
37953 +
37954 +#define SQLVHOST_BACKEND_GETVHOST_RETVAL handler_t
37955 +
37956 +#define SQLVHOST_BACKEND_GETVHOST(name) \
37957 +       SQLVHOST_BACKEND_GETVHOST_RETVAL name SQLVHOST_BACKEND_GETVHOST_PARAMS
37958 +
37959 +#define SQLVHOST_BACKEND_GETVHOST_PTR(name) \
37960 +       SQLVHOST_BACKEND_GETVHOST_RETVAL (* name)SQLVHOST_BACKEND_GETVHOST_PARAMS
37961 +
37962 +typedef struct {
37963 +       buffer  *db;
37964 +       buffer  *user;
37965 +       buffer  *pass;
37966 +       buffer  *sock;
37967 +
37968 +       buffer  *hostname;
37969 +       unsigned short port;
37970 +
37971 +       buffer  *backend;
37972 +       void *backend_data;
37973 +
37974 +       buffer *select_vhost;
37975 +
37976 +       SQLVHOST_BACKEND_GETVHOST_PTR(get_vhost);
37977 +} mod_sql_vhost_core_plugin_config;
37978 +
37979 +/* global plugin data */
37980 +typedef struct {
37981 +       PLUGIN_DATA;
37982 +
37983 +       buffer  *docroot;
37984 +       buffer  *host;
37985 +
37986 +       mod_sql_vhost_core_plugin_config **config_storage;
37987 +
37988 +       mod_sql_vhost_core_plugin_config conf;
37989 +} mod_sql_vhost_core_plugin_data;
37990 +
37991 +
37992 +
37993 +#endif
37994 --- ../lighttpd-1.4.11/src/mod_ssi.c    2006-03-04 17:09:48.000000000 +0200
37995 +++ lighttpd-1.4.12/src/mod_ssi.c       2006-07-16 00:26:04.000000000 +0300
37996 @@ -6,7 +6,6 @@
37997  #include <string.h>
37998  #include <errno.h>
37999  #include <time.h>
38000 -#include <unistd.h>
38001  
38002  #include "base.h"
38003  #include "log.h"
38004 @@ -23,6 +22,8 @@
38005  #include "inet_ntop_cache.h"
38006  
38007  #include "sys-socket.h"
38008 +#include "sys-strings.h"
38009 +#include "sys-files.h"
38010  
38011  #ifdef HAVE_PWD_H
38012  #include <pwd.h>
38013 @@ -39,15 +40,15 @@
38014  /* init the plugin data */
38015  INIT_FUNC(mod_ssi_init) {
38016         plugin_data *p;
38017 -       
38018 +
38019         p = calloc(1, sizeof(*p));
38020 -       
38021 +
38022         p->timefmt = buffer_init();
38023         p->stat_fn = buffer_init();
38024 -       
38025 +
38026         p->ssi_vars = array_init();
38027         p->ssi_cgi_env = array_init();
38028 -       
38029 +
38030         return p;
38031  }
38032  
38033 @@ -55,21 +56,21 @@
38034  FREE_FUNC(mod_ssi_free) {
38035         plugin_data *p = p_d;
38036         UNUSED(srv);
38037 -       
38038 +
38039         if (!p) return HANDLER_GO_ON;
38040 -       
38041 +
38042         if (p->config_storage) {
38043                 size_t i;
38044                 for (i = 0; i < srv->config_context->used; i++) {
38045                         plugin_config *s = p->config_storage[i];
38046 -                       
38047 +
38048                         array_free(s->ssi_extension);
38049 -                       
38050 +
38051                         free(s);
38052                 }
38053                 free(p->config_storage);
38054         }
38055 -       
38056 +
38057         array_free(p->ssi_vars);
38058         array_free(p->ssi_cgi_env);
38059  #ifdef HAVE_PCRE_H
38060 @@ -77,9 +78,9 @@
38061  #endif
38062         buffer_free(p->timefmt);
38063         buffer_free(p->stat_fn);
38064 -       
38065 +
38066         free(p);
38067 -       
38068 +
38069         return HANDLER_GO_ON;
38070  }
38071  
38072 @@ -92,36 +93,36 @@
38073         const char *errptr;
38074         int erroff;
38075  #endif
38076 -       
38077 -       config_values_t cv[] = { 
38078 +
38079 +       config_values_t cv[] = {
38080                 { "ssi.extension",              NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
38081                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
38082         };
38083 -       
38084 +
38085         if (!p) return HANDLER_ERROR;
38086 -       
38087 +
38088         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
38089 -       
38090 +
38091         for (i = 0; i < srv->config_context->used; i++) {
38092                 plugin_config *s;
38093 -               
38094 +
38095                 s = calloc(1, sizeof(plugin_config));
38096                 s->ssi_extension  = array_init();
38097 -               
38098 +
38099                 cv[0].destination = s->ssi_extension;
38100 -               
38101 +
38102                 p->config_storage[i] = s;
38103 -       
38104 +
38105                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
38106                         return HANDLER_ERROR;
38107                 }
38108         }
38109 -       
38110 +
38111  #ifdef HAVE_PCRE_H
38112         /* allow 2 params */
38113         if (NULL == (p->ssi_regex = pcre_compile("<!--#([a-z]+)\\s+(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?-->", 0, &errptr, &erroff, NULL))) {
38114                 log_error_write(srv, __FILE__, __LINE__, "sds",
38115 -                               "ssi: pcre ", 
38116 +                               "ssi: pcre ",
38117                                 erroff, errptr);
38118                 return HANDLER_ERROR;
38119         }
38120 @@ -130,52 +131,52 @@
38121                         "mod_ssi: pcre support is missing, please recompile with pcre support or remove mod_ssi from the list of modules");
38122         return HANDLER_ERROR;
38123  #endif
38124 -       
38125 +
38126         return HANDLER_GO_ON;
38127  }
38128  
38129  int ssi_env_add(array *env, const char *key, const char *val) {
38130         data_string *ds;
38131 -                       
38132 +
38133         if (NULL == (ds = (data_string *)array_get_unused_element(env, TYPE_STRING))) {
38134                 ds = data_string_init();
38135         }
38136         buffer_copy_string(ds->key,   key);
38137         buffer_copy_string(ds->value, val);
38138 -       
38139 +
38140         array_insert_unique(env, (data_unset *)ds);
38141 -       
38142 +
38143         return 0;
38144  }
38145  
38146  /**
38147   *
38148   *  the next two functions are take from fcgi.c
38149 - * 
38150 + *
38151   */
38152  
38153  static int ssi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
38154         size_t i;
38155 -       
38156 +
38157         for (i = 0; i < con->request.headers->used; i++) {
38158                 data_string *ds;
38159 -               
38160 +
38161                 ds = (data_string *)con->request.headers->data[i];
38162 -               
38163 +
38164                 if (ds->value->used && ds->key->used) {
38165                         size_t j;
38166                         buffer_reset(srv->tmp_buf);
38167 -                       
38168 +
38169                         /* don't forward the Authorization: Header */
38170                         if (0 == strcasecmp(ds->key->ptr, "AUTHORIZATION")) {
38171                                 continue;
38172                         }
38173 -                       
38174 +
38175                         if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
38176                                 buffer_copy_string(srv->tmp_buf, "HTTP_");
38177                                 srv->tmp_buf->used--;
38178                         }
38179 -                       
38180 +
38181                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
38182                         for (j = 0; j < ds->key->used - 1; j++) {
38183                                 char c = '_';
38184 @@ -189,33 +190,33 @@
38185                                 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
38186                         }
38187                         srv->tmp_buf->ptr[srv->tmp_buf->used] = '\0';
38188 -                       
38189 +
38190                         ssi_env_add(p->ssi_cgi_env, srv->tmp_buf->ptr, ds->value->ptr);
38191                 }
38192         }
38193 -       
38194 +
38195         return 0;
38196  }
38197  
38198  static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) {
38199         char buf[32];
38200 -       
38201 +
38202         server_socket *srv_sock = con->srv_socket;
38203 -       
38204 +
38205  #ifdef HAVE_IPV6
38206         char b2[INET6_ADDRSTRLEN + 1];
38207  #endif
38208  
38209  #define CONST_STRING(x) \
38210                 x
38211 -       
38212 +
38213         array_reset(p->ssi_cgi_env);
38214 -       
38215 +
38216         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_SOFTWARE"), PACKAGE_NAME"/"PACKAGE_VERSION);
38217         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_NAME"),
38218  #ifdef HAVE_IPV6
38219 -                    inet_ntop(srv_sock->addr.plain.sa_family, 
38220 -                              srv_sock->addr.plain.sa_family == AF_INET6 ? 
38221 +                    inet_ntop(srv_sock->addr.plain.sa_family,
38222 +                              srv_sock->addr.plain.sa_family == AF_INET6 ?
38223                                (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
38224                                (const void *) &(srv_sock->addr.ipv4.sin_addr),
38225                                b2, sizeof(b2)-1)
38226 @@ -224,28 +225,28 @@
38227  #endif
38228                      );
38229         ssi_env_add(p->ssi_cgi_env, CONST_STRING("GATEWAY_INTERFACE"), "CGI/1.1");
38230 -               
38231 -       ltostr(buf, 
38232 +
38233 +       ltostr(buf,
38234  #ifdef HAVE_IPV6
38235                ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
38236  #else
38237                ntohs(srv_sock->addr.ipv4.sin_port)
38238  #endif
38239                );
38240 -       
38241 +
38242         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PORT"), buf);
38243 -       
38244 +
38245         ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_ADDR"),
38246                     inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
38247 -       
38248 +
38249         if (con->authed_user->used) {
38250                 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_USER"),
38251                              con->authed_user->ptr);
38252         }
38253 -       
38254 +
38255         if (con->request.content_length > 0) {
38256                 /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
38257 -               
38258 +
38259                 /* request.content_length < SSIZE_MAX, see request.c */
38260                 ltostr(buf, con->request.content_length);
38261                 ssi_env_add(p->ssi_cgi_env, CONST_STRING("CONTENT_LENGTH"), buf);
38262 @@ -271,30 +272,30 @@
38263         if (con->request.pathinfo->used) {
38264                 ssi_env_add(p->ssi_cgi_env, CONST_STRING("PATH_INFO"), con->request.pathinfo->ptr);
38265         }
38266 -               
38267 +
38268         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SCRIPT_FILENAME"), con->physical.path->ptr);
38269         ssi_env_add(p->ssi_cgi_env, CONST_STRING("DOCUMENT_ROOT"), con->physical.doc_root->ptr);
38270 -       
38271 +
38272         ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_URI"), con->request.uri->ptr);
38273         ssi_env_add(p->ssi_cgi_env, CONST_STRING("QUERY_STRING"), con->uri.query->used ? con->uri.query->ptr : "");
38274         ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_METHOD"), get_http_method_name(con->request.http_method));
38275         ssi_env_add(p->ssi_cgi_env, CONST_STRING("REDIRECT_STATUS"), "200");
38276         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PROTOCOL"), get_http_version_name(con->request.http_version));
38277 -       
38278 +
38279         ssi_env_add_request_headers(srv, con, p);
38280 -       
38281 +
38282         return 0;
38283  }
38284  
38285 -static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, 
38286 +static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
38287                             const char **l, size_t n) {
38288         size_t i, ssicmd = 0;
38289         char buf[255];
38290         buffer *b = NULL;
38291 -       
38292 -       struct { 
38293 +
38294 +       struct {
38295                 const char *var;
38296 -               enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD, 
38297 +               enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD,
38298                                 SSI_CONFIG, SSI_PRINTENV, SSI_SET, SSI_IF, SSI_ELIF,
38299                                 SSI_ELSE, SSI_ENDIF, SSI_EXEC } type;
38300         } ssicmds[] = {
38301 @@ -310,27 +311,27 @@
38302                 { "endif",    SSI_ENDIF },
38303                 { "else",     SSI_ELSE },
38304                 { "exec",     SSI_EXEC },
38305 -               
38306 +
38307                 { NULL, SSI_UNSET }
38308         };
38309 -       
38310 +
38311         for (i = 0; ssicmds[i].var; i++) {
38312                 if (0 == strcmp(l[1], ssicmds[i].var)) {
38313                         ssicmd = ssicmds[i].type;
38314                         break;
38315                 }
38316         }
38317 -       
38318 +
38319         switch(ssicmd) {
38320         case SSI_ECHO: {
38321                 /* echo */
38322                 int var = 0, enc = 0;
38323                 const char *var_val = NULL;
38324                 stat_cache_entry *sce = NULL;
38325 -               
38326 -               struct { 
38327 +
38328 +               struct {
38329                         const char *var;
38330 -                       enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI, 
38331 +                       enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI,
38332                                         SSI_ECHO_LAST_MODIFIED, SSI_ECHO_USER_NAME } type;
38333                 } echovars[] = {
38334                         { "DATE_GMT",      SSI_ECHO_DATE_GMT },
38335 @@ -339,27 +340,27 @@
38336                         { "DOCUMENT_URI",  SSI_ECHO_DOCUMENT_URI },
38337                         { "LAST_MODIFIED", SSI_ECHO_LAST_MODIFIED },
38338                         { "USER_NAME",     SSI_ECHO_USER_NAME },
38339 -                       
38340 +
38341                         { NULL, SSI_ECHO_UNSET }
38342                 };
38343 -               
38344 -               struct { 
38345 +
38346 +               struct {
38347                         const char *var;
38348                         enum { SSI_ENC_UNSET, SSI_ENC_URL, SSI_ENC_NONE, SSI_ENC_ENTITY } type;
38349                 } encvars[] = {
38350                         { "url",          SSI_ENC_URL },
38351                         { "none",         SSI_ENC_NONE },
38352                         { "entity",       SSI_ENC_ENTITY },
38353 -                       
38354 +
38355                         { NULL, SSI_ENC_UNSET }
38356                 };
38357 -               
38358 +
38359                 for (i = 2; i < n; i += 2) {
38360                         if (0 == strcmp(l[i], "var")) {
38361                                 int j;
38362 -                               
38363 +
38364                                 var_val = l[i+1];
38365 -                               
38366 +
38367                                 for (j = 0; echovars[j].var; j++) {
38368                                         if (0 == strcmp(l[i+1], echovars[j].var)) {
38369                                                 var = echovars[j].type;
38370 @@ -368,7 +369,7 @@
38371                                 }
38372                         } else if (0 == strcmp(l[i], "encoding")) {
38373                                 int j;
38374 -                               
38375 +
38376                                 for (j = 0; encvars[j].var; j++) {
38377                                         if (0 == strcmp(l[i+1], encvars[j].var)) {
38378                                                 enc = encvars[j].type;
38379 @@ -377,26 +378,26 @@
38380                                 }
38381                         } else {
38382                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38383 -                                               "ssi: unknow attribute for ", 
38384 +                                               "ssi: unknow attribute for ",
38385                                                 l[1], l[i]);
38386                         }
38387                 }
38388 -               
38389 +
38390                 if (p->if_is_false) break;
38391 -               
38392 +
38393                 if (!var_val) {
38394                         log_error_write(srv, __FILE__, __LINE__, "sss",
38395 -                                       "ssi: ", 
38396 +                                       "ssi: ",
38397                                         l[1], "var is missing");
38398                         break;
38399                 }
38400  
38401                 stat_cache_get_entry(srv, con, con->physical.path, &sce);
38402 -               
38403 +
38404                 switch(var) {
38405                 case SSI_ECHO_USER_NAME: {
38406                         struct passwd *pw;
38407 -                       
38408 +
38409                         b = chunkqueue_get_append_buffer(con->write_queue);
38410  #ifdef HAVE_PWD_H
38411                         if (NULL == (pw = getpwuid(sce->st.st_uid))) {
38412 @@ -411,7 +412,7 @@
38413                 }
38414                 case SSI_ECHO_LAST_MODIFIED:    {
38415                         time_t t = sce->st.st_mtime;
38416 -                       
38417 +
38418                         b = chunkqueue_get_append_buffer(con->write_queue);
38419                         if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
38420                                 buffer_copy_string(b, "(none)");
38421 @@ -422,7 +423,7 @@
38422                 }
38423                 case SSI_ECHO_DATE_LOCAL: {
38424                         time_t t = time(NULL);
38425 -                       
38426 +
38427                         b = chunkqueue_get_append_buffer(con->write_queue);
38428                         if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
38429                                 buffer_copy_string(b, "(none)");
38430 @@ -433,7 +434,7 @@
38431                 }
38432                 case SSI_ECHO_DATE_GMT: {
38433                         time_t t = time(NULL);
38434 -                       
38435 +
38436                         b = chunkqueue_get_append_buffer(con->write_queue);
38437                         if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, gmtime(&t))) {
38438                                 buffer_copy_string(b, "(none)");
38439 @@ -444,7 +445,7 @@
38440                 }
38441                 case SSI_ECHO_DOCUMENT_NAME: {
38442                         char *sl;
38443 -                       
38444 +
38445                         b = chunkqueue_get_append_buffer(con->write_queue);
38446                         if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
38447                                 buffer_copy_string_buffer(b, con->physical.path);
38448 @@ -461,15 +462,15 @@
38449                 default: {
38450                         data_string *ds;
38451                         /* check if it is a cgi-var */
38452 -                       
38453 +
38454                         b = chunkqueue_get_append_buffer(con->write_queue);
38455 -                       
38456 +
38457                         if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, var_val))) {
38458                                 buffer_copy_string_buffer(b, ds->value);
38459                         } else {
38460                                 buffer_copy_string(b, "(none)");
38461                         }
38462 -                       
38463 +
38464                         break;
38465                 }
38466                 }
38467 @@ -481,7 +482,7 @@
38468                 const char * file_path = NULL, *virt_path = NULL;
38469                 struct stat st;
38470                 char *sl;
38471 -               
38472 +
38473                 for (i = 2; i < n; i += 2) {
38474                         if (0 == strcmp(l[i], "file")) {
38475                                 file_path = l[i+1];
38476 @@ -489,28 +490,28 @@
38477                                 virt_path = l[i+1];
38478                         } else {
38479                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38480 -                                               "ssi: unknow attribute for ", 
38481 +                                               "ssi: unknow attribute for ",
38482                                                 l[1], l[i]);
38483                         }
38484                 }
38485 -               
38486 +
38487                 if (!file_path && !virt_path) {
38488                         log_error_write(srv, __FILE__, __LINE__, "sss",
38489 -                                       "ssi: ", 
38490 +                                       "ssi: ",
38491                                         l[1], "file or virtual are missing");
38492                         break;
38493                 }
38494 -               
38495 +
38496                 if (file_path && virt_path) {
38497                         log_error_write(srv, __FILE__, __LINE__, "sss",
38498 -                                       "ssi: ", 
38499 +                                       "ssi: ",
38500                                         l[1], "only one of file and virtual is allowed here");
38501                         break;
38502                 }
38503 -               
38504 -               
38505 +
38506 +
38507                 if (p->if_is_false) break;
38508 -               
38509 +
38510                 if (file_path) {
38511                         /* current doc-root */
38512                         if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
38513 @@ -519,46 +520,46 @@
38514                                 buffer_copy_string_len(p->stat_fn, con->physical.path->ptr, sl - con->physical.path->ptr + 1);
38515                         }
38516  
38517 -                       buffer_copy_string(srv->tmp_buf, file_path); 
38518 +                       buffer_copy_string(srv->tmp_buf, file_path);
38519                         buffer_urldecode_path(srv->tmp_buf);
38520 -                       buffer_path_simplify(srv->tmp_buf, srv->tmp_buf); 
38521 -                       buffer_append_string_buffer(p->stat_fn, srv->tmp_buf); 
38522 +                       buffer_path_simplify(srv->tmp_buf, srv->tmp_buf);
38523 +                       buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
38524                 } else {
38525                         /* virtual */
38526 -                       
38527 +
38528                         if (virt_path[0] == '/') {
38529                                 buffer_copy_string(p->stat_fn, virt_path);
38530                         } else {
38531                                 /* there is always a / */
38532                                 sl = strrchr(con->uri.path->ptr, '/');
38533 -                               
38534 +
38535                                 buffer_copy_string_len(p->stat_fn, con->uri.path->ptr, sl - con->uri.path->ptr + 1);
38536                                 buffer_append_string(p->stat_fn, virt_path);
38537                         }
38538 -                       
38539 +
38540                         buffer_urldecode_path(p->stat_fn);
38541                         buffer_path_simplify(srv->tmp_buf, p->stat_fn);
38542 -                       
38543 +
38544                         /* we have an uri */
38545 -                       
38546 +
38547                         buffer_copy_string_buffer(p->stat_fn, con->physical.doc_root);
38548                         buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
38549                 }
38550 -               
38551 +
38552                 if (0 == stat(p->stat_fn->ptr, &st)) {
38553                         time_t t = st.st_mtime;
38554 -                       
38555 +
38556                         switch (ssicmd) {
38557                         case SSI_FSIZE:
38558                                 b = chunkqueue_get_append_buffer(con->write_queue);
38559                                 if (p->sizefmt) {
38560                                         int j = 0;
38561                                         const char *abr[] = { " B", " kB", " MB", " GB", " TB", NULL };
38562 -                                       
38563 +
38564                                         off_t s = st.st_size;
38565 -                                       
38566 +
38567                                         for (j = 0; s > 1024 && abr[j+1]; s /= 1024, j++);
38568 -                                       
38569 +
38570                                         buffer_copy_off_t(b, s);
38571                                         buffer_append_string(b, abr[j]);
38572                                 } else {
38573 @@ -579,7 +580,7 @@
38574                         }
38575                 } else {
38576                         log_error_write(srv, __FILE__, __LINE__, "sbs",
38577 -                                       "ssi: stating failed ", 
38578 +                                       "ssi: stating failed ",
38579                                         p->stat_fn, strerror(errno));
38580                 }
38581                 break;
38582 @@ -593,33 +594,33 @@
38583                                 val = l[i+1];
38584                         } else {
38585                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38586 -                                               "ssi: unknow attribute for ", 
38587 +                                               "ssi: unknow attribute for ",
38588                                                 l[1], l[i]);
38589                         }
38590                 }
38591 -               
38592 +
38593                 if (p->if_is_false) break;
38594 -               
38595 +
38596                 if (key && val) {
38597                         data_string *ds;
38598 -                       
38599 +
38600                         if (NULL == (ds = (data_string *)array_get_unused_element(p->ssi_vars, TYPE_STRING))) {
38601                                 ds = data_string_init();
38602                         }
38603                         buffer_copy_string(ds->key,   key);
38604                         buffer_copy_string(ds->value, val);
38605 -                       
38606 +
38607                         array_insert_unique(p->ssi_vars, (data_unset *)ds);
38608                 } else {
38609                         log_error_write(srv, __FILE__, __LINE__, "sss",
38610 -                                       "ssi: var and value have to be set in", 
38611 +                                       "ssi: var and value have to be set in",
38612                                         l[0], l[1]);
38613                 }
38614                 break;
38615         }
38616 -       case SSI_CONFIG: 
38617 +       case SSI_CONFIG:
38618                 if (p->if_is_false) break;
38619 -               
38620 +
38621                 for (i = 2; i < n; i += 2) {
38622                         if (0 == strcmp(l[i], "timefmt")) {
38623                                 buffer_copy_string(p->timefmt, l[i+1]);
38624 @@ -632,63 +633,65 @@
38625                                         log_error_write(srv, __FILE__, __LINE__, "sssss",
38626                                                         "ssi: unknow value for attribute '",
38627                                                         l[i],
38628 -                                                       "' for ", 
38629 +                                                       "' for ",
38630                                                         l[1], l[i+1]);
38631                                 }
38632                         } else {
38633                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38634 -                                               "ssi: unknow attribute for ", 
38635 +                                               "ssi: unknow attribute for ",
38636                                                 l[1], l[i]);
38637                         }
38638                 }
38639                 break;
38640         case SSI_PRINTENV:
38641                 if (p->if_is_false) break;
38642 -               
38643 +
38644                 b = chunkqueue_get_append_buffer(con->write_queue);
38645                 buffer_copy_string(b, "<pre>");
38646                 for (i = 0; i < p->ssi_vars->used; i++) {
38647                         data_string *ds = (data_string *)p->ssi_vars->data[p->ssi_vars->sorted[i]];
38648 -                       
38649 +
38650                         buffer_append_string_buffer(b, ds->key);
38651                         buffer_append_string(b, ": ");
38652                         buffer_append_string_buffer(b, ds->value);
38653                         buffer_append_string(b, "<br />");
38654 -                                       
38655 +
38656                 }
38657                 buffer_append_string(b, "</pre>");
38658 -               
38659 +
38660                 break;
38661         case SSI_EXEC: {
38662 +#ifndef _WIN32
38663 +
38664                 const char *cmd = NULL;
38665                 pid_t pid;
38666                 int from_exec_fds[2];
38667 -               
38668 +
38669                 for (i = 2; i < n; i += 2) {
38670                         if (0 == strcmp(l[i], "cmd")) {
38671                                 cmd = l[i+1];
38672                         } else {
38673                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38674 -                                               "ssi: unknow attribute for ", 
38675 +                                               "ssi: unknow attribute for ",
38676                                                 l[1], l[i]);
38677                         }
38678                 }
38679 -               
38680 +
38681                 if (p->if_is_false) break;
38682 -               
38683 +
38684                 /* create a return pipe and send output to the html-page
38685 -                * 
38686 -                * as exec is assumed evil it is implemented synchronously 
38687 +                *
38688 +                * as exec is assumed evil it is implemented synchronously
38689                  */
38690 -               
38691 +
38692                 if (!cmd) break;
38693 -#ifdef HAVE_FORK       
38694 +
38695                 if (pipe(from_exec_fds)) {
38696 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
38697 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
38698                                         "pipe failed: ", strerror(errno));
38699                         return -1;
38700                 }
38701 -       
38702 +
38703                 /* fork, execve */
38704                 switch (pid = fork()) {
38705                 case 0: {
38706 @@ -698,14 +701,14 @@
38707                         close(from_exec_fds[1]);
38708                         /* not needed */
38709                         close(from_exec_fds[0]);
38710 -                       
38711 +
38712                         /* close stdin */
38713                         close(STDIN_FILENO);
38714 -               
38715 +
38716                         execl("/bin/sh", "sh", "-c", cmd, NULL);
38717 -                       
38718 +
38719                         log_error_write(srv, __FILE__, __LINE__, "sss", "spawing exec failed:", strerror(errno), cmd);
38720 -               
38721 +
38722                         /* */
38723                         SEGFAULT();
38724                         break;
38725 @@ -718,9 +721,9 @@
38726                         /* father */
38727                         int status;
38728                         ssize_t r;
38729 -                       
38730 +
38731                         close(from_exec_fds[1]);
38732 -                       
38733 +
38734                         /* wait for the client to end */
38735                         if (-1 == waitpid(pid, &status, 0)) {
38736                                 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed:", strerror(errno));
38737 @@ -730,7 +733,7 @@
38738  
38739                                 while(1) {
38740                                         if (ioctl(from_exec_fds[0], FIONREAD, &toread)) {
38741 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
38742 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
38743                                                         "unexpected end-of-file (perhaps the ssi-exec process died)");
38744                                                 return -1;
38745                                         }
38746 @@ -738,10 +741,10 @@
38747                                         if (toread > 0) {
38748                                                 b = chunkqueue_get_append_buffer(con->write_queue);
38749  
38750 -                                               buffer_prepare_copy(b, toread + 1); 
38751 +                                               buffer_prepare_copy(b, toread + 1);
38752  
38753                                                 if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) {
38754 -                                                       /* read failed */ 
38755 +                                                       /* read failed */
38756                                                         break;
38757                                                 } else {
38758                                                         b->used = r;
38759 @@ -755,59 +758,58 @@
38760                                 log_error_write(srv, __FILE__, __LINE__, "s", "process exited abnormally");
38761                         }
38762                         close(from_exec_fds[0]);
38763 -                       
38764 +
38765                         break;
38766                 }
38767                 }
38768  #else
38769 -
38770                 return -1;
38771  #endif
38772 -               
38773 +
38774                 break;
38775         }
38776         case SSI_IF: {
38777                 const char *expr = NULL;
38778 -               
38779 +
38780                 for (i = 2; i < n; i += 2) {
38781                         if (0 == strcmp(l[i], "expr")) {
38782                                 expr = l[i+1];
38783                         } else {
38784                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38785 -                                               "ssi: unknow attribute for ", 
38786 +                                               "ssi: unknow attribute for ",
38787                                                 l[1], l[i]);
38788                         }
38789                 }
38790 -               
38791 +
38792                 if (!expr) {
38793                         log_error_write(srv, __FILE__, __LINE__, "sss",
38794 -                                       "ssi: ", 
38795 +                                       "ssi: ",
38796                                         l[1], "expr missing");
38797                         break;
38798                 }
38799 -               
38800 +
38801                 if ((!p->if_is_false) &&
38802 -                   ((p->if_is_false_level == 0) || 
38803 +                   ((p->if_is_false_level == 0) ||
38804                      (p->if_level < p->if_is_false_level))) {
38805                         switch (ssi_eval_expr(srv, con, p, expr)) {
38806                         case -1:
38807 -                       case 0: 
38808 -                               p->if_is_false = 1; 
38809 +                       case 0:
38810 +                               p->if_is_false = 1;
38811                                 p->if_is_false_level = p->if_level;
38812                                 break;
38813 -                       case 1: 
38814 -                               p->if_is_false = 0; 
38815 +                       case 1:
38816 +                               p->if_is_false = 0;
38817                                 break;
38818                         }
38819                 }
38820 -               
38821 +
38822                 p->if_level++;
38823 -               
38824 +
38825                 break;
38826         }
38827         case SSI_ELSE:
38828                 p->if_level--;
38829 -               
38830 +
38831                 if (p->if_is_false) {
38832                         if ((p->if_level == p->if_is_false_level) &&
38833                             (p->if_is_false_endif == 0)) {
38834 @@ -815,11 +817,11 @@
38835                         }
38836                 } else {
38837                         p->if_is_false = 1;
38838 -                       
38839 +
38840                         p->if_is_false_level = p->if_level;
38841                 }
38842                 p->if_level++;
38843 -               
38844 +
38845                 break;
38846         case SSI_ELIF: {
38847                 const char *expr = NULL;
38848 @@ -828,52 +830,52 @@
38849                                 expr = l[i+1];
38850                         } else {
38851                                 log_error_write(srv, __FILE__, __LINE__, "sss",
38852 -                                               "ssi: unknow attribute for ", 
38853 +                                               "ssi: unknow attribute for ",
38854                                                 l[1], l[i]);
38855                         }
38856                 }
38857 -               
38858 +
38859                 if (!expr) {
38860                         log_error_write(srv, __FILE__, __LINE__, "sss",
38861 -                                       "ssi: ", 
38862 +                                       "ssi: ",
38863                                         l[1], "expr missing");
38864                         break;
38865                 }
38866 -               
38867 +
38868                 p->if_level--;
38869 -               
38870 +
38871                 if (p->if_level == p->if_is_false_level) {
38872                         if ((p->if_is_false) &&
38873                             (p->if_is_false_endif == 0)) {
38874                                 switch (ssi_eval_expr(srv, con, p, expr)) {
38875                                 case -1:
38876 -                               case 0: 
38877 -                                       p->if_is_false = 1; 
38878 +                               case 0:
38879 +                                       p->if_is_false = 1;
38880                                         p->if_is_false_level = p->if_level;
38881                                         break;
38882 -                               case 1: 
38883 -                                       p->if_is_false = 0; 
38884 +                               case 1:
38885 +                                       p->if_is_false = 0;
38886                                         break;
38887                                 }
38888                         } else {
38889 -                               p->if_is_false = 1; 
38890 +                               p->if_is_false = 1;
38891                                 p->if_is_false_level = p->if_level;
38892                                 p->if_is_false_endif = 1;
38893                         }
38894                 }
38895 -               
38896 +
38897                 p->if_level++;
38898 -               
38899 +
38900                 break;
38901         }
38902         case SSI_ENDIF:
38903                 p->if_level--;
38904 -               
38905 +
38906                 if (p->if_level == p->if_is_false_level) {
38907                         p->if_is_false = 0;
38908                         p->if_is_false_endif = 0;
38909                 }
38910 -                       
38911 +
38912                 break;
38913         default:
38914                 log_error_write(srv, __FILE__, __LINE__, "ss",
38915 @@ -881,41 +883,41 @@
38916                                 l[1]);
38917                 break;
38918         }
38919 -       
38920 +
38921         return 0;
38922 -       
38923 +
38924  }
38925  
38926  static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) {
38927         stream s;
38928  #ifdef  HAVE_PCRE_H
38929         int i, n;
38930 -       
38931 +
38932  #define N 10
38933         int ovec[N * 3];
38934  #endif
38935 -       
38936 +
38937         /* get a stream to the file */
38938 -       
38939 +
38940         array_reset(p->ssi_vars);
38941         array_reset(p->ssi_cgi_env);
38942         buffer_copy_string(p->timefmt, "%a, %d %b %Y %H:%M:%S %Z");
38943         p->sizefmt = 0;
38944         build_ssi_cgi_vars(srv, con, p);
38945         p->if_is_false = 0;
38946 -       
38947 +
38948         if (-1 == stream_open(&s, con->physical.path)) {
38949                 log_error_write(srv, __FILE__, __LINE__, "sb",
38950                                 "stream-open: ", con->physical.path);
38951                 return -1;
38952         }
38953 -       
38954 -       
38955 +
38956 +
38957         /**
38958 -        * <!--#element attribute=value attribute=value ... --> 
38959 -        * 
38960 +        * <!--#element attribute=value attribute=value ... -->
38961 +        *
38962          * config       DONE
38963 -        *   errmsg     -- missing 
38964 +        *   errmsg     -- missing
38965          *   sizefmt    DONE
38966          *   timefmt    DONE
38967          * echo         DONE
38968 @@ -937,13 +939,13 @@
38969          * set          DONE
38970          *   var        DONE
38971          *   value      DONE
38972 -        * 
38973 +        *
38974          * if           DONE
38975          * elif         DONE
38976          * else         DONE
38977          * endif        DONE
38978 -        * 
38979 -        * 
38980 +        *
38981 +        *
38982          * expressions
38983          * AND, OR      DONE
38984          * comp         DONE
38985 @@ -951,118 +953,115 @@
38986          * $...         DONE
38987          * '...'        DONE
38988          * ( ... )      DONE
38989 -        * 
38990 -        * 
38991 -        * 
38992 +        *
38993 +        *
38994 +        *
38995          * ** all DONE **
38996 -        * DATE_GMT 
38997 -        *   The current date in Greenwich Mean Time. 
38998 -        * DATE_LOCAL 
38999 -        *   The current date in the local time zone. 
39000 -        * DOCUMENT_NAME 
39001 -        *   The filename (excluding directories) of the document requested by the user. 
39002 -        * DOCUMENT_URI 
39003 -        *   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. 
39004 -        * LAST_MODIFIED 
39005 -        *   The last modification date of the document requested by the user. 
39006 -        * USER_NAME 
39007 +        * DATE_GMT
39008 +        *   The current date in Greenwich Mean Time.
39009 +        * DATE_LOCAL
39010 +        *   The current date in the local time zone.
39011 +        * DOCUMENT_NAME
39012 +        *   The filename (excluding directories) of the document requested by the user.
39013 +        * DOCUMENT_URI
39014 +        *   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.
39015 +        * LAST_MODIFIED
39016 +        *   The last modification date of the document requested by the user.
39017 +        * USER_NAME
39018          *   Contains the owner of the file which included it.
39019 -        * 
39020 +        *
39021          */
39022 -#ifdef HAVE_PCRE_H     
39023 +#ifdef HAVE_PCRE_H
39024         for (i = 0; (n = pcre_exec(p->ssi_regex, NULL, s.start, s.size, i, 0, ovec, N * 3)) > 0; i = ovec[1]) {
39025                 const char **l;
39026                 /* take everything from last offset to current match pos */
39027 -               
39028 +
39029                 if (!p->if_is_false) chunkqueue_append_file(con->write_queue, con->physical.path, i, ovec[0] - i);
39030 -               
39031 +
39032                 pcre_get_substring_list(s.start, ovec, n, &l);
39033                 process_ssi_stmt(srv, con, p, l, n);
39034                 pcre_free_substring_list(l);
39035         }
39036 -       
39037 +
39038         switch(n) {
39039         case PCRE_ERROR_NOMATCH:
39040                 /* copy everything/the rest */
39041                 chunkqueue_append_file(con->write_queue, con->physical.path, i, s.size - i);
39042 -               
39043 +
39044                 break;
39045         default:
39046                 log_error_write(srv, __FILE__, __LINE__, "sd",
39047                                 "execution error while matching: ", n);
39048                 break;
39049         }
39050 -#endif 
39051 -       
39052 -       
39053 +#endif
39054 +
39055 +
39056         stream_close(&s);
39057 -       
39058 +
39059         con->file_started  = 1;
39060         con->file_finished = 1;
39061 -       
39062 +
39063         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
39064 -       
39065 +
39066         /* reset physical.path */
39067         buffer_reset(con->physical.path);
39068 -       
39069 +
39070         return 0;
39071  }
39072  
39073 -#define PATCH(x) \
39074 -       p->conf.x = s->x;
39075  static int mod_ssi_patch_connection(server *srv, connection *con, plugin_data *p) {
39076         size_t i, j;
39077         plugin_config *s = p->config_storage[0];
39078 -       
39079 -       PATCH(ssi_extension);
39080 -       
39081 +
39082 +       PATCH_OPTION(ssi_extension);
39083 +
39084         /* skip the first, the global context */
39085         for (i = 1; i < srv->config_context->used; i++) {
39086                 data_config *dc = (data_config *)srv->config_context->data[i];
39087                 s = p->config_storage[i];
39088 -               
39089 +
39090                 /* condition didn't match */
39091                 if (!config_check_cond(srv, con, dc)) continue;
39092 -               
39093 +
39094                 /* merge config */
39095                 for (j = 0; j < dc->value->used; j++) {
39096                         data_unset *du = dc->value->data[j];
39097 -                       
39098 +
39099                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssi.extension"))) {
39100 -                               PATCH(ssi_extension);
39101 +                               PATCH_OPTION(ssi_extension);
39102                         }
39103                 }
39104         }
39105 -       
39106 +
39107         return 0;
39108  }
39109 -#undef PATCH
39110  
39111  URIHANDLER_FUNC(mod_ssi_physical_path) {
39112         plugin_data *p = p_d;
39113         size_t k;
39114 -       
39115 +
39116         if (con->physical.path->used == 0) return HANDLER_GO_ON;
39117 -       
39118 +
39119         mod_ssi_patch_connection(srv, con, p);
39120 -       
39121 +
39122         for (k = 0; k < p->conf.ssi_extension->used; k++) {
39123                 data_string *ds = (data_string *)p->conf.ssi_extension->data[k];
39124 -               
39125 +
39126                 if (ds->value->used == 0) continue;
39127 -               
39128 +
39129                 if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
39130                         /* handle ssi-request */
39131 -                       
39132 +
39133                         if (mod_ssi_handle_request(srv, con, p)) {
39134                                 /* on error */
39135                                 con->http_status = 500;
39136                         }
39137 -                       
39138 +
39139                         return HANDLER_FINISHED;
39140                 }
39141         }
39142 -       
39143 +
39144         /* not found */
39145         return HANDLER_GO_ON;
39146  }
39147 @@ -1072,13 +1071,13 @@
39148  int mod_ssi_plugin_init(plugin *p) {
39149         p->version     = LIGHTTPD_VERSION_ID;
39150         p->name        = buffer_init_string("ssi");
39151 -       
39152 +
39153         p->init        = mod_ssi_init;
39154         p->handle_subrequest_start = mod_ssi_physical_path;
39155         p->set_defaults  = mod_ssi_set_defaults;
39156         p->cleanup     = mod_ssi_free;
39157 -       
39158 +
39159         p->data        = NULL;
39160 -       
39161 +
39162         return 0;
39163  }
39164 --- ../lighttpd-1.4.11/src/mod_ssi.h    2005-08-11 01:26:39.000000000 +0300
39165 +++ lighttpd-1.4.12/src/mod_ssi.h       2006-07-16 00:26:04.000000000 +0300
39166 @@ -19,23 +19,23 @@
39167  
39168  typedef struct {
39169         PLUGIN_DATA;
39170 -       
39171 -#ifdef HAVE_PCRE_H     
39172 +
39173 +#ifdef HAVE_PCRE_H
39174         pcre *ssi_regex;
39175 -#endif 
39176 +#endif
39177         buffer *timefmt;
39178         int sizefmt;
39179 -       
39180 +
39181         buffer *stat_fn;
39182 -       
39183 +
39184         array *ssi_vars;
39185         array *ssi_cgi_env;
39186 -       
39187 +
39188         int if_level, if_is_false_level, if_is_false, if_is_false_endif;
39189 -       
39190 +
39191         plugin_config **config_storage;
39192 -       
39193 -       plugin_config conf; 
39194 +
39195 +       plugin_config conf;
39196  } plugin_data;
39197  
39198  int ssi_eval_expr(server *srv, connection *con, plugin_data *p, const char *expr);
39199 --- ../lighttpd-1.4.11/src/mod_ssi_expr.c       2005-08-11 01:26:48.000000000 +0300
39200 +++ lighttpd-1.4.12/src/mod_ssi_expr.c  2006-07-16 00:26:04.000000000 +0300
39201 @@ -11,9 +11,9 @@
39202         const char *input;
39203         size_t offset;
39204         size_t size;
39205 -       
39206 +
39207         int line_pos;
39208 -       
39209 +
39210         int in_key;
39211         int in_brace;
39212         int in_cond;
39213 @@ -21,15 +21,15 @@
39214  
39215  ssi_val_t *ssi_val_init() {
39216         ssi_val_t *s;
39217 -       
39218 +
39219         s = calloc(1, sizeof(*s));
39220 -       
39221 +
39222         return s;
39223  }
39224  
39225  void ssi_val_free(ssi_val_t *s) {
39226         if (s->str) buffer_free(s->str);
39227 -       
39228 +
39229         free(s);
39230  }
39231  
39232 @@ -45,175 +45,175 @@
39233                               ssi_tokenizer_t *t, int *token_id, buffer *token) {
39234         int tid = 0;
39235         size_t i;
39236 -       
39237 +
39238         UNUSED(con);
39239  
39240         for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
39241                 char c = t->input[t->offset];
39242                 data_string *ds;
39243 -               
39244 +
39245                 switch (c) {
39246 -               case '=': 
39247 +               case '=':
39248                         tid = TK_EQ;
39249 -                       
39250 +
39251                         t->offset++;
39252                         t->line_pos++;
39253 -                       
39254 +
39255                         buffer_copy_string(token, "(=)");
39256 -                       
39257 +
39258                         break;
39259                 case '>':
39260                         if (t->input[t->offset + 1] == '=') {
39261                                 t->offset += 2;
39262                                 t->line_pos += 2;
39263 -                               
39264 +
39265                                 tid = TK_GE;
39266 -                               
39267 +
39268                                 buffer_copy_string(token, "(>=)");
39269                         } else {
39270                                 t->offset += 1;
39271                                 t->line_pos += 1;
39272 -                               
39273 +
39274                                 tid = TK_GT;
39275 -                               
39276 +
39277                                 buffer_copy_string(token, "(>)");
39278                         }
39279 -                       
39280 +
39281                         break;
39282                 case '<':
39283                         if (t->input[t->offset + 1] == '=') {
39284                                 t->offset += 2;
39285                                 t->line_pos += 2;
39286 -                               
39287 +
39288                                 tid = TK_LE;
39289 -                               
39290 +
39291                                 buffer_copy_string(token, "(<=)");
39292                         } else {
39293                                 t->offset += 1;
39294                                 t->line_pos += 1;
39295 -                               
39296 +
39297                                 tid = TK_LT;
39298 -                               
39299 +
39300                                 buffer_copy_string(token, "(<)");
39301                         }
39302 -                       
39303 +
39304                         break;
39305 -                       
39306 +
39307                 case '!':
39308                         if (t->input[t->offset + 1] == '=') {
39309                                 t->offset += 2;
39310                                 t->line_pos += 2;
39311 -                               
39312 +
39313                                 tid = TK_NE;
39314 -                               
39315 +
39316                                 buffer_copy_string(token, "(!=)");
39317                         } else {
39318                                 t->offset += 1;
39319                                 t->line_pos += 1;
39320 -                               
39321 +
39322                                 tid = TK_NOT;
39323 -                               
39324 +
39325                                 buffer_copy_string(token, "(!)");
39326                         }
39327 -                       
39328 +
39329                         break;
39330                 case '&':
39331                         if (t->input[t->offset + 1] == '&') {
39332                                 t->offset += 2;
39333                                 t->line_pos += 2;
39334 -                               
39335 +
39336                                 tid = TK_AND;
39337 -                               
39338 +
39339                                 buffer_copy_string(token, "(&&)");
39340                         } else {
39341 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
39342 -                                               "pos:", t->line_pos, 
39343 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
39344 +                                               "pos:", t->line_pos,
39345                                                 "missing second &");
39346                                 return -1;
39347                         }
39348 -                       
39349 +
39350                         break;
39351                 case '|':
39352                         if (t->input[t->offset + 1] == '|') {
39353                                 t->offset += 2;
39354                                 t->line_pos += 2;
39355 -                               
39356 +
39357                                 tid = TK_OR;
39358 -                               
39359 +
39360                                 buffer_copy_string(token, "(||)");
39361                         } else {
39362 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
39363 -                                               "pos:", t->line_pos, 
39364 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
39365 +                                               "pos:", t->line_pos,
39366                                                 "missing second |");
39367                                 return -1;
39368                         }
39369 -                       
39370 +
39371                         break;
39372                 case '\t':
39373                 case ' ':
39374                         t->offset++;
39375                         t->line_pos++;
39376                         break;
39377 -                       
39378 +
39379                 case '\'':
39380                         /* search for the terminating " */
39381                         for (i = 1; t->input[t->offset + i] && t->input[t->offset + i] != '\'';  i++);
39382 -                       
39383 +
39384                         if (t->input[t->offset + i]) {
39385                                 tid = TK_VALUE;
39386 -                               
39387 +
39388                                 buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
39389 -                               
39390 +
39391                                 t->offset += i + 1;
39392                                 t->line_pos += i + 1;
39393                         } else {
39394                                 /* ERROR */
39395 -                               
39396 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
39397 -                                               "pos:", t->line_pos, 
39398 +
39399 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
39400 +                                               "pos:", t->line_pos,
39401                                                 "missing closing quote");
39402 -                               
39403 +
39404                                 return -1;
39405                         }
39406 -                       
39407 +
39408                         break;
39409                 case '(':
39410                         t->offset++;
39411                         t->in_brace++;
39412 -                               
39413 +
39414                         tid = TK_LPARAN;
39415 -                               
39416 +
39417                         buffer_copy_string(token, "(");
39418                         break;
39419                 case ')':
39420                         t->offset++;
39421                         t->in_brace--;
39422 -                               
39423 +
39424                         tid = TK_RPARAN;
39425 -                               
39426 +
39427                         buffer_copy_string(token, ")");
39428                         break;
39429                 case '$':
39430                         if (t->input[t->offset + 1] == '{') {
39431                                 for (i = 2; t->input[t->offset + i] && t->input[t->offset + i] != '}';  i++);
39432 -                               
39433 +
39434                                 if (t->input[t->offset + i] != '}') {
39435 -                                       log_error_write(srv, __FILE__, __LINE__, "sds", 
39436 -                                                       "pos:", t->line_pos, 
39437 +                                       log_error_write(srv, __FILE__, __LINE__, "sds",
39438 +                                                       "pos:", t->line_pos,
39439                                                         "missing closing quote");
39440 -                                       
39441 +
39442                                         return -1;
39443                                 }
39444 -                               
39445 +
39446                                 buffer_copy_string_len(token, t->input + t->offset + 2, i-3);
39447                         } else {
39448                                 for (i = 1; isalpha(t->input[t->offset + i]) || t->input[t->offset + i] == '_';  i++);
39449 -                               
39450 +
39451                                 buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
39452                         }
39453 -                       
39454 +
39455                         tid = TK_VALUE;
39456 -                       
39457 +
39458                         if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, token->ptr))) {
39459                                 buffer_copy_string_buffer(token, ds->value);
39460                         } else if (NULL != (ds = (data_string *)array_get_element(p->ssi_vars, token->ptr))) {
39461 @@ -221,16 +221,16 @@
39462                         } else {
39463                                 buffer_copy_string(token, "");
39464                         }
39465 -                               
39466 +
39467                         t->offset += i;
39468                         t->line_pos += i;
39469 -                       
39470 +
39471                         break;
39472                 default:
39473                         for (i = 0; isgraph(t->input[t->offset + i]);  i++) {
39474                                 char d = t->input[t->offset + i];
39475                                 switch(d) {
39476 -                               case ' ': 
39477 +                               case ' ':
39478                                 case '\t':
39479                                 case ')':
39480                                 case '(':
39481 @@ -244,25 +244,25 @@
39482                                         break;
39483                                 }
39484                         }
39485 -                       
39486 +
39487                         tid = TK_VALUE;
39488 -                               
39489 +
39490                         buffer_copy_string_len(token, t->input + t->offset, i);
39491 -                               
39492 +
39493                         t->offset += i;
39494                         t->line_pos += i;
39495 -                       
39496 +
39497                         break;
39498                 }
39499         }
39500 -                       
39501 +
39502         if (tid) {
39503                 *token_id = tid;
39504 -               
39505 +
39506                 return 1;
39507         } else if (t->offset < t->size) {
39508 -               log_error_write(srv, __FILE__, __LINE__, "sds", 
39509 -                               "pos:", t->line_pos, 
39510 +               log_error_write(srv, __FILE__, __LINE__, "sds",
39511 +                               "pos:", t->line_pos,
39512                                 "foobar");
39513         }
39514         return 0;
39515 @@ -275,50 +275,50 @@
39516         buffer *token;
39517         ssi_ctx_t context;
39518         int ret;
39519 -       
39520 +
39521         t.input = expr;
39522         t.offset = 0;
39523         t.size = strlen(expr);
39524         t.line_pos = 1;
39525 -       
39526 +
39527         t.in_key = 1;
39528         t.in_brace = 0;
39529         t.in_cond = 0;
39530 -       
39531 +
39532         context.ok = 1;
39533         context.srv = srv;
39534 -       
39535 +
39536         /* default context */
39537 -       
39538 +
39539         pParser = ssiexprparserAlloc( malloc );
39540         token = buffer_init();
39541         while((1 == (ret = ssi_expr_tokenizer(srv, con, p, &t, &token_id, token))) && context.ok) {
39542                 ssiexprparser(pParser, token_id, token, &context);
39543 -               
39544 +
39545                 token = buffer_init();
39546         }
39547         ssiexprparser(pParser, 0, token, &context);
39548         ssiexprparserFree(pParser, free );
39549 -       
39550 +
39551         buffer_free(token);
39552 -       
39553 +
39554         if (ret == -1) {
39555 -               log_error_write(srv, __FILE__, __LINE__, "s", 
39556 +               log_error_write(srv, __FILE__, __LINE__, "s",
39557                                 "expr parser failed");
39558                 return -1;
39559         }
39560 -       
39561 +
39562         if (context.ok == 0) {
39563 -               log_error_write(srv, __FILE__, __LINE__, "sds", 
39564 -                               "pos:", t.line_pos, 
39565 +               log_error_write(srv, __FILE__, __LINE__, "sds",
39566 +                               "pos:", t.line_pos,
39567                                 "parser failed somehow near here");
39568                 return -1;
39569         }
39570  #if 0
39571 -       log_error_write(srv, __FILE__, __LINE__, "ssd", 
39572 +       log_error_write(srv, __FILE__, __LINE__, "ssd",
39573                         "expr: ",
39574                         expr,
39575                         context.val.bo);
39576 -#endif 
39577 +#endif
39578         return context.val.bo;
39579  }
39580 --- ../lighttpd-1.4.11/src/mod_ssi_expr.h       2005-08-11 01:26:48.000000000 +0300
39581 +++ lighttpd-1.4.12/src/mod_ssi_expr.h  2006-07-16 00:26:04.000000000 +0300
39582 @@ -5,16 +5,16 @@
39583  
39584  typedef struct {
39585         enum { SSI_TYPE_UNSET, SSI_TYPE_BOOL, SSI_TYPE_STRING } type;
39586 -       
39587 +
39588         buffer *str;
39589         int     bo;
39590  } ssi_val_t;
39591  
39592  typedef struct {
39593         int     ok;
39594 -       
39595 +
39596         ssi_val_t val;
39597 -       
39598 +
39599         void   *srv;
39600  } ssi_ctx_t;
39601  
39602 --- ../lighttpd-1.4.11/src/mod_ssi_exprparser.c 2005-10-03 00:40:25.000000000 +0300
39603 +++ lighttpd-1.4.12/src/mod_ssi_exprparser.c    2006-07-17 22:02:23.000000000 +0300
39604 @@ -18,10 +18,10 @@
39605  /* Next is all token values, in a form suitable for use by makeheaders.
39606  ** This section will be null unless lemon is run with the -m switch.
39607  */
39608 -/* 
39609 +/*
39610  ** These constants (all generated automatically by the parser generator)
39611  ** specify the various kinds of tokens (terminals) that the parser
39612 -** understands. 
39613 +** understands.
39614  **
39615  ** Each symbol here is a terminal symbol in the grammar.
39616  */
39617 @@ -38,7 +38,7 @@
39618  **                       and nonterminals.  "int" is used otherwise.
39619  **    YYNOCODE           is a number of type YYCODETYPE which corresponds
39620  **                       to no legal terminal or nonterminal number.  This
39621 -**                       number is used to fill in empty slots of the hash 
39622 +**                       number is used to fill in empty slots of the hash
39623  **                       table.
39624  **    YYFALLBACK         If defined, this indicates that one or more tokens
39625  **                       have fall-back values which should be used if the
39626 @@ -47,7 +47,7 @@
39627  **                       and nonterminal numbers.  "unsigned char" is
39628  **                       used if there are fewer than 250 rules and
39629  **                       states combined.  "int" is used otherwise.
39630 -**    ssiexprparserTOKENTYPE     is the data type used for minor tokens given 
39631 +**    ssiexprparserTOKENTYPE     is the data type used for minor tokens given
39632  **                       directly to the parser from the tokenizer.
39633  **    YYMINORTYPE        is the data type used for all minor tokens.
39634  **                       This is typically a union of many types, one of
39635 @@ -91,7 +91,7 @@
39636  /* Next are that tables used to determine what action to take based on the
39637  ** current state and lookahead token.  These tables are used to implement
39638  ** functions that take a state number and lookahead value and return an
39639 -** action integer.  
39640 +** action integer.
39641  **
39642  ** Suppose the action integer is N.  Then the action is determined as
39643  ** follows
39644 @@ -116,7 +116,7 @@
39645  ** If the index value yy_shift_ofst[S]+X is out of range or if the value
39646  ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
39647  ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
39648 -** and that yy_default[S] should be used instead.  
39649 +** and that yy_default[S] should be used instead.
39650  **
39651  ** The formula above is for computing the action when the lookahead is
39652  ** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
39653 @@ -168,7 +168,7 @@
39654  
39655  /* The next table maps tokens into fallback tokens.  If a construct
39656  ** like the following:
39657 -** 
39658 +**
39659  **      %fallback ID X Y Z.
39660  **
39661  ** appears in the grammer, then ID becomes a fallback token for X, Y,
39662 @@ -219,10 +219,10 @@
39663  #endif /* NDEBUG */
39664  
39665  #ifndef NDEBUG
39666 -/* 
39667 +/*
39668  ** Turn parser tracing on by giving a stream to which to write the trace
39669  ** and a prompt to preface each trace message.  Tracing is turned off
39670 -** by making either argument NULL 
39671 +** by making either argument NULL
39672  **
39673  ** Inputs:
39674  ** <ul>
39675 @@ -247,7 +247,7 @@
39676  #ifndef NDEBUG
39677  /* For tracing shifts, the names of all terminals and nonterminals
39678  ** are required.  The following table supplies these names */
39679 -static const char *yyTokenName[] = { 
39680 +static const char *yyTokenName[] = {
39681    "$",             "AND",           "OR",            "EQ",          
39682    "NE",            "GT",            "GE",            "LT",          
39683    "LE",            "NOT",           "LPARAN",        "RPARAN",      
39684 @@ -295,7 +295,7 @@
39685  #endif
39686  }
39687  
39688 -/* 
39689 +/*
39690  ** This function allocates a new parser.
39691  ** The only argument is a pointer to a function which works like
39692  ** malloc.
39693 @@ -326,7 +326,7 @@
39694      /* Here is inserted the actions which take place when a
39695      ** terminal or non-terminal is destroyed.  This can happen
39696      ** when the symbol is popped from the stack during a
39697 -    ** reduce or during error processing or when a parser is 
39698 +    ** reduce or during error processing or when a parser is
39699      ** being destroyed before it is finished parsing.
39700      **
39701      ** Note: during a reduce, the only symbols destroyed are those
39702 @@ -379,7 +379,7 @@
39703    return yymajor;
39704  }
39705  
39706 -/* 
39707 +/*
39708  ** Deallocate and destroy a parser.  Destructors are all called for
39709  ** all stack elements before shutting the parser down.
39710  **
39711 @@ -415,7 +415,7 @@
39712  ){
39713    int i;
39714    int stateno = pParser->yystack[pParser->yyidx].stateno;
39715
39716 +
39717    /* if( pParser->yyidx<0 ) return YY_NO_ACTION;  */
39718    i = yy_shift_ofst[stateno];
39719    if( i==YY_SHIFT_USE_DFLT ){
39720 @@ -459,7 +459,7 @@
39721  ){
39722    int i;
39723    int stateno = pParser->yystack[pParser->yyidx].stateno;
39724
39725 +
39726    i = yy_reduce_ofst[stateno];
39727    if( i==YY_REDUCE_USE_DFLT ){
39728      return yy_default[stateno];
39729 @@ -559,7 +559,7 @@
39730    ssiexprparserARG_FETCH;
39731    yymsp = &yypParser->yystack[yypParser->yyidx];
39732  #ifndef NDEBUG
39733 -  if( yyTraceFILE && yyruleno>=0 
39734 +  if( yyTraceFILE && yyruleno>=0
39735          && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
39736      fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
39737        yyRuleName[yyruleno]);
39738 @@ -872,7 +872,7 @@
39739  #ifdef YYERRORSYMBOL
39740        /* A syntax error has occurred.
39741        ** The response to an error depends upon whether or not the
39742 -      ** grammar defines an error token "ERROR".  
39743 +      ** grammar defines an error token "ERROR".
39744        **
39745        ** This is what we do if the grammar does define ERROR:
39746        **
39747 --- ../lighttpd-1.4.11/src/mod_staticfile.c     2006-02-15 14:31:14.000000000 +0200
39748 +++ lighttpd-1.4.12/src/mod_staticfile.c        2006-07-16 00:26:03.000000000 +0300
39749 @@ -14,9 +14,11 @@
39750  #include "http_chunk.h"
39751  #include "response.h"
39752  
39753 +#include "sys-files.h"
39754 +#include "sys-strings.h"
39755  /**
39756   * this is a staticfile for a lighttpd plugin
39757 - * 
39758 + *
39759   */
39760  
39761  
39762 @@ -29,48 +31,48 @@
39763  
39764  typedef struct {
39765         PLUGIN_DATA;
39766 -       
39767 +
39768         buffer *range_buf;
39769 -       
39770 +
39771         plugin_config **config_storage;
39772 -       
39773 -       plugin_config conf; 
39774 +
39775 +       plugin_config conf;
39776  } plugin_data;
39777  
39778  /* init the plugin data */
39779  INIT_FUNC(mod_staticfile_init) {
39780         plugin_data *p;
39781 -       
39782 +
39783         p = calloc(1, sizeof(*p));
39784 -       
39785 +
39786         p->range_buf = buffer_init();
39787 -       
39788 +
39789         return p;
39790  }
39791  
39792 -/* detroy the plugin data */
39793 +/* destroy the plugin data */
39794  FREE_FUNC(mod_staticfile_free) {
39795         plugin_data *p = p_d;
39796 -       
39797 +
39798         UNUSED(srv);
39799  
39800         if (!p) return HANDLER_GO_ON;
39801 -       
39802 +
39803         if (p->config_storage) {
39804                 size_t i;
39805                 for (i = 0; i < srv->config_context->used; i++) {
39806                         plugin_config *s = p->config_storage[i];
39807 -                       
39808 +
39809                         array_free(s->exclude_ext);
39810 -                       
39811 +
39812                         free(s);
39813                 }
39814                 free(p->config_storage);
39815         }
39816         buffer_free(p->range_buf);
39817 -       
39818 +
39819         free(p);
39820 -       
39821 +
39822         return HANDLER_GO_ON;
39823  }
39824  
39825 @@ -79,63 +81,60 @@
39826  SETDEFAULTS_FUNC(mod_staticfile_set_defaults) {
39827         plugin_data *p = p_d;
39828         size_t i = 0;
39829 -       
39830 -       config_values_t cv[] = { 
39831 +
39832 +       config_values_t cv[] = {
39833                 { "static-file.exclude-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
39834                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
39835         };
39836 -       
39837 +
39838         if (!p) return HANDLER_ERROR;
39839 -       
39840 +
39841         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
39842 -       
39843 +
39844         for (i = 0; i < srv->config_context->used; i++) {
39845                 plugin_config *s;
39846 -               
39847 +
39848                 s = calloc(1, sizeof(plugin_config));
39849                 s->exclude_ext    = array_init();
39850 -               
39851 +
39852                 cv[0].destination = s->exclude_ext;
39853 -               
39854 +
39855                 p->config_storage[i] = s;
39856 -       
39857 +
39858                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
39859                         return HANDLER_ERROR;
39860                 }
39861         }
39862 -       
39863 +
39864         return HANDLER_GO_ON;
39865  }
39866  
39867 -#define PATCH(x) \
39868 -       p->conf.x = s->x;
39869  static int mod_staticfile_patch_connection(server *srv, connection *con, plugin_data *p) {
39870         size_t i, j;
39871         plugin_config *s = p->config_storage[0];
39872 -       
39873 -       PATCH(exclude_ext);
39874 -       
39875 +
39876 +       PATCH_OPTION(exclude_ext);
39877 +
39878         /* skip the first, the global context */
39879         for (i = 1; i < srv->config_context->used; i++) {
39880                 data_config *dc = (data_config *)srv->config_context->data[i];
39881                 s = p->config_storage[i];
39882 -               
39883 +
39884                 /* condition didn't match */
39885                 if (!config_check_cond(srv, con, dc)) continue;
39886 -               
39887 +
39888                 /* merge config */
39889                 for (j = 0; j < dc->value->used; j++) {
39890                         data_unset *du = dc->value->data[j];
39891 -                       
39892 +
39893                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("static-file.exclude-extensions"))) {
39894 -                               PATCH(exclude_ext);
39895 +                               PATCH_OPTION(exclude_ext);
39896                         }
39897                 }
39898         }
39899 -       
39900 +
39901         return 0;
39902  }
39903 -#undef PATCH
39904  
39905  static int http_response_parse_range(server *srv, connection *con, plugin_data *p) {
39906         int multipart = 0;
39907 @@ -146,69 +145,69 @@
39908         data_string *ds;
39909         stat_cache_entry *sce = NULL;
39910         buffer *content_type = NULL;
39911 -       
39912 +
39913         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
39914                 SEGFAULT();
39915         }
39916 -       
39917 +
39918         start = 0;
39919         end = sce->st.st_size - 1;
39920 -       
39921 +
39922         con->response.content_length = 0;
39923 -       
39924 +
39925         if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Content-Type"))) {
39926                 content_type = ds->value;
39927         }
39928 -       
39929 +
39930         for (s = con->request.http_range, error = 0;
39931              !error && *s && NULL != (minus = strchr(s, '-')); ) {
39932                 char *err;
39933                 off_t la, le;
39934 -               
39935 +
39936                 if (s == minus) {
39937                         /* -<stop> */
39938 -                       
39939 +
39940                         le = strtoll(s, &err, 10);
39941 -                       
39942 +
39943                         if (le == 0) {
39944                                 /* RFC 2616 - 14.35.1 */
39945 -                               
39946 +
39947                                 con->http_status = 416;
39948                                 error = 1;
39949                         } else if (*err == '\0') {
39950                                 /* end */
39951                                 s = err;
39952 -                               
39953 +
39954                                 end = sce->st.st_size - 1;
39955                                 start = sce->st.st_size + le;
39956                         } else if (*err == ',') {
39957                                 multipart = 1;
39958                                 s = err + 1;
39959 -                               
39960 +
39961                                 end = sce->st.st_size - 1;
39962                                 start = sce->st.st_size + le;
39963                         } else {
39964                                 error = 1;
39965                         }
39966 -                       
39967 +
39968                 } else if (*(minus+1) == '\0' || *(minus+1) == ',') {
39969                         /* <start>- */
39970 -                       
39971 +
39972                         la = strtoll(s, &err, 10);
39973 -                       
39974 +
39975                         if (err == minus) {
39976                                 /* ok */
39977 -                               
39978 +
39979                                 if (*(err + 1) == '\0') {
39980                                         s = err + 1;
39981 -                                       
39982 +
39983                                         end = sce->st.st_size - 1;
39984                                         start = la;
39985 -                                       
39986 +
39987                                 } else if (*(err + 1) == ',') {
39988                                         multipart = 1;
39989                                         s = err + 2;
39990 -                                       
39991 +
39992                                         end = sce->st.st_size - 1;
39993                                         start = la;
39994                                 } else {
39995 @@ -220,64 +219,64 @@
39996                         }
39997                 } else {
39998                         /* <start>-<stop> */
39999 -                       
40000 +
40001                         la = strtoll(s, &err, 10);
40002 -                       
40003 +
40004                         if (err == minus) {
40005                                 le = strtoll(minus+1, &err, 10);
40006 -                               
40007 +
40008                                 /* RFC 2616 - 14.35.1 */
40009                                 if (la > le) {
40010                                         error = 1;
40011                                 }
40012 -                                       
40013 +
40014                                 if (*err == '\0') {
40015                                         /* ok, end*/
40016                                         s = err;
40017 -                                       
40018 +
40019                                         end = le;
40020                                         start = la;
40021                                 } else if (*err == ',') {
40022                                         multipart = 1;
40023                                         s = err + 1;
40024 -                                       
40025 +
40026                                         end = le;
40027                                         start = la;
40028                                 } else {
40029                                         /* error */
40030 -                                       
40031 +
40032                                         error = 1;
40033                                 }
40034                         } else {
40035                                 /* error */
40036 -                               
40037 +
40038                                 error = 1;
40039                         }
40040                 }
40041 -               
40042 +
40043                 if (!error) {
40044                         if (start < 0) start = 0;
40045 -                       
40046 +
40047                         /* RFC 2616 - 14.35.1 */
40048                         if (end > sce->st.st_size - 1) end = sce->st.st_size - 1;
40049 -                       
40050 +
40051                         if (start > sce->st.st_size - 1) {
40052                                 error = 1;
40053 -                               
40054 +
40055                                 con->http_status = 416;
40056                         }
40057                 }
40058 -               
40059 +
40060                 if (!error) {
40061                         if (multipart) {
40062                                 /* write boundary-header */
40063                                 buffer *b;
40064 -                               
40065 +
40066                                 b = chunkqueue_get_append_buffer(con->write_queue);
40067 -                               
40068 +
40069                                 buffer_copy_string(b, "\r\n--");
40070                                 buffer_append_string(b, boundary);
40071 -                               
40072 +
40073                                 /* write Content-Range */
40074                                 buffer_append_string(b, "\r\nContent-Range: bytes ");
40075                                 buffer_append_off_t(b, start);
40076 @@ -285,54 +284,54 @@
40077                                 buffer_append_off_t(b, end);
40078                                 buffer_append_string(b, "/");
40079                                 buffer_append_off_t(b, sce->st.st_size);
40080 -                               
40081 +
40082                                 buffer_append_string(b, "\r\nContent-Type: ");
40083                                 buffer_append_string_buffer(b, content_type);
40084 -                               
40085 +
40086                                 /* write END-OF-HEADER */
40087                                 buffer_append_string(b, "\r\n\r\n");
40088 -                               
40089 +
40090                                 con->response.content_length += b->used - 1;
40091 -                               
40092 +
40093                         }
40094 -                       
40095 +
40096                         chunkqueue_append_file(con->write_queue, con->physical.path, start, end - start + 1);
40097                         con->response.content_length += end - start + 1;
40098                 }
40099         }
40100 -       
40101 +
40102         /* something went wrong */
40103         if (error) return -1;
40104 -       
40105 +
40106         if (multipart) {
40107                 /* add boundary end */
40108                 buffer *b;
40109 -               
40110 +
40111                 b = chunkqueue_get_append_buffer(con->write_queue);
40112 -               
40113 +
40114                 buffer_copy_string_len(b, "\r\n--", 4);
40115                 buffer_append_string(b, boundary);
40116                 buffer_append_string_len(b, "--\r\n", 4);
40117 -               
40118 +
40119                 con->response.content_length += b->used - 1;
40120 -               
40121 +
40122                 /* set header-fields */
40123 -               
40124 +
40125                 buffer_copy_string(p->range_buf, "multipart/byteranges; boundary=");
40126                 buffer_append_string(p->range_buf, boundary);
40127 -               
40128 +
40129                 /* overwrite content-type */
40130                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->range_buf));
40131         } else {
40132                 /* add Content-Range-header */
40133 -               
40134 +
40135                 buffer_copy_string(p->range_buf, "bytes ");
40136                 buffer_append_off_t(p->range_buf, start);
40137                 buffer_append_string(p->range_buf, "-");
40138                 buffer_append_off_t(p->range_buf, end);
40139                 buffer_append_string(p->range_buf, "/");
40140                 buffer_append_off_t(p->range_buf, sce->st.st_size);
40141 -               
40142 +
40143                 response_header_insert(srv, con, CONST_STR_LEN("Content-Range"), CONST_BUF_LEN(p->range_buf));
40144         }
40145  
40146 @@ -347,12 +346,12 @@
40147         stat_cache_entry *sce = NULL;
40148         buffer *mtime;
40149         data_string *ds;
40150 -       
40151 +
40152         /* someone else has done a decision for us */
40153         if (con->http_status != 0) return HANDLER_GO_ON;
40154         if (con->uri.path->used == 0) return HANDLER_GO_ON;
40155         if (con->physical.path->used == 0) return HANDLER_GO_ON;
40156 -       
40157 +
40158         /* someone else has handled this request */
40159         if (con->mode != DIRECT) return HANDLER_GO_ON;
40160  
40161 @@ -365,52 +364,52 @@
40162         default:
40163                 return HANDLER_GO_ON;
40164         }
40165 -       
40166 +
40167         mod_staticfile_patch_connection(srv, con, p);
40168 -       
40169 +
40170         s_len = con->uri.path->used - 1;
40171 -       
40172 +
40173         /* ignore certain extensions */
40174         for (k = 0; k < p->conf.exclude_ext->used; k++) {
40175 -               ds = (data_string *)p->conf.exclude_ext->data[k]; 
40176 -               
40177 +               ds = (data_string *)p->conf.exclude_ext->data[k];
40178 +
40179                 if (ds->value->used == 0) continue;
40180  
40181                 if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
40182                         return HANDLER_GO_ON;
40183                 }
40184         }
40185 -       
40186 +
40187  
40188         if (con->conf.log_request_handling) {
40189                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling file as static file");
40190         }
40191 -       
40192 +
40193         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
40194                 con->http_status = 403;
40195 -               
40196 +
40197                 log_error_write(srv, __FILE__, __LINE__, "sbsb",
40198                                 "not a regular file:", con->uri.path,
40199                                 "->", con->physical.path);
40200 -               
40201 +
40202                 return HANDLER_FINISHED;
40203         }
40204 -       
40205 -       /* we only handline regular files */
40206 +
40207 +       /* we only handle regular files */
40208         if (!S_ISREG(sce->st.st_mode)) {
40209                 con->http_status = 404;
40210 -               
40211 +
40212                 if (con->conf.log_file_not_found) {
40213                         log_error_write(srv, __FILE__, __LINE__, "sbsb",
40214                                         "not a regular file:", con->uri.path,
40215                                         "->", sce->name);
40216                 }
40217 -               
40218 +
40219                 return HANDLER_FINISHED;
40220         }
40221  
40222 -       /* mod_compress might set several data directly, don't overwrite them */
40223 -       
40224 +       /* mod_compress might set several parameters directly; don't overwrite them */
40225 +
40226         /* set response content-type, if not set already */
40227  
40228         if (NULL == array_get_element(con->response.headers, "Content-Type")) {
40229 @@ -420,15 +419,15 @@
40230                         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
40231                 }
40232         }
40233 -       
40234 +
40235         if (NULL == array_get_element(con->response.headers, "ETag")) {
40236                 /* generate e-tag */
40237                 etag_mutate(con->physical.etag, sce->etag);
40238 -       
40239 +
40240                 response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
40241         }
40242         response_header_overwrite(srv, con, CONST_STR_LEN("Accept-Ranges"), CONST_STR_LEN("bytes"));
40243 -       
40244 +
40245         /* prepare header */
40246         if (NULL == (ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"))) {
40247                 mtime = strftime_cache_get(srv, sce->st.st_mtime);
40248 @@ -444,34 +443,34 @@
40249                 /* check if we have a conditional GET */
40250  
40251                 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If-Range"))) {
40252 -                       /* if the value is the same as our ETag, we do a Range-request, 
40253 +                       /* if the value is the same as our ETag, we do a Range-request,
40254                          * otherwise a full 200 */
40255  
40256                         if (!buffer_is_equal(ds->value, con->physical.etag)) {
40257                                 do_range_request = 0;
40258                         }
40259                 }
40260 -       
40261 +
40262                 if (do_range_request) {
40263                         /* content prepared, I'm done */
40264                         con->file_finished = 1;
40265 -               
40266 +
40267                         if (0 == http_response_parse_range(srv, con, p)) {
40268                                 con->http_status = 206;
40269                         }
40270                         return HANDLER_FINISHED;
40271                 }
40272         }
40273 -       
40274 +
40275         /* if we are still here, prepare body */
40276 -       
40277 -       /* we add it here for all requests 
40278 -        * the HEAD request will drop it afterwards again 
40279 +
40280 +       /* we add it here for all requests
40281 +        * the HEAD request will drop it afterwards again
40282          */
40283         http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
40284 -       
40285 +
40286         con->file_finished = 1;
40287 -       
40288 +
40289         return HANDLER_FINISHED;
40290  }
40291  
40292 @@ -480,13 +479,13 @@
40293  int mod_staticfile_plugin_init(plugin *p) {
40294         p->version     = LIGHTTPD_VERSION_ID;
40295         p->name        = buffer_init_string("staticfile");
40296 -       
40297 +
40298         p->init        = mod_staticfile_init;
40299         p->handle_subrequest_start = mod_staticfile_subrequest;
40300         p->set_defaults  = mod_staticfile_set_defaults;
40301         p->cleanup     = mod_staticfile_free;
40302 -       
40303 +
40304         p->data        = NULL;
40305 -       
40306 +
40307         return 0;
40308  }
40309 --- ../lighttpd-1.4.11/src/mod_status.c 2006-01-10 21:45:32.000000000 +0200
40310 +++ lighttpd-1.4.12/src/mod_status.c    2006-07-19 20:02:55.000000000 +0300
40311 @@ -4,7 +4,6 @@
40312  #include <fcntl.h>
40313  #include <stdlib.h>
40314  #include <string.h>
40315 -#include <unistd.h>
40316  #include <errno.h>
40317  #include <time.h>
40318  #include <stdio.h>
40319 @@ -14,6 +13,7 @@
40320  #include "response.h"
40321  #include "connections.h"
40322  #include "log.h"
40323 +#include "status_counter.h"
40324  
40325  #include "plugin.h"
40326  
40327 @@ -29,114 +29,114 @@
40328  
40329  typedef struct {
40330         PLUGIN_DATA;
40331 -       
40332 +
40333         double traffic_out;
40334         double requests;
40335 -       
40336 +
40337         double mod_5s_traffic_out[5];
40338         double mod_5s_requests[5];
40339         size_t mod_5s_ndx;
40340 -       
40341 +
40342         double rel_traffic_out;
40343         double rel_requests;
40344 -       
40345 +
40346         double abs_traffic_out;
40347         double abs_requests;
40348 -       
40349 +
40350         double bytes_written;
40351 -       
40352 +
40353         buffer *module_list;
40354 -       
40355 +
40356         plugin_config **config_storage;
40357 -       
40358 -       plugin_config conf; 
40359 +
40360 +       plugin_config conf;
40361  } plugin_data;
40362  
40363  INIT_FUNC(mod_status_init) {
40364         plugin_data *p;
40365         size_t i;
40366 -       
40367 +
40368         p = calloc(1, sizeof(*p));
40369 -       
40370 +
40371         p->traffic_out = p->requests = 0;
40372         p->rel_traffic_out = p->rel_requests = 0;
40373         p->abs_traffic_out = p->abs_requests = 0;
40374         p->bytes_written = 0;
40375         p->module_list = buffer_init();
40376 -       
40377 +
40378         for (i = 0; i < 5; i++) {
40379                 p->mod_5s_traffic_out[i] = p->mod_5s_requests[i] = 0;
40380         }
40381 -       
40382 +
40383         return p;
40384  }
40385  
40386  FREE_FUNC(mod_status_free) {
40387         plugin_data *p = p_d;
40388 -       
40389 +
40390         UNUSED(srv);
40391  
40392         if (!p) return HANDLER_GO_ON;
40393 -       
40394 +
40395         buffer_free(p->module_list);
40396 -       
40397 +
40398         if (p->config_storage) {
40399                 size_t i;
40400                 for (i = 0; i < srv->config_context->used; i++) {
40401                         plugin_config *s = p->config_storage[i];
40402 -                       
40403 +
40404                         buffer_free(s->status_url);
40405                         buffer_free(s->statistics_url);
40406                         buffer_free(s->config_url);
40407 -                       
40408 +
40409                         free(s);
40410                 }
40411                 free(p->config_storage);
40412         }
40413 -       
40414 -       
40415 +
40416 +
40417         free(p);
40418 -       
40419 +
40420         return HANDLER_GO_ON;
40421  }
40422  
40423  SETDEFAULTS_FUNC(mod_status_set_defaults) {
40424         plugin_data *p = p_d;
40425         size_t i;
40426 -       
40427 -       config_values_t cv[] = { 
40428 +
40429 +       config_values_t cv[] = {
40430                 { "status.status-url",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
40431                 { "status.config-url",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
40432                 { "status.enable-sort",          NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
40433                 { "status.statistics-url",       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
40434                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
40435         };
40436 -       
40437 +
40438         if (!p) return HANDLER_ERROR;
40439 -       
40440 +
40441         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
40442 -       
40443 +
40444         for (i = 0; i < srv->config_context->used; i++) {
40445                 plugin_config *s;
40446 -               
40447 +
40448                 s = calloc(1, sizeof(plugin_config));
40449                 s->config_url    = buffer_init();
40450                 s->status_url    = buffer_init();
40451                 s->sort          = 1;
40452                 s->statistics_url    = buffer_init();
40453 -               
40454 +
40455                 cv[0].destination = s->status_url;
40456                 cv[1].destination = s->config_url;
40457                 cv[2].destination = &(s->sort);
40458                 cv[3].destination = s->statistics_url;
40459 -               
40460 +
40461                 p->config_storage[i] = s;
40462 -       
40463 +
40464                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
40465                         return HANDLER_ERROR;
40466                 }
40467         }
40468 -       
40469 +
40470         return HANDLER_GO_ON;
40471  }
40472  
40473 @@ -151,7 +151,7 @@
40474         buffer_append_string(b, value);
40475         BUFFER_APPEND_STRING_CONST(b, "</td>\n");
40476         BUFFER_APPEND_STRING_CONST(b, "   </tr>\n");
40477 -       
40478 +
40479         return 0;
40480  }
40481  
40482 @@ -161,13 +161,13 @@
40483         buffer_append_string(b, key);
40484         BUFFER_APPEND_STRING_CONST(b, "</th>\n");
40485         BUFFER_APPEND_STRING_CONST(b, "   </tr>\n");
40486 -       
40487 +
40488         return 0;
40489  }
40490  
40491  static int mod_status_header_append_sort(buffer *b, void *p_d, const char* key) {
40492         plugin_data *p = p_d;
40493 -       
40494 +
40495         if (p->conf.sort) {
40496                 BUFFER_APPEND_STRING_CONST(b, "<th class=\"status\"><a href=\"#\" class=\"sortheader\" onclick=\"resort(this);return false;\">");
40497                 buffer_append_string(b, key);
40498 @@ -177,13 +177,13 @@
40499                 buffer_append_string(b, key);
40500                 BUFFER_APPEND_STRING_CONST(b, "</th>\n");
40501         }
40502 -       
40503 +
40504         return 0;
40505  }
40506  
40507  static int mod_status_get_multiplier(double *avg, char *multiplier, int size) {
40508         *multiplier = ' ';
40509 -       
40510 +
40511         if (*avg > size) { *avg /= size; *multiplier = 'k'; }
40512         if (*avg > size) { *avg /= size; *multiplier = 'M'; }
40513         if (*avg > size) { *avg /= size; *multiplier = 'G'; }
40514 @@ -202,21 +202,21 @@
40515         size_t j;
40516         double avg;
40517         char multiplier = '\0';
40518 -       char buf[32];
40519 +       char buf[128];
40520         time_t ts;
40521 -       
40522 +
40523         int days, hours, mins, seconds;
40524 -       
40525 +
40526         b = chunkqueue_get_append_buffer(con->write_queue);
40527  
40528 -       BUFFER_COPY_STRING_CONST(b, 
40529 +       BUFFER_COPY_STRING_CONST(b,
40530                                  "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
40531                                  "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
40532                                  "         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
40533                                  "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
40534                                  " <head>\n"
40535                                  "  <title>Status</title>\n");
40536 -       
40537 +
40538         BUFFER_APPEND_STRING_CONST(b,
40539                                    "  <style type=\"text/css\">\n"
40540                                    "    table.status { border: black solid thin; }\n"
40541 @@ -226,14 +226,14 @@
40542                                    "    a.sortheader { background-color: black; color: white; font-weight: bold; text-decoration: none; display: block; }\n"
40543                                    "    span.sortarrow { color: white; text-decoration: none; }\n"
40544                                    "  </style>\n");
40545 -       
40546 +
40547         if (p->conf.sort) {
40548                 BUFFER_APPEND_STRING_CONST(b,
40549                                            "<script type=\"text/javascript\">\n"
40550                                            "// <!--\n"
40551                                            "var sort_column;\n"
40552                                            "var prev_span = null;\n");
40553 -               
40554 +
40555                 BUFFER_APPEND_STRING_CONST(b,
40556                                            "function get_inner_text(el) {\n"
40557                                            " if((typeof el == 'string')||(typeof el == 'undefined'))\n"
40558 @@ -251,7 +251,7 @@
40559                                            " }\n"
40560                                            " return str;\n"
40561                                            "}\n");
40562 -               
40563 +
40564                 BUFFER_APPEND_STRING_CONST(b,
40565                                            "function sortfn(a,b) {\n"
40566                                            " var at = get_inner_text(a.cells[sort_column]);\n"
40567 @@ -266,7 +266,7 @@
40568                                            "  else return 1;\n"
40569                                            " }\n"
40570                                            "}\n");
40571 -               
40572 +
40573                 BUFFER_APPEND_STRING_CONST(b,
40574                                            "function resort(lnk) {\n"
40575                                            " var span = lnk.childNodes[1];\n"
40576 @@ -276,7 +276,7 @@
40577                                            "  rows[j-1] = table.rows[j];\n"
40578                                            " sort_column = lnk.parentNode.cellIndex;\n"
40579                                            " rows.sort(sortfn);\n");
40580 -               
40581 +
40582                 BUFFER_APPEND_STRING_CONST(b,
40583                                            " if (prev_span != null) prev_span.innerHTML = '';\n"
40584                                            " if (span.getAttribute('sortdir')=='down') {\n"
40585 @@ -294,175 +294,175 @@
40586                                            "// -->\n"
40587                                            "</script>\n");
40588         }
40589 -       
40590 -       BUFFER_APPEND_STRING_CONST(b, 
40591 +
40592 +       BUFFER_APPEND_STRING_CONST(b,
40593                                  " </head>\n"
40594                                  " <body>\n");
40595 -       
40596 -       
40597 -       
40598 +
40599 +
40600 +
40601         /* connection listing */
40602         BUFFER_APPEND_STRING_CONST(b, "<h1>Server-Status</h1>");
40603 -       
40604 -       BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\">");
40605 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Hostname</td><td class=\"string\">");
40606 +
40607 +       BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\" id=\"status\" summary=\"Server Status\">");
40608 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Hostname</td><td class=\"string\"><span id=\"host_addr\">");
40609         buffer_append_string_buffer(b, con->uri.authority);
40610 -       BUFFER_APPEND_STRING_CONST(b, " (");
40611 +       BUFFER_APPEND_STRING_CONST(b, "</span> (<span id=\"host_name\">");
40612         buffer_append_string_buffer(b, con->server_name);
40613 -       BUFFER_APPEND_STRING_CONST(b, ")</td></tr>\n");
40614 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Uptime</td><td class=\"string\">");
40615 -       
40616 +       BUFFER_APPEND_STRING_CONST(b, "</span>)</td></tr>\n");
40617 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Uptime</td><td class=\"string\" id=\"uptime\">");
40618 +
40619         ts = srv->cur_ts - srv->startup_ts;
40620 -       
40621 +
40622         days = ts / (60 * 60 * 24);
40623         ts %= (60 * 60 * 24);
40624 -       
40625 +
40626         hours = ts / (60 * 60);
40627         ts %= (60 * 60);
40628 -       
40629 +
40630         mins = ts / (60);
40631         ts %= (60);
40632 -       
40633 +
40634         seconds = ts;
40635 -       
40636 +
40637         if (days) {
40638                 buffer_append_long(b, days);
40639                 BUFFER_APPEND_STRING_CONST(b, " days ");
40640         }
40641 -       
40642 +
40643         if (hours) {
40644                 buffer_append_long(b, hours);
40645                 BUFFER_APPEND_STRING_CONST(b, " hours ");
40646         }
40647 -       
40648 +
40649         if (mins) {
40650                 buffer_append_long(b, mins);
40651                 BUFFER_APPEND_STRING_CONST(b, " min ");
40652         }
40653 -       
40654 +
40655         buffer_append_long(b, seconds);
40656         BUFFER_APPEND_STRING_CONST(b, " s");
40657 -       
40658 +
40659         BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
40660         BUFFER_APPEND_STRING_CONST(b, "<tr><td>Started at</td><td class=\"string\">");
40661 -       
40662 +
40663         ts = srv->startup_ts;
40664 -       
40665 -       strftime(buf, sizeof(buf) - 1, "%Y-%m-%d %H:%M:%S", localtime(&ts));
40666 +
40667 +       strftime(buf, sizeof(buf) - 1, "<span id=\"start_date\">%Y-%m-%d</span> <span id=\"start_time\">%H:%M:%S</span>", localtime(&ts));
40668         buffer_append_string(b, buf);
40669         BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
40670 -       
40671 -       
40672 +
40673 +
40674         BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">absolute (since start)</th></tr>\n");
40675 -       
40676 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
40677 +
40678 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\" ><span id=\"requests\">");
40679         avg = p->abs_requests;
40680  
40681         mod_status_get_multiplier(&avg, &multiplier, 1000);
40682 -       
40683 +
40684         buffer_append_long(b, avg);
40685 -       BUFFER_APPEND_STRING_CONST(b, " ");
40686 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_mult\">");
40687         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40688 -       BUFFER_APPEND_STRING_CONST(b, "req</td></tr>\n");
40689 -       
40690 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
40691 +       BUFFER_APPEND_STRING_CONST(b, "</span>req</td></tr>\n");
40692 +
40693 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"traffic\">");
40694         avg = p->abs_traffic_out;
40695  
40696         mod_status_get_multiplier(&avg, &multiplier, 1024);
40697  
40698         sprintf(buf, "%.2f", avg);
40699         buffer_append_string(b, buf);
40700 -       BUFFER_APPEND_STRING_CONST(b, " ");
40701 +       BUFFER_APPEND_STRING_CONST(b, "</span>  <span id=\"traffic_mult\">");
40702         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40703 -       BUFFER_APPEND_STRING_CONST(b, "byte</td></tr>\n");
40704 +       BUFFER_APPEND_STRING_CONST(b, "</span>byte</td></tr>\n");
40705  
40706  
40707  
40708         BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (since start)</th></tr>\n");
40709 -       
40710 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
40711 +
40712 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\"><span id=\"requests_avg\">");
40713         avg = p->abs_requests / (srv->cur_ts - srv->startup_ts);
40714  
40715         mod_status_get_multiplier(&avg, &multiplier, 1000);
40716  
40717         buffer_append_long(b, avg);
40718 -       BUFFER_APPEND_STRING_CONST(b, " ");
40719 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_avg_mult\">");
40720         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40721 -       BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n");
40722 -       
40723 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
40724 +       BUFFER_APPEND_STRING_CONST(b, "</span>req/s</td></tr>\n");
40725 +
40726 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"traffic_avg\">");
40727         avg = p->abs_traffic_out / (srv->cur_ts - srv->startup_ts);
40728  
40729         mod_status_get_multiplier(&avg, &multiplier, 1024);
40730  
40731         sprintf(buf, "%.2f", avg);
40732         buffer_append_string(b, buf);
40733 -       BUFFER_APPEND_STRING_CONST(b, " ");
40734 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"traffic_avg_mult\">");
40735         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40736 -       BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n");
40737 +       BUFFER_APPEND_STRING_CONST(b, "</span>byte/s</td></tr>\n");
40738 +
40739 +
40740  
40741 -       
40742 -       
40743         BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (5s sliding average)</th></tr>\n");
40744         for (j = 0, avg = 0; j < 5; j++) {
40745                 avg += p->mod_5s_requests[j];
40746         }
40747 -       
40748 +
40749         avg /= 5;
40750 -       
40751 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
40752 +
40753 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\"><span id=\"requests_sliding_avg\">");
40754  
40755         mod_status_get_multiplier(&avg, &multiplier, 1000);
40756  
40757         buffer_append_long(b, avg);
40758 -       BUFFER_APPEND_STRING_CONST(b, " ");
40759 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_sliding_avg_mult\">");
40760         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40761 -       
40762 -       BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n");
40763 -       
40764 +
40765 +       BUFFER_APPEND_STRING_CONST(b, "</span>req/s</td></tr>\n");
40766 +
40767         for (j = 0, avg = 0; j < 5; j++) {
40768                 avg += p->mod_5s_traffic_out[j];
40769         }
40770 -       
40771 +
40772         avg /= 5;
40773 -       
40774 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
40775 +
40776 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"requests_sliding_traffic\">");
40777  
40778         mod_status_get_multiplier(&avg, &multiplier, 1024);
40779  
40780         sprintf(buf, "%.2f", avg);
40781         buffer_append_string(b, buf);
40782 -       BUFFER_APPEND_STRING_CONST(b, " ");
40783 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_sliding_traffic_mult\">");
40784         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40785 -       BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n");
40786 -       
40787 +       BUFFER_APPEND_STRING_CONST(b, "</span>byte/s</td></tr>\n");
40788 +
40789         BUFFER_APPEND_STRING_CONST(b, "</table>\n");
40790 -       
40791 -       
40792 +
40793 +
40794         BUFFER_APPEND_STRING_CONST(b, "<hr />\n<pre><b>legend</b>\n");
40795         BUFFER_APPEND_STRING_CONST(b, ". = connect, C = close, E = hard error\n");
40796         BUFFER_APPEND_STRING_CONST(b, "r = read, R = read-POST, W = write, h = handle-request\n");
40797         BUFFER_APPEND_STRING_CONST(b, "q = request-start,  Q = request-end\n");
40798         BUFFER_APPEND_STRING_CONST(b, "s = response-start, S = response-end\n");
40799 -       
40800 -       BUFFER_APPEND_STRING_CONST(b, "<b>");
40801 +
40802 +       BUFFER_APPEND_STRING_CONST(b, "<strong><span id=\"connections\">");
40803         buffer_append_long(b, srv->conns->used);
40804 -       BUFFER_APPEND_STRING_CONST(b, " connections</b>\n");
40805 -       
40806 +       BUFFER_APPEND_STRING_CONST(b, "</span> connections</strong>\n");
40807 +
40808         for (j = 0; j < srv->conns->used; j++) {
40809                 connection *c = srv->conns->ptr[j];
40810                 const char *state = connection_get_short_state(c->state);
40811 -               
40812 +
40813                 buffer_append_string_len(b, state, 1);
40814 -               
40815 +
40816                 if (((j + 1) % 50) == 0) {
40817                         BUFFER_APPEND_STRING_CONST(b, "\n");
40818                 }
40819         }
40820 -       
40821 +
40822         BUFFER_APPEND_STRING_CONST(b, "\n</pre><hr />\n<h2>Connections</h2>\n");
40823 -       
40824 -       BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\">\n");
40825 +
40826 +       BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\" summary=\"Current connections\" id=\"clients\">\n");
40827         BUFFER_APPEND_STRING_CONST(b, "<tr>");
40828         mod_status_header_append_sort(b, p_d, "Client IP");
40829         mod_status_header_append_sort(b, p_d, "Read");
40830 @@ -473,16 +473,16 @@
40831         mod_status_header_append_sort(b, p_d, "URI");
40832         mod_status_header_append_sort(b, p_d, "File");
40833         BUFFER_APPEND_STRING_CONST(b, "</tr>\n");
40834 -       
40835 +
40836         for (j = 0; j < srv->conns->used; j++) {
40837                 connection *c = srv->conns->ptr[j];
40838 -               
40839 -               BUFFER_APPEND_STRING_CONST(b, "<tr><td class=\"string\">");
40840 -               
40841 +
40842 +               BUFFER_APPEND_STRING_CONST(b, "<tr><td class=\"string ip\">");
40843 +
40844                 buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(c->dst_addr)));
40845 -               
40846 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
40847 -               
40848 +
40849 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int bytes_read\">");
40850 +
40851                 if (con->request.content_length) {
40852                         buffer_append_long(b, c->request_content_queue->bytes_in);
40853                         BUFFER_APPEND_STRING_CONST(b, "/");
40854 @@ -490,55 +490,55 @@
40855                 } else {
40856                         BUFFER_APPEND_STRING_CONST(b, "0/0");
40857                 }
40858 -       
40859 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
40860 -               
40861 +
40862 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int bytes_written\">");
40863 +
40864                 buffer_append_off_t(b, chunkqueue_written(c->write_queue));
40865                 BUFFER_APPEND_STRING_CONST(b, "/");
40866                 buffer_append_off_t(b, chunkqueue_length(c->write_queue));
40867 -               
40868 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40869 -               
40870 +
40871 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string state\">");
40872 +
40873                 buffer_append_string(b, connection_get_state(c->state));
40874 -               
40875 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
40876 -               
40877 +
40878 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int time\">");
40879 +
40880                 buffer_append_long(b, srv->cur_ts - c->request_start);
40881 -               
40882 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40883 -               
40884 +
40885 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string host\">");
40886 +
40887                 if (buffer_is_empty(c->server_name)) {
40888                         buffer_append_string_buffer(b, c->uri.authority);
40889                 }
40890                 else {
40891                         buffer_append_string_buffer(b, c->server_name);
40892                 }
40893 -               
40894 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40895 -               
40896 +
40897 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string uri\">");
40898 +
40899                 if (!buffer_is_empty(c->uri.path)) {
40900                         buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.path), ENCODING_HTML);
40901                 }
40902 -               
40903 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40904 -               
40905 +
40906 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string file\">");
40907 +
40908                 buffer_append_string_buffer(b, c->physical.path);
40909 -               
40910 +
40911                 BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
40912         }
40913 -       
40914 -       
40915 -       BUFFER_APPEND_STRING_CONST(b, 
40916 +
40917 +
40918 +       BUFFER_APPEND_STRING_CONST(b,
40919                       "</table>\n");
40920 -       
40921 -       
40922 -       BUFFER_APPEND_STRING_CONST(b, 
40923 +
40924 +
40925 +       BUFFER_APPEND_STRING_CONST(b,
40926                       " </body>\n"
40927                       "</html>\n"
40928                       );
40929 -       
40930 +
40931         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
40932 -       
40933 +
40934         return 0;
40935  }
40936  
40937 @@ -548,7 +548,7 @@
40938         buffer *b;
40939         double avg;
40940         time_t ts;
40941 -       
40942 +
40943         b = chunkqueue_get_append_buffer(con->write_queue);
40944  
40945         /* output total number of requests */
40946 @@ -556,19 +556,19 @@
40947         avg = p->abs_requests;
40948         buffer_append_long(b, avg);
40949         BUFFER_APPEND_STRING_CONST(b, "\n");
40950 -       
40951 +
40952         /* output total traffic out in kbytes */
40953         BUFFER_APPEND_STRING_CONST(b, "Total kBytes: ");
40954         avg = p->abs_traffic_out / 1024;
40955         buffer_append_long(b, avg);
40956         BUFFER_APPEND_STRING_CONST(b, "\n");
40957 -       
40958 +
40959         /* output uptime */
40960         BUFFER_APPEND_STRING_CONST(b, "Uptime: ");
40961         ts = srv->cur_ts - srv->startup_ts;
40962         buffer_append_long(b, ts);
40963         BUFFER_APPEND_STRING_CONST(b, "\n");
40964 -       
40965 +
40966         /* output busy servers */
40967         BUFFER_APPEND_STRING_CONST(b, "BusyServers: ");
40968         buffer_append_long(b, srv->conns->used);
40969 @@ -577,7 +577,7 @@
40970         /* set text/plain output */
40971  
40972         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
40973 -       
40974 +
40975         return 0;
40976  }
40977  
40978 @@ -585,16 +585,16 @@
40979         plugin_data *p = p_d;
40980         buffer *b, *m = p->module_list;
40981         size_t i;
40982 -       array *st = srv->status;
40983 +       array *st = status_counter_get_array();
40984  
40985         if (0 == st->used) {
40986                 /* we have nothing to send */
40987                 con->http_status = 204;
40988                 con->file_finished = 1;
40989 -       
40990 +
40991                 return HANDLER_FINISHED;
40992         }
40993 -       
40994 +
40995         b = chunkqueue_get_append_buffer(con->write_queue);
40996  
40997         for (i = 0; i < st->used; i++) {
40998 @@ -605,27 +605,27 @@
40999                 buffer_append_long(b, ((data_integer *)(st->data[ndx]))->value);
41000                 buffer_append_string(b, "\n");
41001         }
41002 -       
41003 +
41004         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
41005 -       
41006 +
41007         con->http_status = 200;
41008         con->file_finished = 1;
41009 -       
41010 +
41011         return HANDLER_FINISHED;
41012  }
41013  
41014  
41015  static handler_t mod_status_handle_server_status(server *srv, connection *con, void *p_d) {
41016 -       
41017 +
41018         if (buffer_is_equal_string(con->uri.query, CONST_STR_LEN("auto"))) {
41019                 mod_status_handle_server_status_text(srv, con, p_d);
41020         } else {
41021                 mod_status_handle_server_status_html(srv, con, p_d);
41022         }
41023 -       
41024 +
41025         con->http_status = 200;
41026         con->file_finished = 1;
41027 -       
41028 +
41029         return HANDLER_FINISHED;
41030  }
41031  
41032 @@ -634,9 +634,9 @@
41033         plugin_data *p = p_d;
41034         buffer *b, *m = p->module_list;
41035         size_t i;
41036 -       
41037 -       struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] = 
41038 -       { 
41039 +
41040 +       struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
41041 +       {
41042                 /* - poll is most reliable
41043                  * - select works everywhere
41044                  * - linux-* are experimental
41045 @@ -661,10 +661,10 @@
41046  #endif
41047                 { FDEVENT_HANDLER_UNSET,          NULL }
41048         };
41049 -       
41050 +
41051         b = chunkqueue_get_append_buffer(con->write_queue);
41052 -       
41053 -       BUFFER_COPY_STRING_CONST(b, 
41054 +
41055 +       BUFFER_COPY_STRING_CONST(b,
41056                            "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
41057                            "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
41058                            "         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
41059 @@ -675,7 +675,7 @@
41060                            " <body>\n"
41061                            "  <h1>" PACKAGE_NAME " " PACKAGE_VERSION "</h1>\n"
41062                            "  <table border=\"1\">\n");
41063 -       
41064 +
41065         mod_status_header_append(b, "Server-Features");
41066  #ifdef HAVE_PCRE_H
41067         mod_status_row_append(b, "RegEx Conditionals", "enabled");
41068 @@ -683,21 +683,21 @@
41069         mod_status_row_append(b, "RegEx Conditionals", "disabled - pcre missing");
41070  #endif
41071         mod_status_header_append(b, "Network Engine");
41072 -       
41073 +
41074         for (i = 0; event_handlers[i].name; i++) {
41075                 if (event_handlers[i].et == srv->event_handler) {
41076                         mod_status_row_append(b, "fd-Event-Handler", event_handlers[i].name);
41077                         break;
41078                 }
41079         }
41080 -       
41081 +
41082         mod_status_header_append(b, "Config-File-Settings");
41083 -       
41084 +
41085         for (i = 0; i < srv->plugins.used; i++) {
41086                 plugin **ps = srv->plugins.ptr;
41087 -               
41088 +
41089                 plugin *pl = ps[i];
41090 -       
41091 +
41092                 if (i == 0) {
41093                         buffer_copy_string_buffer(m, pl->name);
41094                 } else {
41095 @@ -705,137 +705,135 @@
41096                         buffer_append_string_buffer(m, pl->name);
41097                 }
41098         }
41099 -       
41100 +
41101         mod_status_row_append(b, "Loaded Modules", m->ptr);
41102 -       
41103 +
41104         BUFFER_APPEND_STRING_CONST(b, "  </table>\n");
41105 -       
41106 -       BUFFER_APPEND_STRING_CONST(b, 
41107 +
41108 +       BUFFER_APPEND_STRING_CONST(b,
41109                       " </body>\n"
41110                       "</html>\n"
41111                       );
41112 -       
41113 +
41114         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
41115 -       
41116 +
41117         con->http_status = 200;
41118         con->file_finished = 1;
41119 -       
41120 +
41121         return HANDLER_FINISHED;
41122  }
41123  
41124 -#define PATCH(x) \
41125 -       p->conf.x = s->x;
41126  static int mod_status_patch_connection(server *srv, connection *con, plugin_data *p) {
41127         size_t i, j;
41128         plugin_config *s = p->config_storage[0];
41129 -       
41130 -       PATCH(status_url);
41131 -       PATCH(config_url);
41132 -       PATCH(sort);
41133 -       PATCH(statistics_url);
41134 -       
41135 +
41136 +       PATCH_OPTION(status_url);
41137 +       PATCH_OPTION(config_url);
41138 +       PATCH_OPTION(sort);
41139 +       PATCH_OPTION(statistics_url);
41140 +
41141         /* skip the first, the global context */
41142         for (i = 1; i < srv->config_context->used; i++) {
41143                 data_config *dc = (data_config *)srv->config_context->data[i];
41144                 s = p->config_storage[i];
41145 -               
41146 +
41147                 /* condition didn't match */
41148                 if (!config_check_cond(srv, con, dc)) continue;
41149 -               
41150 +
41151                 /* merge config */
41152                 for (j = 0; j < dc->value->used; j++) {
41153                         data_unset *du = dc->value->data[j];
41154 -                       
41155 +
41156                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.status-url"))) {
41157 -                               PATCH(status_url);
41158 +                               PATCH_OPTION(status_url);
41159                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.config-url"))) {
41160 -                               PATCH(config_url);
41161 +                               PATCH_OPTION(config_url);
41162                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.enable-sort"))) {
41163 -                               PATCH(sort);
41164 +                               PATCH_OPTION(sort);
41165                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.statistics-url"))) {
41166 -                               PATCH(statistics_url);
41167 -                       } 
41168 +                               PATCH_OPTION(statistics_url);
41169 +                       }
41170                 }
41171         }
41172 -       
41173 +
41174         return 0;
41175  }
41176  
41177  static handler_t mod_status_handler(server *srv, connection *con, void *p_d) {
41178         plugin_data *p = p_d;
41179 -       
41180 +
41181         mod_status_patch_connection(srv, con, p);
41182 -       
41183 -       if (!buffer_is_empty(p->conf.status_url) && 
41184 +
41185 +       if (!buffer_is_empty(p->conf.status_url) &&
41186             buffer_is_equal(p->conf.status_url, con->uri.path)) {
41187                 return mod_status_handle_server_status(srv, con, p_d);
41188 -       } else if (!buffer_is_empty(p->conf.config_url) && 
41189 +       } else if (!buffer_is_empty(p->conf.config_url) &&
41190             buffer_is_equal(p->conf.config_url, con->uri.path)) {
41191                 return mod_status_handle_server_config(srv, con, p_d);
41192 -       } else if (!buffer_is_empty(p->conf.statistics_url) && 
41193 +       } else if (!buffer_is_empty(p->conf.statistics_url) &&
41194             buffer_is_equal(p->conf.statistics_url, con->uri.path)) {
41195                 return mod_status_handle_server_statistics(srv, con, p_d);
41196         }
41197 -       
41198 +
41199         return HANDLER_GO_ON;
41200  }
41201  
41202  TRIGGER_FUNC(mod_status_trigger) {
41203         plugin_data *p = p_d;
41204         size_t i;
41205 -       
41206 +
41207         /* check all connections */
41208         for (i = 0; i < srv->conns->used; i++) {
41209                 connection *c = srv->conns->ptr[i];
41210 -               
41211 +
41212                 p->bytes_written += c->bytes_written_cur_second;
41213         }
41214 -       
41215 +
41216         /* a sliding average */
41217         p->mod_5s_traffic_out[p->mod_5s_ndx] = p->bytes_written;
41218         p->mod_5s_requests   [p->mod_5s_ndx] = p->requests;
41219 -       
41220 +
41221         p->mod_5s_ndx = (p->mod_5s_ndx+1) % 5;
41222 -       
41223 +
41224         p->abs_traffic_out += p->bytes_written;
41225         p->rel_traffic_out += p->bytes_written;
41226 -       
41227 +
41228         p->bytes_written = 0;
41229 -       
41230 +
41231         /* reset storage - second */
41232         p->traffic_out = 0;
41233         p->requests    = 0;
41234 -       
41235 +
41236         return HANDLER_GO_ON;
41237  }
41238  
41239  REQUESTDONE_FUNC(mod_status_account) {
41240         plugin_data *p = p_d;
41241 -       
41242 +
41243         UNUSED(srv);
41244  
41245         p->requests++;
41246         p->rel_requests++;
41247         p->abs_requests++;
41248 -       
41249 +
41250         p->bytes_written += con->bytes_written_cur_second;
41251 -       
41252 +
41253         return HANDLER_GO_ON;
41254  }
41255  
41256  int mod_status_plugin_init(plugin *p) {
41257         p->version     = LIGHTTPD_VERSION_ID;
41258         p->name        = buffer_init_string("status");
41259 -       
41260 +
41261         p->init        = mod_status_init;
41262         p->cleanup     = mod_status_free;
41263         p->set_defaults= mod_status_set_defaults;
41264 -       
41265 +
41266         p->handle_uri_clean    = mod_status_handler;
41267         p->handle_trigger      = mod_status_trigger;
41268         p->handle_request_done = mod_status_account;
41269 -       
41270 +
41271         p->data        = NULL;
41272 -       
41273 +
41274         return 0;
41275  }
41276 --- ../lighttpd-1.4.11/src/mod_trigger_b4_dl.c  2005-09-23 22:53:55.000000000 +0300
41277 +++ lighttpd-1.4.12/src/mod_trigger_b4_dl.c     2006-07-16 00:26:03.000000000 +0300
41278 @@ -24,18 +24,18 @@
41279  
41280  /**
41281   * this is a trigger_b4_dl for a lighttpd plugin
41282 - * 
41283 + *
41284   */
41285  
41286  /* plugin config for all request/connections */
41287  
41288  typedef struct {
41289         buffer *db_filename;
41290 -       
41291 +
41292         buffer *trigger_url;
41293         buffer *download_url;
41294         buffer *deny_url;
41295 -       
41296 +
41297         array  *mc_hosts;
41298         buffer *mc_namespace;
41299  #if defined(HAVE_PCRE_H)
41300 @@ -46,58 +46,58 @@
41301         GDBM_FILE db;
41302  #endif
41303  
41304 -#if defined(HAVE_MEMCACHE_H) 
41305 +#if defined(HAVE_MEMCACHE_H)
41306         struct memcache *mc;
41307  #endif
41308 -       
41309 +
41310         unsigned short trigger_timeout;
41311         unsigned short debug;
41312  } plugin_config;
41313  
41314  typedef struct {
41315         PLUGIN_DATA;
41316 -       
41317 +
41318         buffer *tmp_buf;
41319 -       
41320 +
41321         plugin_config **config_storage;
41322 -       
41323 -       plugin_config conf; 
41324 +
41325 +       plugin_config conf;
41326  } plugin_data;
41327  
41328  /* init the plugin data */
41329  INIT_FUNC(mod_trigger_b4_dl_init) {
41330         plugin_data *p;
41331 -       
41332 +
41333         p = calloc(1, sizeof(*p));
41334 -       
41335 +
41336         p->tmp_buf = buffer_init();
41337 -       
41338 +
41339         return p;
41340  }
41341  
41342  /* detroy the plugin data */
41343  FREE_FUNC(mod_trigger_b4_dl_free) {
41344         plugin_data *p = p_d;
41345 -       
41346 +
41347         UNUSED(srv);
41348  
41349         if (!p) return HANDLER_GO_ON;
41350 -       
41351 +
41352         if (p->config_storage) {
41353                 size_t i;
41354                 for (i = 0; i < srv->config_context->used; i++) {
41355                         plugin_config *s = p->config_storage[i];
41356  
41357                         if (!s) continue;
41358 -                       
41359 +
41360                         buffer_free(s->db_filename);
41361                         buffer_free(s->download_url);
41362                         buffer_free(s->trigger_url);
41363                         buffer_free(s->deny_url);
41364 -                       
41365 +
41366                         buffer_free(s->mc_namespace);
41367                         array_free(s->mc_hosts);
41368 -                       
41369 +
41370  #if defined(HAVE_PCRE_H)
41371                         if (s->trigger_regex) pcre_free(s->trigger_regex);
41372                         if (s->download_regex) pcre_free(s->download_regex);
41373 @@ -108,16 +108,16 @@
41374  #if defined(HAVE_MEMCACHE_H)
41375                         if (s->mc) mc_free(s->mc);
41376  #endif
41377 -                       
41378 +
41379                         free(s);
41380                 }
41381                 free(p->config_storage);
41382         }
41383 -       
41384 +
41385         buffer_free(p->tmp_buf);
41386 -       
41387 +
41388         free(p);
41389 -       
41390 +
41391         return HANDLER_GO_ON;
41392  }
41393  
41394 @@ -126,9 +126,9 @@
41395  SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) {
41396         plugin_data *p = p_d;
41397         size_t i = 0;
41398 -       
41399 -       
41400 -       config_values_t cv[] = { 
41401 +
41402 +
41403 +       config_values_t cv[] = {
41404                 { "trigger-before-download.gdbm-filename",   NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
41405                 { "trigger-before-download.trigger-url",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
41406                 { "trigger-before-download.download-url",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
41407 @@ -139,18 +139,18 @@
41408                 { "trigger-before-download.debug",           NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 7 */
41409                 { NULL,                        NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
41410         };
41411 -       
41412 +
41413         if (!p) return HANDLER_ERROR;
41414 -       
41415 +
41416         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
41417 -       
41418 +
41419         for (i = 0; i < srv->config_context->used; i++) {
41420                 plugin_config *s;
41421  #if defined(HAVE_PCRE_H)
41422                 const char *errptr;
41423                 int erroff;
41424  #endif
41425 -               
41426 +
41427                 s = calloc(1, sizeof(plugin_config));
41428                 s->db_filename    = buffer_init();
41429                 s->download_url   = buffer_init();
41430 @@ -158,7 +158,7 @@
41431                 s->deny_url       = buffer_init();
41432                 s->mc_hosts       = array_init();
41433                 s->mc_namespace   = buffer_init();
41434 -               
41435 +
41436                 cv[0].destination = s->db_filename;
41437                 cv[1].destination = s->trigger_url;
41438                 cv[2].destination = s->download_url;
41439 @@ -167,41 +167,41 @@
41440                 cv[5].destination = s->mc_hosts;
41441                 cv[6].destination = s->mc_namespace;
41442                 cv[7].destination = &(s->debug);
41443 -               
41444 +
41445                 p->config_storage[i] = s;
41446 -       
41447 +
41448                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
41449                         return HANDLER_ERROR;
41450                 }
41451  #if defined(HAVE_GDBM_H)
41452                 if (!buffer_is_empty(s->db_filename)) {
41453                         if (NULL == (s->db = gdbm_open(s->db_filename->ptr, 4096, GDBM_WRCREAT | GDBM_NOLOCK, S_IRUSR | S_IWUSR, 0))) {
41454 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
41455 +                               log_error_write(srv, __FILE__, __LINE__, "s",
41456                                                 "gdbm-open failed");
41457                                 return HANDLER_ERROR;
41458                         }
41459                 }
41460  #endif
41461 -#if defined(HAVE_PCRE_H)               
41462 +#if defined(HAVE_PCRE_H)
41463                 if (!buffer_is_empty(s->download_url)) {
41464                         if (NULL == (s->download_regex = pcre_compile(s->download_url->ptr,
41465                                                                       0, &errptr, &erroff, NULL))) {
41466 -                               
41467 -                               log_error_write(srv, __FILE__, __LINE__, "sbss", 
41468 -                                               "compiling regex for download-url failed:", 
41469 +
41470 +                               log_error_write(srv, __FILE__, __LINE__, "sbss",
41471 +                                               "compiling regex for download-url failed:",
41472                                                 s->download_url, "pos:", erroff);
41473                                 return HANDLER_ERROR;
41474                         }
41475                 }
41476 -               
41477 +
41478                 if (!buffer_is_empty(s->trigger_url)) {
41479                         if (NULL == (s->trigger_regex = pcre_compile(s->trigger_url->ptr,
41480                                                                      0, &errptr, &erroff, NULL))) {
41481 -                               
41482 -                               log_error_write(srv, __FILE__, __LINE__, "sbss", 
41483 -                                               "compiling regex for trigger-url failed:", 
41484 +
41485 +                               log_error_write(srv, __FILE__, __LINE__, "sbss",
41486 +                                               "compiling regex for trigger-url failed:",
41487                                                 s->trigger_url, "pos:", erroff);
41488 -                               
41489 +
41490                                 return HANDLER_ERROR;
41491                         }
41492                 }
41493 @@ -211,100 +211,97 @@
41494  #if defined(HAVE_MEMCACHE_H)
41495                         size_t k;
41496                         s->mc = mc_new();
41497 -               
41498 +
41499                         for (k = 0; k < s->mc_hosts->used; k++) {
41500                                 data_string *ds = (data_string *)s->mc_hosts->data[k];
41501 -                               
41502 +
41503                                 if (0 != mc_server_add4(s->mc, ds->value->ptr)) {
41504 -                                       log_error_write(srv, __FILE__, __LINE__, "sb", 
41505 -                                                       "connection to host failed:", 
41506 +                                       log_error_write(srv, __FILE__, __LINE__, "sb",
41507 +                                                       "connection to host failed:",
41508                                                         ds->value);
41509 -                                       
41510 +
41511                                         return HANDLER_ERROR;
41512                                 }
41513                         }
41514  #else
41515 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
41516 +                       log_error_write(srv, __FILE__, __LINE__, "s",
41517                                         "memcache support is not compiled in but trigger-before-download.memcache-hosts is set, aborting");
41518                         return HANDLER_ERROR;
41519  #endif
41520                 }
41521 -               
41522 +
41523  
41524  #if (!defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H)) || !defined(HAVE_PCRE_H)
41525 -               log_error_write(srv, __FILE__, __LINE__, "s", 
41526 +               log_error_write(srv, __FILE__, __LINE__, "s",
41527                                 "(either gdbm or libmemcache) and pcre are require, but were not found, aborting");
41528                 return HANDLER_ERROR;
41529  #endif
41530         }
41531 -       
41532 +
41533         return HANDLER_GO_ON;
41534  }
41535  
41536 -#define PATCH(x) \
41537 -       p->conf.x = s->x;
41538  static int mod_trigger_b4_dl_patch_connection(server *srv, connection *con, plugin_data *p) {
41539         size_t i, j;
41540         plugin_config *s = p->config_storage[0];
41541 -       
41542 +
41543  #if defined(HAVE_GDBM)
41544 -       PATCH(db);
41545 -#endif 
41546 +       PATCH_OPTION(db);
41547 +#endif
41548  #if defined(HAVE_PCRE_H)
41549 -       PATCH(download_regex);
41550 -       PATCH(trigger_regex);
41551 -#endif 
41552 -       PATCH(trigger_timeout);
41553 -       PATCH(deny_url);
41554 -       PATCH(mc_namespace);
41555 -       PATCH(debug);
41556 +       PATCH_OPTION(download_regex);
41557 +       PATCH_OPTION(trigger_regex);
41558 +#endif
41559 +       PATCH_OPTION(trigger_timeout);
41560 +       PATCH_OPTION(deny_url);
41561 +       PATCH_OPTION(mc_namespace);
41562 +       PATCH_OPTION(debug);
41563  #if defined(HAVE_MEMCACHE_H)
41564 -       PATCH(mc);
41565 +       PATCH_OPTION(mc);
41566  #endif
41567 -       
41568 +
41569         /* skip the first, the global context */
41570         for (i = 1; i < srv->config_context->used; i++) {
41571                 data_config *dc = (data_config *)srv->config_context->data[i];
41572                 s = p->config_storage[i];
41573 -               
41574 +
41575                 /* condition didn't match */
41576                 if (!config_check_cond(srv, con, dc)) continue;
41577 -               
41578 +
41579                 /* merge config */
41580                 for (j = 0; j < dc->value->used; j++) {
41581                         data_unset *du = dc->value->data[j];
41582  
41583                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.download-url"))) {
41584  #if defined(HAVE_PCRE_H)
41585 -                               PATCH(download_regex);
41586 +                               PATCH_OPTION(download_regex);
41587  #endif
41588                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-url"))) {
41589  # if defined(HAVE_PCRE_H)
41590 -                               PATCH(trigger_regex);
41591 +                               PATCH_OPTION(trigger_regex);
41592  # endif
41593                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.gdbm-filename"))) {
41594  #if defined(HAVE_GDBM_H)
41595 -                               PATCH(db);
41596 +                               PATCH_OPTION(db);
41597  #endif
41598                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-timeout"))) {
41599 -                               PATCH(trigger_timeout);
41600 +                               PATCH_OPTION(trigger_timeout);
41601                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.debug"))) {
41602 -                               PATCH(debug);
41603 +                               PATCH_OPTION(debug);
41604                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.deny-url"))) {
41605 -                               PATCH(deny_url);
41606 +                               PATCH_OPTION(deny_url);
41607                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-namespace"))) {
41608 -                               PATCH(mc_namespace);
41609 +                               PATCH_OPTION(mc_namespace);
41610                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-hosts"))) {
41611  #if defined(HAVE_MEMCACHE_H)
41612 -                               PATCH(mc);
41613 +                               PATCH_OPTION(mc);
41614  #endif
41615                         }
41616                 }
41617         }
41618 -       
41619 +
41620         return 0;
41621  }
41622 -#undef PATCH
41623  
41624  URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
41625         plugin_data *p = p_d;
41626 @@ -315,20 +312,20 @@
41627         int n;
41628  # define N 10
41629         int ovec[N * 3];
41630 -       
41631 +
41632         if (con->uri.path->used == 0) return HANDLER_GO_ON;
41633 -       
41634 +
41635         mod_trigger_b4_dl_patch_connection(srv, con, p);
41636 -       
41637 +
41638         if (!p->conf.trigger_regex || !p->conf.download_regex) return HANDLER_GO_ON;
41639 -       
41640 +
41641  # if !defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H)
41642         return HANDLER_GO_ON;
41643  # elif defined(HAVE_GDBM_H) && defined(HAVE_MEMCACHE_H)
41644         if (!p->conf.db && !p->conf.mc) return HANDLER_GO_ON;
41645         if (p->conf.db && p->conf.mc) {
41646                 /* can't decide which one */
41647 -               
41648 +
41649                 return HANDLER_GO_ON;
41650         }
41651  # elif defined(HAVE_GDBM_H)
41652 @@ -336,12 +333,12 @@
41653  # else
41654         if (!p->conf.mc) return HANDLER_GO_ON;
41655  # endif
41656 -       
41657 +
41658         if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "X-Forwarded-For"))) {
41659                 /* X-Forwarded-For contains the ip behind the proxy */
41660 -               
41661 +
41662                 remote_ip = ds->value->ptr;
41663 -               
41664 +
41665                 /* memcache can't handle spaces */
41666         } else {
41667                 remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
41668 @@ -350,13 +347,13 @@
41669         if (p->conf.debug) {
41670                 log_error_write(srv, __FILE__, __LINE__, "ss", "(debug) remote-ip:", remote_ip);
41671         }
41672 -               
41673 +
41674         /* check if URL is a trigger -> insert IP into DB */
41675         if ((n = pcre_exec(p->conf.trigger_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
41676                 if (n != PCRE_ERROR_NOMATCH) {
41677                         log_error_write(srv, __FILE__, __LINE__, "sd",
41678                                         "execution error while matching:", n);
41679 -                       
41680 +
41681                         return HANDLER_ERROR;
41682                 }
41683         } else {
41684 @@ -364,34 +361,34 @@
41685                 if (p->conf.db) {
41686                         /* the trigger matched */
41687                         datum key, val;
41688 -                       
41689 +
41690                         key.dptr = (char *)remote_ip;
41691                         key.dsize = strlen(remote_ip);
41692 -                       
41693 +
41694                         val.dptr = (char *)&(srv->cur_ts);
41695                         val.dsize = sizeof(srv->cur_ts);
41696 -                       
41697 +
41698                         if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
41699                                 log_error_write(srv, __FILE__, __LINE__, "s",
41700                                                 "insert failed");
41701                         }
41702                 }
41703  # endif
41704 -# if defined(HAVE_MEMCACHE_H)          
41705 +# if defined(HAVE_MEMCACHE_H)
41706                 if (p->conf.mc) {
41707                         size_t i;
41708                         buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace);
41709                         buffer_append_string(p->tmp_buf, remote_ip);
41710 -                       
41711 +
41712                         for (i = 0; i < p->tmp_buf->used - 1; i++) {
41713                                 if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
41714                         }
41715 -                       
41716 +
41717                         if (p->conf.debug) {
41718                                 log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) triggered IP:", p->tmp_buf);
41719                         }
41720  
41721 -                       if (0 != mc_set(p->conf.mc, 
41722 +                       if (0 != mc_set(p->conf.mc,
41723                                         CONST_BUF_LEN(p->tmp_buf),
41724                                         (char *)&(srv->cur_ts), sizeof(srv->cur_ts),
41725                                         p->conf.trigger_timeout, 0)) {
41726 @@ -401,7 +398,7 @@
41727                 }
41728  # endif
41729         }
41730 -               
41731 +
41732         /* check if URL is a download -> check IP in DB, update timestamp */
41733         if ((n = pcre_exec(p->conf.download_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
41734                 if (n != PCRE_ERROR_NOMATCH) {
41735 @@ -411,93 +408,93 @@
41736                 }
41737         } else {
41738                 /* the download uri matched */
41739 -# if defined(HAVE_GDBM_H)              
41740 +# if defined(HAVE_GDBM_H)
41741                 if (p->conf.db) {
41742                         datum key, val;
41743                         time_t last_hit;
41744 -               
41745 +
41746                         key.dptr = (char *)remote_ip;
41747                         key.dsize = strlen(remote_ip);
41748 -                       
41749 +
41750                         val = gdbm_fetch(p->conf.db, key);
41751 -               
41752 +
41753                         if (val.dptr == NULL) {
41754                                 /* not found, redirect */
41755 -                               
41756 +
41757                                 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
41758 -                               
41759 +
41760                                 con->http_status = 307;
41761 -                               
41762 +
41763                                 return HANDLER_FINISHED;
41764                         }
41765 -                       
41766 +
41767                         last_hit = *(time_t *)(val.dptr);
41768 -                       
41769 +
41770                         free(val.dptr);
41771 -                       
41772 +
41773                         if (srv->cur_ts - last_hit > p->conf.trigger_timeout) {
41774                                 /* found, but timeout, redirect */
41775 -                               
41776 +
41777                                 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
41778                                 con->http_status = 307;
41779 -                               
41780 +
41781                                 if (p->conf.db) {
41782                                         if (0 != gdbm_delete(p->conf.db, key)) {
41783                                                 log_error_write(srv, __FILE__, __LINE__, "s",
41784                                                                 "delete failed");
41785                                         }
41786                                 }
41787 -                               
41788 +
41789                                 return HANDLER_FINISHED;
41790                         }
41791 -                       
41792 +
41793                         val.dptr = (char *)&(srv->cur_ts);
41794                         val.dsize = sizeof(srv->cur_ts);
41795 -                       
41796 +
41797                         if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
41798                                 log_error_write(srv, __FILE__, __LINE__, "s",
41799                                                 "insert failed");
41800                         }
41801                 }
41802  # endif
41803 -               
41804 -# if defined(HAVE_MEMCACHE_H)          
41805 +
41806 +# if defined(HAVE_MEMCACHE_H)
41807                 if (p->conf.mc) {
41808                         void *r;
41809                         size_t i;
41810 -                       
41811 +
41812                         buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace);
41813                         buffer_append_string(p->tmp_buf, remote_ip);
41814 -                       
41815 +
41816                         for (i = 0; i < p->tmp_buf->used - 1; i++) {
41817                                 if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
41818                         }
41819 -                       
41820 +
41821                         if (p->conf.debug) {
41822                                 log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) checking IP:", p->tmp_buf);
41823                         }
41824  
41825                         /**
41826 -                        * 
41827 +                        *
41828                          * memcached is do expiration for us, as long as we can fetch it every thing is ok
41829 -                        * and the timestamp is updated 
41830 -                        * 
41831 +                        * and the timestamp is updated
41832 +                        *
41833                          */
41834 -                       if (NULL == (r = mc_aget(p->conf.mc, 
41835 +                       if (NULL == (r = mc_aget(p->conf.mc,
41836                                                  CONST_BUF_LEN(p->tmp_buf)
41837                                                  ))) {
41838 -                               
41839 +
41840                                 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
41841 -                               
41842 +
41843                                 con->http_status = 307;
41844 -                               
41845 +
41846                                 return HANDLER_FINISHED;
41847                         }
41848 -                       
41849 +
41850                         free(r);
41851 -                       
41852 +
41853                         /* set a new timeout */
41854 -                       if (0 != mc_set(p->conf.mc, 
41855 +                       if (0 != mc_set(p->conf.mc,
41856                                         CONST_BUF_LEN(p->tmp_buf),
41857                                         (char *)&(srv->cur_ts), sizeof(srv->cur_ts),
41858                                         p->conf.trigger_timeout, 0)) {
41859 @@ -507,13 +504,13 @@
41860                 }
41861  # endif
41862         }
41863 -       
41864 +
41865  #else
41866         UNUSED(srv);
41867         UNUSED(con);
41868         UNUSED(p_d);
41869  #endif
41870 -       
41871 +
41872         return HANDLER_GO_ON;
41873  }
41874  
41875 @@ -521,21 +518,21 @@
41876  TRIGGER_FUNC(mod_trigger_b4_dl_handle_trigger) {
41877         plugin_data *p = p_d;
41878         size_t i;
41879 -       
41880 +
41881         /* check DB each minute */
41882         if (srv->cur_ts % 60 != 0) return HANDLER_GO_ON;
41883 -       
41884 +
41885         /* cleanup */
41886         for (i = 0; i < srv->config_context->used; i++) {
41887                 plugin_config *s = p->config_storage[i];
41888                 datum key, val, okey;
41889 -               
41890 +
41891                 if (!s->db) continue;
41892 -               
41893 +
41894                 okey.dptr = NULL;
41895 -               
41896 -               /* according to the manual this loop + delete does delete all entries on its way 
41897 -                * 
41898 +
41899 +               /* according to the manual this loop + delete does delete all entries on its way
41900 +                *
41901                  * we don't care as the next round will remove them. We don't have to perfect here.
41902                  */
41903                 for (key = gdbm_firstkey(s->db); key.dptr; key = gdbm_nextkey(s->db, okey)) {
41904 @@ -544,21 +541,21 @@
41905                                 free(okey.dptr);
41906                                 okey.dptr = NULL;
41907                         }
41908 -                       
41909 +
41910                         val = gdbm_fetch(s->db, key);
41911 -                       
41912 +
41913                         last_hit = *(time_t *)(val.dptr);
41914 -                       
41915 +
41916                         free(val.dptr);
41917 -                       
41918 +
41919                         if (srv->cur_ts - last_hit > s->trigger_timeout) {
41920                                 gdbm_delete(s->db, key);
41921                         }
41922 -                       
41923 +
41924                         okey = key;
41925                 }
41926                 if (okey.dptr) free(okey.dptr);
41927 -               
41928 +
41929                 /* reorg once a day */
41930                 if ((srv->cur_ts % (60 * 60 * 24) != 0)) gdbm_reorganize(s->db);
41931         }
41932 @@ -571,7 +568,7 @@
41933  int mod_trigger_b4_dl_plugin_init(plugin *p) {
41934         p->version     = LIGHTTPD_VERSION_ID;
41935         p->name        = buffer_init_string("trigger_b4_dl");
41936 -       
41937 +
41938         p->init        = mod_trigger_b4_dl_init;
41939         p->handle_uri_clean  = mod_trigger_b4_dl_uri_handler;
41940         p->set_defaults  = mod_trigger_b4_dl_set_defaults;
41941 @@ -579,8 +576,8 @@
41942         p->handle_trigger  = mod_trigger_b4_dl_handle_trigger;
41943  #endif
41944         p->cleanup     = mod_trigger_b4_dl_free;
41945 -       
41946 +
41947         p->data        = NULL;
41948 -       
41949 +
41950         return 0;
41951  }
41952 --- ../lighttpd-1.4.11/src/mod_userdir.c        2005-10-28 16:48:28.000000000 +0300
41953 +++ lighttpd-1.4.12/src/mod_userdir.c   2006-07-16 00:26:04.000000000 +0300
41954 @@ -10,6 +10,7 @@
41955  #include "response.h"
41956  
41957  #include "plugin.h"
41958 +#include "sys-files.h"
41959  
41960  #ifdef HAVE_PWD_H
41961  #include <pwd.h>
41962 @@ -25,54 +26,54 @@
41963  
41964  typedef struct {
41965         PLUGIN_DATA;
41966 -       
41967 +
41968         buffer *username;
41969         buffer *temp_path;
41970 -       
41971 +
41972         plugin_config **config_storage;
41973 -       
41974 -       plugin_config conf; 
41975 +
41976 +       plugin_config conf;
41977  } plugin_data;
41978  
41979  /* init the plugin data */
41980  INIT_FUNC(mod_userdir_init) {
41981         plugin_data *p;
41982 -       
41983 +
41984         p = calloc(1, sizeof(*p));
41985 -       
41986 +
41987         p->username = buffer_init();
41988         p->temp_path = buffer_init();
41989 -       
41990 +
41991         return p;
41992  }
41993  
41994  /* detroy the plugin data */
41995  FREE_FUNC(mod_userdir_free) {
41996         plugin_data *p = p_d;
41997 -       
41998 +
41999         if (!p) return HANDLER_GO_ON;
42000 -       
42001 +
42002         if (p->config_storage) {
42003                 size_t i;
42004 -               
42005 +
42006                 for (i = 0; i < srv->config_context->used; i++) {
42007                         plugin_config *s = p->config_storage[i];
42008 -                       
42009 +
42010                         array_free(s->include_user);
42011                         array_free(s->exclude_user);
42012                         buffer_free(s->path);
42013                         buffer_free(s->basepath);
42014 -                       
42015 +
42016                         free(s);
42017                 }
42018                 free(p->config_storage);
42019         }
42020 -       
42021 +
42022         buffer_free(p->username);
42023         buffer_free(p->temp_path);
42024 -       
42025 +
42026         free(p);
42027 -       
42028 +
42029         return HANDLER_GO_ON;
42030  }
42031  
42032 @@ -81,81 +82,78 @@
42033  SETDEFAULTS_FUNC(mod_userdir_set_defaults) {
42034         plugin_data *p = p_d;
42035         size_t i;
42036 -       
42037 -       config_values_t cv[] = { 
42038 +
42039 +       config_values_t cv[] = {
42040                 { "userdir.path",               NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
42041                 { "userdir.exclude-user",       NULL, T_CONFIG_ARRAY,  T_CONFIG_SCOPE_CONNECTION },       /* 1 */
42042                 { "userdir.include-user",       NULL, T_CONFIG_ARRAY,  T_CONFIG_SCOPE_CONNECTION },       /* 2 */
42043                 { "userdir.basepath",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
42044                 { NULL,                         NULL, T_CONFIG_UNSET,  T_CONFIG_SCOPE_UNSET }
42045         };
42046 -       
42047 +
42048         if (!p) return HANDLER_ERROR;
42049 -       
42050 +
42051         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
42052 -       
42053 +
42054         for (i = 0; i < srv->config_context->used; i++) {
42055                 plugin_config *s;
42056 -               
42057 +
42058                 s = calloc(1, sizeof(plugin_config));
42059                 s->exclude_user = array_init();
42060                 s->include_user = array_init();
42061                 s->path = buffer_init();
42062                 s->basepath = buffer_init();
42063 -       
42064 +
42065                 cv[0].destination = s->path;
42066                 cv[1].destination = s->exclude_user;
42067                 cv[2].destination = s->include_user;
42068                 cv[3].destination = s->basepath;
42069 -               
42070 +
42071                 p->config_storage[i] = s;
42072 -       
42073 +
42074                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
42075                         return HANDLER_ERROR;
42076                 }
42077         }
42078 -       
42079 +
42080         return HANDLER_GO_ON;
42081  }
42082  
42083 -#define PATCH(x) \
42084 -       p->conf.x = s->x;
42085  static int mod_userdir_patch_connection(server *srv, connection *con, plugin_data *p) {
42086         size_t i, j;
42087         plugin_config *s = p->config_storage[0];
42088 -       
42089 -       PATCH(path);
42090 -       PATCH(exclude_user);
42091 -       PATCH(include_user);
42092 -       PATCH(basepath);
42093 -       
42094 +
42095 +       PATCH_OPTION(path);
42096 +       PATCH_OPTION(exclude_user);
42097 +       PATCH_OPTION(include_user);
42098 +       PATCH_OPTION(basepath);
42099 +
42100         /* skip the first, the global context */
42101         for (i = 1; i < srv->config_context->used; i++) {
42102                 data_config *dc = (data_config *)srv->config_context->data[i];
42103                 s = p->config_storage[i];
42104 -               
42105 +
42106                 /* condition didn't match */
42107                 if (!config_check_cond(srv, con, dc)) continue;
42108 -               
42109 +
42110                 /* merge config */
42111                 for (j = 0; j < dc->value->used; j++) {
42112                         data_unset *du = dc->value->data[j];
42113 -                       
42114 +
42115                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.path"))) {
42116 -                               PATCH(path);
42117 +                               PATCH_OPTION(path);
42118                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.exclude-user"))) {
42119 -                               PATCH(exclude_user);
42120 +                               PATCH_OPTION(exclude_user);
42121                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.include-user"))) {
42122 -                               PATCH(include_user);
42123 +                               PATCH_OPTION(include_user);
42124                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.basepath"))) {
42125 -                               PATCH(basepath);
42126 +                               PATCH_OPTION(basepath);
42127                         }
42128                 }
42129         }
42130 -       
42131 +
42132         return 0;
42133  }
42134 -#undef PATCH
42135  
42136  URIHANDLER_FUNC(mod_userdir_docroot_handler) {
42137         plugin_data *p = p_d;
42138 @@ -169,18 +167,18 @@
42139         if (con->uri.path->used == 0) return HANDLER_GO_ON;
42140  
42141         mod_userdir_patch_connection(srv, con, p);
42142 -       
42143 +
42144         uri_len = con->uri.path->used - 1;
42145 -       
42146 +
42147         /* /~user/foo.html -> /home/user/public_html/foo.html */
42148 -       
42149 +
42150         if (con->uri.path->ptr[0] != '/' ||
42151             con->uri.path->ptr[1] != '~') return HANDLER_GO_ON;
42152 -       
42153 +
42154         if (NULL == (rel_url = strchr(con->uri.path->ptr + 2, '/'))) {
42155                 /* / is missing -> redirect to .../ as we are a user - DIRECTORY ! :) */
42156                 http_response_redirect_to_directory(srv, con);
42157 -               
42158 +
42159                 return HANDLER_FINISHED;
42160         }
42161  
42162 @@ -188,10 +186,10 @@
42163         if (0 == rel_url - (con->uri.path->ptr + 2)) {
42164                 return HANDLER_GO_ON;
42165         }
42166 -       
42167 +
42168         buffer_copy_string_len(p->username, con->uri.path->ptr + 2, rel_url - (con->uri.path->ptr + 2));
42169 -       
42170 -       if (buffer_is_empty(p->conf.basepath) 
42171 +
42172 +       if (buffer_is_empty(p->conf.basepath)
42173  #ifdef HAVE_PWD_H
42174             && NULL == (pwd = getpwnam(p->username->ptr))
42175  #endif
42176 @@ -200,31 +198,31 @@
42177                 return HANDLER_GO_ON;
42178         }
42179  
42180 -       
42181 +
42182         for (k = 0; k < p->conf.exclude_user->used; k++) {
42183                 data_string *ds = (data_string *)p->conf.exclude_user->data[k];
42184 -               
42185 +
42186                 if (buffer_is_equal(ds->value, p->username)) {
42187                         /* user in exclude list */
42188                         return HANDLER_GO_ON;
42189                 }
42190         }
42191 -       
42192 +
42193         if (p->conf.include_user->used) {
42194                 int found_user = 0;
42195                 for (k = 0; k < p->conf.include_user->used; k++) {
42196                         data_string *ds = (data_string *)p->conf.include_user->data[k];
42197 -                       
42198 +
42199                         if (buffer_is_equal(ds->value, p->username)) {
42200                                 /* user in include list */
42201                                 found_user = 1;
42202                                 break;
42203                         }
42204                 }
42205 -               
42206 +
42207                 if (!found_user) return HANDLER_GO_ON;
42208         }
42209 -       
42210 +
42211         /* we build the physical path */
42212  
42213         if (buffer_is_empty(p->conf.basepath)) {
42214 @@ -252,23 +250,23 @@
42215                 }
42216  
42217                 buffer_copy_string_buffer(p->temp_path, p->conf.basepath);
42218 -               BUFFER_APPEND_SLASH(p->temp_path);
42219 +               PATHNAME_APPEND_SLASH(p->temp_path);
42220                 buffer_append_string_buffer(p->temp_path, p->username);
42221         }
42222 -       BUFFER_APPEND_SLASH(p->temp_path);
42223 -       buffer_append_string_buffer(p->temp_path, p->conf.path); 
42224 +       PATHNAME_APPEND_SLASH(p->temp_path);
42225 +       buffer_append_string_buffer(p->temp_path, p->conf.path);
42226  
42227         if (buffer_is_empty(p->conf.basepath)) {
42228                 struct stat st;
42229                 int ret;
42230 -               
42231 +
42232                 ret = stat(p->temp_path->ptr, &st);
42233                 if (ret < 0 || S_ISDIR(st.st_mode) != 1) {
42234                         return HANDLER_GO_ON;
42235 -               } 
42236 +               }
42237         }
42238  
42239 -       BUFFER_APPEND_SLASH(p->temp_path);
42240 +       PATHNAME_APPEND_SLASH(p->temp_path);
42241         buffer_append_string(p->temp_path, rel_url + 1); /* skip the / */
42242         buffer_copy_string_buffer(con->physical.path, p->temp_path);
42243  
42244 @@ -282,13 +280,13 @@
42245  int mod_userdir_plugin_init(plugin *p) {
42246         p->version     = LIGHTTPD_VERSION_ID;
42247         p->name        = buffer_init_string("userdir");
42248 -       
42249 +
42250         p->init           = mod_userdir_init;
42251         p->handle_physical = mod_userdir_docroot_handler;
42252         p->set_defaults   = mod_userdir_set_defaults;
42253         p->cleanup        = mod_userdir_free;
42254 -       
42255 +
42256         p->data        = NULL;
42257 -       
42258 +
42259         return 0;
42260  }
42261 --- ../lighttpd-1.4.11/src/mod_usertrack.c      2006-01-31 15:01:20.000000000 +0200
42262 +++ lighttpd-1.4.12/src/mod_usertrack.c 2006-07-16 00:26:04.000000000 +0300
42263 @@ -24,44 +24,44 @@
42264  
42265  typedef struct {
42266         PLUGIN_DATA;
42267 -       
42268 +
42269         plugin_config **config_storage;
42270 -       
42271 -       plugin_config conf; 
42272 +
42273 +       plugin_config conf;
42274  } plugin_data;
42275  
42276  /* init the plugin data */
42277  INIT_FUNC(mod_usertrack_init) {
42278         plugin_data *p;
42279 -       
42280 +
42281         p = calloc(1, sizeof(*p));
42282 -       
42283 +
42284         return p;
42285  }
42286  
42287  /* detroy the plugin data */
42288  FREE_FUNC(mod_usertrack_free) {
42289         plugin_data *p = p_d;
42290 -       
42291 +
42292         UNUSED(srv);
42293 -       
42294 +
42295         if (!p) return HANDLER_GO_ON;
42296 -       
42297 +
42298         if (p->config_storage) {
42299                 size_t i;
42300                 for (i = 0; i < srv->config_context->used; i++) {
42301                         plugin_config *s = p->config_storage[i];
42302 -                       
42303 +
42304                         buffer_free(s->cookie_name);
42305                         buffer_free(s->cookie_domain);
42306 -                       
42307 +
42308                         free(s);
42309                 }
42310                 free(p->config_storage);
42311         }
42312 -       
42313 +
42314         free(p);
42315 -       
42316 +
42317         return HANDLER_GO_ON;
42318  }
42319  
42320 @@ -70,38 +70,38 @@
42321  SETDEFAULTS_FUNC(mod_usertrack_set_defaults) {
42322         plugin_data *p = p_d;
42323         size_t i = 0;
42324 -       
42325 -       config_values_t cv[] = { 
42326 +
42327 +       config_values_t cv[] = {
42328                 { "usertrack.cookie-name",       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
42329                 { "usertrack.cookie-max-age",    NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 1 */
42330                 { "usertrack.cookie-domain",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
42331 -               
42332 -               { "usertrack.cookiename",        NULL, T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION },   
42333 +
42334 +               { "usertrack.cookiename",        NULL, T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION },
42335                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
42336         };
42337 -       
42338 +
42339         if (!p) return HANDLER_ERROR;
42340 -       
42341 +
42342         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
42343 -       
42344 +
42345         for (i = 0; i < srv->config_context->used; i++) {
42346                 plugin_config *s;
42347 -               
42348 +
42349                 s = calloc(1, sizeof(plugin_config));
42350                 s->cookie_name    = buffer_init();
42351                 s->cookie_domain  = buffer_init();
42352                 s->cookie_max_age = 0;
42353 -               
42354 +
42355                 cv[0].destination = s->cookie_name;
42356                 cv[1].destination = &(s->cookie_max_age);
42357                 cv[2].destination = s->cookie_domain;
42358 -               
42359 +
42360                 p->config_storage[i] = s;
42361 -       
42362 +
42363                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
42364                         return HANDLER_ERROR;
42365                 }
42366 -       
42367 +
42368                 if (buffer_is_empty(s->cookie_name)) {
42369                         buffer_copy_string(s->cookie_name, "TRACKID");
42370                 } else {
42371 @@ -109,68 +109,65 @@
42372                         for (j = 0; j < s->cookie_name->used - 1; j++) {
42373                                 char c = s->cookie_name->ptr[j] | 32;
42374                                 if (c < 'a' || c > 'z') {
42375 -                                       log_error_write(srv, __FILE__, __LINE__, "sb", 
42376 -                                                       "invalid character in usertrack.cookie-name:", 
42377 +                                       log_error_write(srv, __FILE__, __LINE__, "sb",
42378 +                                                       "invalid character in usertrack.cookie-name:",
42379                                                         s->cookie_name);
42380 -                                       
42381 +
42382                                         return HANDLER_ERROR;
42383                                 }
42384                         }
42385                 }
42386 -               
42387 +
42388                 if (!buffer_is_empty(s->cookie_domain)) {
42389                         size_t j;
42390                         for (j = 0; j < s->cookie_domain->used - 1; j++) {
42391                                 char c = s->cookie_domain->ptr[j];
42392                                 if (c <= 32 || c >= 127 || c == '"' || c == '\\') {
42393 -                                       log_error_write(srv, __FILE__, __LINE__, "sb", 
42394 -                                                       "invalid character in usertrack.cookie-domain:", 
42395 +                                       log_error_write(srv, __FILE__, __LINE__, "sb",
42396 +                                                       "invalid character in usertrack.cookie-domain:",
42397                                                         s->cookie_domain);
42398 -                                       
42399 +
42400                                         return HANDLER_ERROR;
42401                                 }
42402                         }
42403                 }
42404         }
42405 -               
42406 +
42407         return HANDLER_GO_ON;
42408  }
42409  
42410 -#define PATCH(x) \
42411 -       p->conf.x = s->x;
42412  static int mod_usertrack_patch_connection(server *srv, connection *con, plugin_data *p) {
42413         size_t i, j;
42414         plugin_config *s = p->config_storage[0];
42415 -       
42416 -       PATCH(cookie_name);
42417 -       PATCH(cookie_domain);
42418 -       PATCH(cookie_max_age);
42419 -       
42420 +
42421 +       PATCH_OPTION(cookie_name);
42422 +       PATCH_OPTION(cookie_domain);
42423 +       PATCH_OPTION(cookie_max_age);
42424 +
42425         /* skip the first, the global context */
42426         for (i = 1; i < srv->config_context->used; i++) {
42427                 data_config *dc = (data_config *)srv->config_context->data[i];
42428                 s = p->config_storage[i];
42429 -               
42430 +
42431                 /* condition didn't match */
42432                 if (!config_check_cond(srv, con, dc)) continue;
42433 -               
42434 +
42435                 /* merge config */
42436                 for (j = 0; j < dc->value->used; j++) {
42437                         data_unset *du = dc->value->data[j];
42438 -                       
42439 +
42440                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-name"))) {
42441 -                               PATCH(cookie_name);
42442 +                               PATCH_OPTION(cookie_name);
42443                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-max-age"))) {
42444 -                               PATCH(cookie_max_age);
42445 +                               PATCH_OPTION(cookie_max_age);
42446                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-domain"))) {
42447 -                               PATCH(cookie_domain);
42448 +                               PATCH_OPTION(cookie_domain);
42449                         }
42450                 }
42451         }
42452 -       
42453 +
42454         return 0;
42455  }
42456 -#undef PATCH
42457  
42458  URIHANDLER_FUNC(mod_usertrack_uri_handler) {
42459         plugin_data *p = p_d;
42460 @@ -178,38 +175,38 @@
42461         unsigned char h[16];
42462         MD5_CTX Md5Ctx;
42463         char hh[32];
42464 -       
42465 +
42466         if (con->uri.path->used == 0) return HANDLER_GO_ON;
42467 -       
42468 +
42469         mod_usertrack_patch_connection(srv, con, p);
42470 -       
42471 +
42472         if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) {
42473                 char *g;
42474                 /* we have a cookie, does it contain a valid name ? */
42475 -               
42476 -               /* parse the cookie 
42477 -                * 
42478 +
42479 +               /* parse the cookie
42480 +                *
42481                  * check for cookiename + (WS | '=')
42482 -                * 
42483 +                *
42484                  */
42485 -               
42486 +
42487                 if (NULL != (g = strstr(ds->value->ptr, p->conf.cookie_name->ptr))) {
42488                         char *nc;
42489 -                       
42490 +
42491                         /* skip WS */
42492                         for (nc = g + p->conf.cookie_name->used-1; *nc == ' ' || *nc == '\t'; nc++);
42493 -                       
42494 +
42495                         if (*nc == '=') {
42496                                 /* ok, found the key of our own cookie */
42497 -                               
42498 +
42499                                 if (strlen(nc) > 32) {
42500                                         /* i'm lazy */
42501                                         return HANDLER_GO_ON;
42502                                 }
42503                         }
42504                 }
42505 -       } 
42506 -       
42507 +       }
42508 +
42509         /* set a cookie */
42510         if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
42511                 ds = data_response_init();
42512 @@ -217,39 +214,39 @@
42513         buffer_copy_string(ds->key, "Set-Cookie");
42514         buffer_copy_string_buffer(ds->value, p->conf.cookie_name);
42515         buffer_append_string(ds->value, "=");
42516 -       
42517 +
42518  
42519         /* taken from mod_auth.c */
42520 -       
42521 +
42522         /* generate shared-secret */
42523         MD5_Init(&Md5Ctx);
42524         MD5_Update(&Md5Ctx, (unsigned char *)con->uri.path->ptr, con->uri.path->used - 1);
42525         MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
42526 -       
42527 +
42528         /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
42529         ltostr(hh, srv->cur_ts);
42530         MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
42531         ltostr(hh, rand());
42532         MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
42533 -       
42534 +
42535         MD5_Final(h, &Md5Ctx);
42536 -       
42537 +
42538         buffer_append_string_encoded(ds->value, (char *)h, 16, ENCODING_HEX);
42539         buffer_append_string(ds->value, "; Path=/");
42540         buffer_append_string(ds->value, "; Version=1");
42541 -       
42542 +
42543         if (!buffer_is_empty(p->conf.cookie_domain)) {
42544                 buffer_append_string(ds->value, "; Domain=");
42545                 buffer_append_string_encoded(ds->value, CONST_BUF_LEN(p->conf.cookie_domain), ENCODING_REL_URI);
42546         }
42547 -       
42548 +
42549         if (p->conf.cookie_max_age) {
42550                 buffer_append_string(ds->value, "; max-age=");
42551                 buffer_append_long(ds->value, p->conf.cookie_max_age);
42552         }
42553 -       
42554 +
42555         array_insert_unique(con->response.headers, (data_unset *)ds);
42556 -       
42557 +
42558         return HANDLER_GO_ON;
42559  }
42560  
42561 @@ -258,13 +255,13 @@
42562  int mod_usertrack_plugin_init(plugin *p) {
42563         p->version     = LIGHTTPD_VERSION_ID;
42564         p->name        = buffer_init_string("usertrack");
42565 -       
42566 +
42567         p->init        = mod_usertrack_init;
42568         p->handle_uri_clean  = mod_usertrack_uri_handler;
42569         p->set_defaults  = mod_usertrack_set_defaults;
42570         p->cleanup     = mod_usertrack_free;
42571 -       
42572 +
42573         p->data        = NULL;
42574 -       
42575 +
42576         return 0;
42577  }
42578 --- ../lighttpd-1.4.11/src/mod_webdav.c 2006-03-03 01:28:58.000000000 +0200
42579 +++ lighttpd-1.4.12/src/mod_webdav.c    2006-07-18 13:03:40.000000000 +0300
42580 @@ -3,13 +3,10 @@
42581  #include <ctype.h>
42582  #include <stdlib.h>
42583  #include <string.h>
42584 -#include <dirent.h>
42585  #include <errno.h>
42586 -#include <unistd.h>
42587  #include <fcntl.h>
42588  #include <stdio.h>
42589  #include <assert.h>
42590 -#include <sys/mman.h>
42591  
42592  #ifdef HAVE_CONFIG_H
42593  #include "config.h"
42594 @@ -23,6 +20,11 @@
42595  #include <sqlite3.h>
42596  #endif
42597  
42598 +#if defined(HAVE_LIBXML_H) && defined(HAVE_SQLITE3_H) && defined(HAVE_UUID_H)
42599 +#define USE_LOCKS
42600 +#include <uuid/uuid.h>
42601 +#endif
42602 +
42603  #include "base.h"
42604  #include "log.h"
42605  #include "buffer.h"
42606 @@ -33,13 +35,16 @@
42607  #include "stream.h"
42608  #include "stat_cache.h"
42609  
42610 +#include "sys-files.h"
42611 +#include "sys-mmap.h"
42612 +#include "sys-strings.h"
42613  
42614  /**
42615   * this is a webdav for a lighttpd plugin
42616   *
42617 - * at least a very basic one. 
42618 + * at least a very basic one.
42619   * - for now it is read-only and we only support PROPFIND
42620 - * 
42621 + *
42622   */
42623  
42624  
42625 @@ -58,64 +63,70 @@
42626         sqlite3_stmt *stmt_delete_prop;
42627         sqlite3_stmt *stmt_select_prop;
42628         sqlite3_stmt *stmt_select_propnames;
42629 -       
42630 +
42631         sqlite3_stmt *stmt_delete_uri;
42632         sqlite3_stmt *stmt_move_uri;
42633         sqlite3_stmt *stmt_copy_uri;
42634 +
42635 +       sqlite3_stmt *stmt_remove_lock;
42636 +       sqlite3_stmt *stmt_create_lock;
42637 +       sqlite3_stmt *stmt_read_lock;
42638 +       sqlite3_stmt *stmt_read_lock_by_uri;
42639 +       sqlite3_stmt *stmt_refresh_lock;
42640  #endif
42641  } plugin_config;
42642  
42643  typedef struct {
42644         PLUGIN_DATA;
42645 -       
42646 +
42647         buffer *tmp_buf;
42648         request_uri uri;
42649         physical physical;
42650  
42651         plugin_config **config_storage;
42652 -       
42653 -       plugin_config conf; 
42654 +
42655 +       plugin_config conf;
42656  } plugin_data;
42657  
42658  /* init the plugin data */
42659  INIT_FUNC(mod_webdav_init) {
42660         plugin_data *p;
42661 -       
42662 +
42663         p = calloc(1, sizeof(*p));
42664 -       
42665 +
42666         p->tmp_buf = buffer_init();
42667  
42668         p->uri.scheme = buffer_init();
42669         p->uri.path_raw = buffer_init();
42670         p->uri.path = buffer_init();
42671         p->uri.authority = buffer_init();
42672 -       
42673 +
42674         p->physical.path = buffer_init();
42675         p->physical.rel_path = buffer_init();
42676         p->physical.doc_root = buffer_init();
42677         p->physical.basedir = buffer_init();
42678 -       
42679 +
42680         return p;
42681  }
42682  
42683  /* detroy the plugin data */
42684  FREE_FUNC(mod_webdav_free) {
42685         plugin_data *p = p_d;
42686 -       
42687 +
42688         UNUSED(srv);
42689  
42690         if (!p) return HANDLER_GO_ON;
42691 -       
42692 +
42693         if (p->config_storage) {
42694                 size_t i;
42695                 for (i = 0; i < srv->config_context->used; i++) {
42696                         plugin_config *s = p->config_storage[i];
42697  
42698                         if (!s) continue;
42699 -       
42700 +
42701                         buffer_free(s->sqlite_db_name);
42702  #ifdef USE_PROPPATCH
42703 -                       if (s->sql) {   
42704 +                       if (s->sql) {
42705                                 sqlite3_finalize(s->stmt_delete_prop);
42706                                 sqlite3_finalize(s->stmt_delete_uri);
42707                                 sqlite3_finalize(s->stmt_copy_uri);
42708 @@ -123,9 +134,15 @@
42709                                 sqlite3_finalize(s->stmt_update_prop);
42710                                 sqlite3_finalize(s->stmt_select_prop);
42711                                 sqlite3_finalize(s->stmt_select_propnames);
42712 +
42713 +                               sqlite3_finalize(s->stmt_read_lock);
42714 +                               sqlite3_finalize(s->stmt_read_lock_by_uri);
42715 +                               sqlite3_finalize(s->stmt_create_lock);
42716 +                               sqlite3_finalize(s->stmt_remove_lock);
42717 +                               sqlite3_finalize(s->stmt_refresh_lock);
42718                                 sqlite3_close(s->sql);
42719                         }
42720 -#endif 
42721 +#endif
42722                         free(s);
42723                 }
42724                 free(p->config_storage);
42725 @@ -135,16 +152,16 @@
42726         buffer_free(p->uri.path_raw);
42727         buffer_free(p->uri.path);
42728         buffer_free(p->uri.authority);
42729 -       
42730 +
42731         buffer_free(p->physical.path);
42732         buffer_free(p->physical.rel_path);
42733         buffer_free(p->physical.doc_root);
42734         buffer_free(p->physical.basedir);
42735 -       
42736 +
42737         buffer_free(p->tmp_buf);
42738 -       
42739 +
42740         free(p);
42741 -       
42742 +
42743         return HANDLER_GO_ON;
42744  }
42745  
42746 @@ -153,32 +170,32 @@
42747  SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
42748         plugin_data *p = p_d;
42749         size_t i = 0;
42750 -       
42751 -       config_values_t cv[] = { 
42752 +
42753 +       config_values_t cv[] = {
42754                 { "webdav.activate",            NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
42755                 { "webdav.is-readonly",         NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
42756                 { "webdav.sqlite-db-name",      NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_CONNECTION },       /* 2 */
42757                 { "webdav.log-xml",             NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
42758                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
42759         };
42760 -       
42761 +
42762         if (!p) return HANDLER_ERROR;
42763 -       
42764 +
42765         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
42766 -       
42767 +
42768         for (i = 0; i < srv->config_context->used; i++) {
42769                 plugin_config *s;
42770 -               
42771 +
42772                 s = calloc(1, sizeof(plugin_config));
42773                 s->sqlite_db_name = buffer_init();
42774 -               
42775 +
42776                 cv[0].destination = &(s->enabled);
42777                 cv[1].destination = &(s->is_readonly);
42778                 cv[2].destination = s->sqlite_db_name;
42779                 cv[3].destination = &(s->log_xml);
42780 -               
42781 +
42782                 p->config_storage[i] = s;
42783 -       
42784 +
42785                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
42786                         return HANDLER_ERROR;
42787                 }
42788 @@ -193,8 +210,26 @@
42789                                 return HANDLER_ERROR;
42790                         }
42791  
42792 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42793 -                               CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"), 
42794 +                       if (SQLITE_OK != sqlite3_exec(s->sql,
42795 +                                       "CREATE TABLE properties ("
42796 +                                       "  resource TEXT NOT NULL,"
42797 +                                       "  prop TEXT NOT NULL,"
42798 +                                       "  ns TEXT NOT NULL,"
42799 +                                       "  value TEXT NOT NULL,"
42800 +                                       "  PRIMARY KEY(resource, prop, ns))",
42801 +                                       NULL, NULL, &err)) {
42802 +
42803 +                               if (0 != strcmp(err, "table properties already exists")) {
42804 +                                       log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
42805 +                                       sqlite3_free(err);
42806 +
42807 +                                       return HANDLER_ERROR;
42808 +                               }
42809 +                               sqlite3_free(err);
42810 +                       }
42811 +
42812 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42813 +                               CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
42814                                 &(s->stmt_select_prop), &next_stmt)) {
42815                                 /* prepare failed */
42816  
42817 @@ -202,8 +237,8 @@
42818                                 return HANDLER_ERROR;
42819                         }
42820  
42821 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42822 -                               CONST_STR_LEN("SELECT ns, prop FROM properties WHERE resource = ?"), 
42823 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42824 +                               CONST_STR_LEN("SELECT ns, prop FROM properties WHERE resource = ?"),
42825                                 &(s->stmt_select_propnames), &next_stmt)) {
42826                                 /* prepare failed */
42827  
42828 @@ -211,16 +246,67 @@
42829                                 return HANDLER_ERROR;
42830                         }
42831  
42832 -                       if (SQLITE_OK != sqlite3_exec(s->sql, 
42833 -                                       "CREATE TABLE properties ("
42834 +
42835 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42836 +                               CONST_STR_LEN("REPLACE INTO properties (resource, prop, ns, value) VALUES (?, ?, ?, ?)"),
42837 +                               &(s->stmt_update_prop), &next_stmt)) {
42838 +                               /* prepare failed */
42839 +
42840 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
42841 +                               return HANDLER_ERROR;
42842 +                       }
42843 +
42844 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42845 +                               CONST_STR_LEN("DELETE FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
42846 +                               &(s->stmt_delete_prop), &next_stmt)) {
42847 +                               /* prepare failed */
42848 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42849 +
42850 +                               return HANDLER_ERROR;
42851 +                       }
42852 +
42853 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42854 +                               CONST_STR_LEN("DELETE FROM properties WHERE resource = ?"),
42855 +                               &(s->stmt_delete_uri), &next_stmt)) {
42856 +                               /* prepare failed */
42857 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42858 +
42859 +                               return HANDLER_ERROR;
42860 +                       }
42861 +
42862 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42863 +                               CONST_STR_LEN("INSERT INTO properties SELECT ?, prop, ns, value FROM properties WHERE resource = ?"),
42864 +                               &(s->stmt_copy_uri), &next_stmt)) {
42865 +                               /* prepare failed */
42866 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42867 +
42868 +                               return HANDLER_ERROR;
42869 +                       }
42870 +
42871 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42872 +                               CONST_STR_LEN("UPDATE properties SET resource = ? WHERE resource = ?"),
42873 +                               &(s->stmt_move_uri), &next_stmt)) {
42874 +                               /* prepare failed */
42875 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42876 +
42877 +                               return HANDLER_ERROR;
42878 +                       }
42879 +
42880 +                       /* LOCKS */
42881 +
42882 +                       if (SQLITE_OK != sqlite3_exec(s->sql,
42883 +                                       "CREATE TABLE locks ("
42884 +                                       "  locktoken TEXT NOT NULL,"
42885                                         "  resource TEXT NOT NULL,"
42886 -                                       "  prop TEXT NOT NULL,"
42887 -                                       "  ns TEXT NOT NULL,"
42888 -                                       "  value TEXT NOT NULL,"
42889 -                                       "  PRIMARY KEY(resource, prop, ns))",
42890 +                                       "  lockscope TEXT NOT NULL,"
42891 +                                       "  locktype TEXT NOT NULL,"
42892 +                                       "  owner TEXT NOT NULL,"
42893 +                                       "  depth INT NOT NULL,"
42894 +                                       "  timeout TIMESTAMP NOT NULL,"
42895 +                                       "  PRIMARY KEY(locktoken))",
42896                                         NULL, NULL, &err)) {
42897  
42898 -                               if (0 != strcmp(err, "table properties already exists")) {
42899 +                               if (0 != strcmp(err, "table locks already exists")) {
42900                                         log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
42901                                         sqlite3_free(err);
42902  
42903 @@ -228,127 +314,138 @@
42904                                 }
42905                                 sqlite3_free(err);
42906                         }
42907 -       
42908 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42909 -                               CONST_STR_LEN("REPLACE INTO properties (resource, prop, ns, value) VALUES (?, ?, ?, ?)"), 
42910 -                               &(s->stmt_update_prop), &next_stmt)) {
42911 +
42912 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42913 +                               CONST_STR_LEN("INSERT INTO locks (locktoken, resource, lockscope, locktype, owner, depth, timeout) VALUES (?,?,?,?,?,?, CURRENT_TIME + 600)"),
42914 +                               &(s->stmt_create_lock), &next_stmt)) {
42915                                 /* prepare failed */
42916 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42917  
42918 -                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
42919                                 return HANDLER_ERROR;
42920                         }
42921  
42922 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42923 -                               CONST_STR_LEN("DELETE FROM properties WHERE resource = ? AND prop = ? AND ns = ?"), 
42924 -                               &(s->stmt_delete_prop), &next_stmt)) {
42925 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42926 +                               CONST_STR_LEN("DELETE FROM locks WHERE locktoken = ?"),
42927 +                               &(s->stmt_remove_lock), &next_stmt)) {
42928                                 /* prepare failed */
42929                                 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42930  
42931                                 return HANDLER_ERROR;
42932                         }
42933  
42934 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42935 -                               CONST_STR_LEN("DELETE FROM properties WHERE resource = ?"), 
42936 -                               &(s->stmt_delete_uri), &next_stmt)) {
42937 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42938 +                               CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout FROM locks WHERE locktoken = ?"),
42939 +                               &(s->stmt_read_lock), &next_stmt)) {
42940                                 /* prepare failed */
42941                                 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42942  
42943                                 return HANDLER_ERROR;
42944                         }
42945  
42946 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42947 -                               CONST_STR_LEN("INSERT INTO properties SELECT ?, prop, ns, value FROM properties WHERE resource = ?"), 
42948 -                               &(s->stmt_copy_uri), &next_stmt)) {
42949 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42950 +                               CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout FROM locks WHERE resource = ?"),
42951 +                               &(s->stmt_read_lock_by_uri), &next_stmt)) {
42952                                 /* prepare failed */
42953                                 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42954  
42955                                 return HANDLER_ERROR;
42956                         }
42957  
42958 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
42959 -                               CONST_STR_LEN("UPDATE properties SET resource = ? WHERE resource = ?"), 
42960 -                               &(s->stmt_move_uri), &next_stmt)) {
42961 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
42962 +                               CONST_STR_LEN("UPDATE locks SET timeout = CURRENT_TIME + 600 WHERE locktoken = ?"),
42963 +                               &(s->stmt_refresh_lock), &next_stmt)) {
42964                                 /* prepare failed */
42965                                 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42966  
42967                                 return HANDLER_ERROR;
42968                         }
42969 +
42970 +
42971  #else
42972                         log_error_write(srv, __FILE__, __LINE__, "s", "Sorry, no sqlite3 and libxml2 support include, compile with --with-webdav-props");
42973                         return HANDLER_ERROR;
42974  #endif
42975                 }
42976         }
42977 -       
42978 +
42979         return HANDLER_GO_ON;
42980  }
42981  
42982 -#define PATCH(x) \
42983 -       p->conf.x = s->x;
42984  static int mod_webdav_patch_connection(server *srv, connection *con, plugin_data *p) {
42985         size_t i, j;
42986         plugin_config *s = p->config_storage[0];
42987 -       
42988 -       PATCH(enabled);
42989 -       PATCH(is_readonly);
42990 -       PATCH(log_xml);
42991 -       
42992 +
42993 +       PATCH_OPTION(enabled);
42994 +       PATCH_OPTION(is_readonly);
42995 +       PATCH_OPTION(log_xml);
42996 +
42997  #ifdef USE_PROPPATCH
42998 -       PATCH(sql);
42999 -       PATCH(stmt_update_prop);
43000 -       PATCH(stmt_delete_prop);
43001 -       PATCH(stmt_select_prop);
43002 -       PATCH(stmt_select_propnames);
43003 -
43004 -       PATCH(stmt_delete_uri);
43005 -       PATCH(stmt_move_uri);
43006 -       PATCH(stmt_copy_uri);
43007 +       PATCH_OPTION(sql);
43008 +       PATCH_OPTION(stmt_update_prop);
43009 +       PATCH_OPTION(stmt_delete_prop);
43010 +       PATCH_OPTION(stmt_select_prop);
43011 +       PATCH_OPTION(stmt_select_propnames);
43012 +
43013 +       PATCH_OPTION(stmt_delete_uri);
43014 +       PATCH_OPTION(stmt_move_uri);
43015 +       PATCH_OPTION(stmt_copy_uri);
43016 +
43017 +       PATCH_OPTION(stmt_remove_lock);
43018 +       PATCH_OPTION(stmt_refresh_lock);
43019 +       PATCH_OPTION(stmt_create_lock);
43020 +       PATCH_OPTION(stmt_read_lock);
43021 +       PATCH_OPTION(stmt_read_lock_by_uri);
43022  #endif
43023         /* skip the first, the global context */
43024         for (i = 1; i < srv->config_context->used; i++) {
43025                 data_config *dc = (data_config *)srv->config_context->data[i];
43026                 s = p->config_storage[i];
43027 -               
43028 +
43029                 /* condition didn't match */
43030                 if (!config_check_cond(srv, con, dc)) continue;
43031 -               
43032 +
43033                 /* merge config */
43034                 for (j = 0; j < dc->value->used; j++) {
43035                         data_unset *du = dc->value->data[j];
43036 -                       
43037 +
43038                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.activate"))) {
43039 -                               PATCH(enabled);
43040 +                               PATCH_OPTION(enabled);
43041                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.is-readonly"))) {
43042 -                               PATCH(is_readonly);
43043 +                               PATCH_OPTION(is_readonly);
43044                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.log-xml"))) {
43045 -                               PATCH(log_xml);
43046 +                               PATCH_OPTION(log_xml);
43047                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.sqlite-db-name"))) {
43048  #ifdef USE_PROPPATCH
43049 -                               PATCH(sql);
43050 -                               PATCH(stmt_update_prop);
43051 -                               PATCH(stmt_delete_prop);
43052 -                               PATCH(stmt_select_prop);
43053 -                               PATCH(stmt_select_propnames);
43054 -                               
43055 -                               PATCH(stmt_delete_uri);
43056 -                               PATCH(stmt_move_uri);
43057 -                               PATCH(stmt_copy_uri);
43058 +                               PATCH_OPTION(sql);
43059 +                               PATCH_OPTION(stmt_update_prop);
43060 +                               PATCH_OPTION(stmt_delete_prop);
43061 +                               PATCH_OPTION(stmt_select_prop);
43062 +                               PATCH_OPTION(stmt_select_propnames);
43063 +
43064 +                               PATCH_OPTION(stmt_delete_uri);
43065 +                               PATCH_OPTION(stmt_move_uri);
43066 +                               PATCH_OPTION(stmt_copy_uri);
43067 +
43068 +                               PATCH_OPTION(stmt_remove_lock);
43069 +                               PATCH_OPTION(stmt_refresh_lock);
43070 +                               PATCH_OPTION(stmt_create_lock);
43071 +                               PATCH_OPTION(stmt_read_lock);
43072 +                               PATCH_OPTION(stmt_read_lock_by_uri);
43073  #endif
43074                         }
43075                 }
43076         }
43077 -       
43078 +
43079         return 0;
43080  }
43081 -#undef PATCH
43082  
43083  URIHANDLER_FUNC(mod_webdav_uri_handler) {
43084         plugin_data *p = p_d;
43085 -       
43086 +
43087         UNUSED(srv);
43088  
43089         if (con->uri.path->used == 0) return HANDLER_GO_ON;
43090 -       
43091 +
43092         mod_webdav_patch_connection(srv, con, p);
43093  
43094         if (!p->conf.enabled) return HANDLER_GO_ON;
43095 @@ -362,20 +459,20 @@
43096                 if (p->conf.is_readonly) {
43097                         response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND"));
43098                 } else {
43099 -                       response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH"));
43100 +                       response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH, LOCK, UNLOCK"));
43101                 }
43102                 break;
43103         default:
43104                 break;
43105         }
43106 -       
43107 +
43108         /* not found */
43109         return HANDLER_GO_ON;
43110  }
43111 -static int webdav_gen_prop_tag(server *srv, connection *con, 
43112 -               char *prop_name, 
43113 -               char *prop_ns, 
43114 -               char *value, 
43115 +static int webdav_gen_prop_tag(server *srv, connection *con,
43116 +               char *prop_name,
43117 +               char *prop_ns,
43118 +               char *value,
43119                 buffer *b) {
43120  
43121         UNUSED(srv);
43122 @@ -414,7 +511,7 @@
43123         buffer_append_string_buffer(b, dst->rel_path);
43124         buffer_append_string(b,"</D:href>\n");
43125         buffer_append_string(b,"<D:status>\n");
43126 -       
43127 +
43128         if (con->request.http_version == HTTP_VERSION_1_1) {
43129                 BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 ");
43130         } else {
43131 @@ -458,14 +555,13 @@
43132  
43133                         /* bind the values to the insert */
43134  
43135 -                       sqlite3_bind_text(stmt, 1, 
43136 -                                         dst->rel_path->ptr, 
43137 +                       sqlite3_bind_text(stmt, 1,
43138 +                                         dst->rel_path->ptr,
43139                                           dst->rel_path->used - 1,
43140                                           SQLITE_TRANSIENT);
43141 -                                                                       
43142 +
43143                         if (SQLITE_DONE != sqlite3_step(stmt)) {
43144                                 /* */
43145 -                               WP();
43146                         }
43147                 }
43148  #endif
43149 @@ -493,14 +589,14 @@
43150                             (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
43151                                 continue;
43152                                 /* ignore the parent dir */
43153 -                       } 
43154 +                       }
43155  
43156                         buffer_copy_string_buffer(d.path, dst->path);
43157 -                       BUFFER_APPEND_SLASH(d.path);
43158 +                       PATHNAME_APPEND_SLASH(d.path);
43159                         buffer_append_string(d.path, de->d_name);
43160 -                       
43161 +
43162                         buffer_copy_string_buffer(d.rel_path, dst->rel_path);
43163 -                       BUFFER_APPEND_SLASH(d.rel_path);
43164 +                       PATHNAME_APPEND_SLASH(d.rel_path);
43165                         buffer_append_string(d.rel_path, de->d_name);
43166  
43167                         /* stat and unlink afterwards */
43168 @@ -508,7 +604,7 @@
43169                                 /* don't about it yet, rmdir will fail too */
43170                         } else if (S_ISDIR(st.st_mode)) {
43171                                 have_multi_status = webdav_delete_dir(srv, con, p, &d, b);
43172 -                                       
43173 +
43174                                 /* try to unlink it */
43175                                 if (-1 == rmdir(d.path->ptr)) {
43176                                         switch(errno) {
43177 @@ -535,14 +631,13 @@
43178  
43179                                                 /* bind the values to the insert */
43180  
43181 -                                               sqlite3_bind_text(stmt, 1, 
43182 -                                                                 d.rel_path->ptr, 
43183 +                                               sqlite3_bind_text(stmt, 1,
43184 +                                                                 d.rel_path->ptr,
43185                                                                   d.rel_path->used - 1,
43186                                                                   SQLITE_TRANSIENT);
43187 -                                                                                                       
43188 +
43189                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {
43190                                                         /* */
43191 -                                                       WP();
43192                                                 }
43193                                         }
43194  #endif
43195 @@ -569,7 +664,7 @@
43196         if (stream_open(&s, src->path)) {
43197                 return 403;
43198         }
43199 -                       
43200 +
43201         if (-1 == (ofd = open(dst->path->ptr, O_WRONLY|O_TRUNC|O_CREAT|(overwrite ? 0 : O_EXCL), 0600))) {
43202                 /* opening the destination failed for some reason */
43203                 switch(errno) {
43204 @@ -601,7 +696,7 @@
43205                         break;
43206                 }
43207         }
43208 -       
43209 +
43210         stream_close(&s);
43211         close(ofd);
43212  
43213 @@ -614,19 +709,18 @@
43214                         sqlite3_reset(stmt);
43215  
43216                         /* bind the values to the insert */
43217 -                       sqlite3_bind_text(stmt, 1, 
43218 -                                         dst->rel_path->ptr, 
43219 +                       sqlite3_bind_text(stmt, 1,
43220 +                                         dst->rel_path->ptr,
43221                                           dst->rel_path->used - 1,
43222                                           SQLITE_TRANSIENT);
43223  
43224 -                       sqlite3_bind_text(stmt, 2, 
43225 -                                         src->rel_path->ptr, 
43226 +                       sqlite3_bind_text(stmt, 2,
43227 +                                         src->rel_path->ptr,
43228                                           src->rel_path->used - 1,
43229                                           SQLITE_TRANSIENT);
43230 -                                                                                                       
43231 +
43232                         if (SQLITE_DONE != sqlite3_step(stmt)) {
43233                                 /* */
43234 -                               WP();
43235                         }
43236                 }
43237         }
43238 @@ -655,21 +749,21 @@
43239                             (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
43240                                 continue;
43241                         }
43242 -                       
43243 +
43244                         buffer_copy_string_buffer(s.path, src->path);
43245 -                       BUFFER_APPEND_SLASH(s.path);
43246 +                       PATHNAME_APPEND_SLASH(s.path);
43247                         buffer_append_string(s.path, de->d_name);
43248  
43249                         buffer_copy_string_buffer(d.path, dst->path);
43250 -                       BUFFER_APPEND_SLASH(d.path);
43251 +                       PATHNAME_APPEND_SLASH(d.path);
43252                         buffer_append_string(d.path, de->d_name);
43253  
43254                         buffer_copy_string_buffer(s.rel_path, src->rel_path);
43255 -                       BUFFER_APPEND_SLASH(s.rel_path);
43256 +                       PATHNAME_APPEND_SLASH(s.rel_path);
43257                         buffer_append_string(s.rel_path, de->d_name);
43258  
43259                         buffer_copy_string_buffer(d.rel_path, dst->rel_path);
43260 -                       BUFFER_APPEND_SLASH(d.rel_path);
43261 +                       PATHNAME_APPEND_SLASH(d.rel_path);
43262                         buffer_append_string(d.rel_path, de->d_name);
43263  
43264                         if (-1 == stat(s.path->ptr, &st)) {
43265 @@ -692,19 +786,18 @@
43266                                                 sqlite3_reset(stmt);
43267  
43268                                                 /* bind the values to the insert */
43269 -                                               sqlite3_bind_text(stmt, 1, 
43270 -                                                         dst->rel_path->ptr, 
43271 +                                               sqlite3_bind_text(stmt, 1,
43272 +                                                         dst->rel_path->ptr,
43273                                                           dst->rel_path->used - 1,
43274                                                           SQLITE_TRANSIENT);
43275  
43276 -                                               sqlite3_bind_text(stmt, 2, 
43277 -                                                         src->rel_path->ptr, 
43278 +                                               sqlite3_bind_text(stmt, 2,
43279 +                                                         src->rel_path->ptr,
43280                                                           src->rel_path->used - 1,
43281                                                           SQLITE_TRANSIENT);
43282 -                                                                                                       
43283 +
43284                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {
43285                                                         /* */
43286 -                                                       WP();
43287                                                 }
43288                                         }
43289  #endif
43290 @@ -721,7 +814,7 @@
43291                 buffer_free(s.rel_path);
43292                 buffer_free(d.path);
43293                 buffer_free(d.rel_path);
43294 -               
43295 +
43296                 closedir(srcdir);
43297         }
43298  
43299 @@ -748,12 +841,12 @@
43300                         if (S_ISDIR(sce->st.st_mode)) {
43301                                 buffer_append_string(b, "<D:getcontenttype>httpd/unix-directory</D:getcontenttype>");
43302                                 found = 1;
43303 -                       } else if(S_ISREG(sce->st.st_mode)) { 
43304 +                       } else if(S_ISREG(sce->st.st_mode)) {
43305                                 for (k = 0; k < con->conf.mimetypes->used; k++) {
43306                                         data_string *ds = (data_string *)con->conf.mimetypes->data[k];
43307 -               
43308 +
43309                                         if (ds->key->used == 0) continue;
43310 -                               
43311 +
43312                                         if (buffer_is_equal_right_len(dst->path, ds->key, ds->key->used - 1)) {
43313                                                 buffer_append_string(b,"<D:getcontenttype>");
43314                                                 buffer_append_string_buffer(b, ds->value);
43315 @@ -807,23 +900,23 @@
43316  
43317                         /* bind the values to the insert */
43318  
43319 -                       sqlite3_bind_text(stmt, 1, 
43320 -                                         dst->rel_path->ptr, 
43321 +                       sqlite3_bind_text(stmt, 1,
43322 +                                         dst->rel_path->ptr,
43323                                           dst->rel_path->used - 1,
43324                                           SQLITE_TRANSIENT);
43325 -                       sqlite3_bind_text(stmt, 2, 
43326 +                       sqlite3_bind_text(stmt, 2,
43327                                           prop_name,
43328                                           strlen(prop_name),
43329                                           SQLITE_TRANSIENT);
43330 -                       sqlite3_bind_text(stmt, 3, 
43331 +                       sqlite3_bind_text(stmt, 3,
43332                                           prop_ns,
43333                                           strlen(prop_ns),
43334                                           SQLITE_TRANSIENT);
43335  
43336                         /* it is the PK */
43337 -                       while (SQLITE_ROW == sqlite3_step(p->conf.stmt_select_prop)) {
43338 +                       while (SQLITE_ROW == sqlite3_step(stmt)) {
43339                                 /* there is a row for us, we only expect a single col 'value' */
43340 -                               webdav_gen_prop_tag(srv, con, prop_name, prop_ns, (char *)sqlite3_column_text(p->conf.stmt_select_prop, 0), b);
43341 +                               webdav_gen_prop_tag(srv, con, prop_name, prop_ns, (char *)sqlite3_column_text(stmt, 0), b);
43342                                 found = 1;
43343                         }
43344                 }
43345 @@ -840,7 +933,7 @@
43346         char *prop;
43347  } webdav_property;
43348  
43349 -webdav_property live_properties[] = { 
43350 +webdav_property live_properties[] = {
43351         { "DAV:", "creationdate" },
43352         { "DAV:", "displayname" },
43353         { "DAV:", "getcontentlanguage" },
43354 @@ -871,8 +964,8 @@
43355                         webdav_property *prop;
43356  
43357                         prop = props->ptr[i];
43358 -                       
43359 -                       if (0 != webdav_get_property(srv, con, p, 
43360 +
43361 +                       if (0 != webdav_get_property(srv, con, p,
43362                                 dst, prop->prop, prop->ns, b_200)) {
43363                                 webdav_gen_prop_tag(srv, con, prop->prop, prop->ns, NULL, b_404);
43364                         }
43365 @@ -916,12 +1009,12 @@
43366                                 if (-1 == c->file.fd &&  /* open the file if not already open */
43367                                     -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
43368                                         log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
43369 -               
43370 +
43371                                         return -1;
43372                                 }
43373 -       
43374 +
43375                                 if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
43376 -                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ", 
43377 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
43378                                                         strerror(errno), c->file.name,  c->file.fd);
43379  
43380                                         return -1;
43381 @@ -938,7 +1031,7 @@
43382                         if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->file.mmap.start + c->offset, weHave, 0))) {
43383                                 log_error_write(srv, __FILE__, __LINE__, "sddd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
43384                         }
43385 -                       
43386 +
43387                         c->offset += weHave;
43388                         cq->bytes_out += weHave;
43389  
43390 @@ -956,7 +1049,7 @@
43391                         if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->mem->ptr + c->offset, weHave, 0))) {
43392                                 log_error_write(srv, __FILE__, __LINE__, "sddd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
43393                         }
43394 -                       
43395 +
43396                         c->offset += weHave;
43397                         cq->bytes_out += weHave;
43398  
43399 @@ -991,6 +1084,113 @@
43400  }
43401  #endif
43402  
43403 +int webdav_lockdiscovery(server *srv, connection *con,
43404 +               buffer *locktoken, const char *lockscope, const char *locktype, int depth) {
43405 +
43406 +       buffer *b;
43407 +
43408 +       response_header_overwrite(srv, con, CONST_STR_LEN("Lock-Token"), CONST_BUF_LEN(locktoken));
43409 +
43410 +       response_header_overwrite(srv, con,
43411 +               CONST_STR_LEN("Content-Type"),
43412 +               CONST_STR_LEN("text/xml; charset=\"utf-8\""));
43413 +
43414 +       b = chunkqueue_get_append_buffer(con->write_queue);
43415 +
43416 +       buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
43417 +
43418 +       buffer_append_string(b,"<D:prop xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n");
43419 +       buffer_append_string(b,"<D:lockdiscovery>\n");
43420 +       buffer_append_string(b,"<D:activelock>\n");
43421 +
43422 +       buffer_append_string(b,"<D:lockscope>");
43423 +       buffer_append_string(b,"<D:");
43424 +       buffer_append_string(b, lockscope);
43425 +       buffer_append_string(b, "/>");
43426 +       buffer_append_string(b,"</D:lockscope>\n");
43427 +
43428 +       buffer_append_string(b,"<D:locktype>");
43429 +       buffer_append_string(b,"<D:");
43430 +       buffer_append_string(b, locktype);
43431 +       buffer_append_string(b, "/>");
43432 +       buffer_append_string(b,"</D:locktype>\n");
43433 +
43434 +       buffer_append_string(b,"<D:depth>");
43435 +       buffer_append_string(b, depth == 0 ? "0" : "infinity");
43436 +       buffer_append_string(b,"</D:depth>\n");
43437 +
43438 +       buffer_append_string(b,"<D:timeout>");
43439 +       buffer_append_string(b, "Second-600");
43440 +       buffer_append_string(b,"</D:timeout>\n");
43441 +
43442 +       buffer_append_string(b,"<D:owner>");
43443 +       buffer_append_string(b,"</D:owner>\n");
43444 +
43445 +       buffer_append_string(b,"<D:locktoken>");
43446 +       buffer_append_string(b, "<D:href>");
43447 +       buffer_append_string_buffer(b, locktoken);
43448 +       buffer_append_string(b, "</D:href>");
43449 +       buffer_append_string(b,"</D:locktoken>\n");
43450 +
43451 +       buffer_append_string(b,"</D:activelock>\n");
43452 +       buffer_append_string(b,"</D:lockdiscovery>\n");
43453 +       buffer_append_string(b,"</D:prop>\n");
43454 +
43455 +       return 0;
43456 +}
43457 +/**
43458 + * check if resource is having the right locks to access to resource
43459 + *
43460 + *
43461 + *
43462 + */
43463 +int webdav_has_lock(server *srv, connection *con, plugin_data *p, buffer *uri) {
43464 +       int has_lock = 1;
43465 +
43466 +#ifdef USE_LOCKS
43467 +       data_string *ds;
43468 +
43469 +       /**
43470 +        * If can have
43471 +        * - <lock-token>
43472 +        * - [etag]
43473 +        *
43474 +        * there is NOT, AND and OR
43475 +        * and a list can be tagged
43476 +        *
43477 +        * (<lock-token>) is untagged
43478 +        * <tag> (<lock-token>) is tagged
43479 +        *
43480 +        * as long as we don't handle collections it is simple. :)
43481 +        *
43482 +        * X-Litmus: locks: 11 (owner_modify)
43483 +        * If: <http://127.0.0.1:1025/dav/litmus/lockme> (<opaquelocktoken:2165478d-0611-49c4-be92-e790d68a38f1>)
43484 +        *
43485 +        * X-Litmus: locks: 16 (fail_cond_put)
43486 +        * If: (<DAV:no-lock> ["-1622396671"])
43487 +        */
43488 +       if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
43489 +       } else {
43490 +               /* we didn't provided a lock-token -> */
43491 +               /* if the resource is locked -> 423 */
43492 +
43493 +               sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
43494 +
43495 +               sqlite3_reset(stmt);
43496 +
43497 +               sqlite3_bind_text(stmt, 1,
43498 +                         CONST_BUF_LEN(uri),
43499 +                         SQLITE_TRANSIENT);
43500 +
43501 +               while (SQLITE_ROW == sqlite3_step(stmt)) {
43502 +                       has_lock = 0;
43503 +               }
43504 +       }
43505 +#endif
43506 +
43507 +       return has_lock;
43508 +}
43509 +
43510  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
43511         plugin_data *p = p_d;
43512         buffer *b;
43513 @@ -1001,7 +1201,8 @@
43514         buffer *prop_200;
43515         buffer *prop_404;
43516         webdav_properties *req_props;
43517 -       
43518 +       stat_cache_entry *sce = NULL;
43519 +
43520         UNUSED(srv);
43521  
43522         if (!p->conf.enabled) return HANDLER_GO_ON;
43523 @@ -1019,7 +1220,19 @@
43524                 req_props = NULL;
43525  
43526                 /* is there a content-body ? */
43527 -       
43528 +
43529 +               switch (stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
43530 +               case HANDLER_ERROR:
43531 +                       if (errno == ENOENT) {
43532 +                               con->http_status = 404;
43533 +                               return HANDLER_FINISHED;
43534 +                       }
43535 +                       break;
43536 +               default:
43537 +                       break;
43538 +               }
43539 +
43540 +
43541  #ifdef USE_PROPPATCH
43542                 /* any special requests or just allprop ? */
43543                 if (con->request.content_length) {
43544 @@ -1087,14 +1300,13 @@
43545                                                                 /* get all property names (EMPTY) */
43546                                                                 sqlite3_reset(stmt);
43547                                                                 /* bind the values to the insert */
43548 -       
43549 -                                                               sqlite3_bind_text(stmt, 1, 
43550 -                                                                                 con->uri.path->ptr, 
43551 +
43552 +                                                               sqlite3_bind_text(stmt, 1,
43553 +                                                                                 con->uri.path->ptr,
43554                                                                                   con->uri.path->used - 1,
43555                                                                                   SQLITE_TRANSIENT);
43556 -                                               
43557 +
43558                                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {
43559 -                                                                       WP();
43560                                                                 }
43561                                                         }
43562                                                 } else if (0 == xmlStrcmp(cmd->name, BAD_CAST "allprop")) {
43563 @@ -1115,13 +1327,13 @@
43564                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
43565  
43566                 b = chunkqueue_get_append_buffer(con->write_queue);
43567 -                               
43568 +
43569                 buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
43570  
43571                 buffer_append_string(b,"<D:multistatus xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n");
43572  
43573                 /* allprop */
43574 -               
43575 +
43576                 prop_200 = buffer_init();
43577                 prop_404 = buffer_init();
43578  
43579 @@ -1129,7 +1341,7 @@
43580                 case 0:
43581                         /* Depth: 0 */
43582                         webdav_get_props(srv, con, p, &(con->physical), req_props, prop_200, prop_404);
43583 -       
43584 +
43585                         buffer_append_string(b,"<D:response>\n");
43586                         buffer_append_string(b,"<D:href>");
43587                         buffer_append_string_buffer(b, con->uri.scheme);
43588 @@ -1145,9 +1357,9 @@
43589                                 buffer_append_string_buffer(b, prop_200);
43590  
43591                                 buffer_append_string(b,"</D:prop>\n");
43592 -       
43593 +
43594                                 buffer_append_string(b,"<D:status>HTTP/1.1 200 OK</D:status>\n");
43595 -       
43596 +
43597                                 buffer_append_string(b,"</D:propstat>\n");
43598                         }
43599                         if (!buffer_is_empty(prop_404)) {
43600 @@ -1157,16 +1369,16 @@
43601                                 buffer_append_string_buffer(b, prop_404);
43602  
43603                                 buffer_append_string(b,"</D:prop>\n");
43604 -       
43605 +
43606                                 buffer_append_string(b,"<D:status>HTTP/1.1 404 Not Found</D:status>\n");
43607 -       
43608 +
43609                                 buffer_append_string(b,"</D:propstat>\n");
43610                         }
43611  
43612                         buffer_append_string(b,"</D:response>\n");
43613  
43614                         break;
43615 -               case 1: 
43616 +               case 1:
43617                         if (NULL != (dir = opendir(con->physical.path->ptr))) {
43618                                 struct dirent *de;
43619                                 physical d;
43620 @@ -1179,16 +1391,16 @@
43621                                         if (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0') {
43622                                                 continue;
43623                                                 /* ignore the parent dir */
43624 -                                       } 
43625 +                                       }
43626  
43627                                         buffer_copy_string_buffer(d.path, dst->path);
43628 -                                       BUFFER_APPEND_SLASH(d.path);
43629 +                                       PATHNAME_APPEND_SLASH(d.path);
43630  
43631                                         buffer_copy_string_buffer(d.rel_path, dst->rel_path);
43632 -                                       BUFFER_APPEND_SLASH(d.rel_path);
43633 +                                       PATHNAME_APPEND_SLASH(d.rel_path);
43634  
43635                                         if (de->d_name[0] == '.' && de->d_name[1] == '\0') {
43636 -                                               /* don't append the . */ 
43637 +                                               /* don't append the . */
43638                                         } else {
43639                                                 buffer_append_string(d.path, de->d_name);
43640                                                 buffer_append_string(d.rel_path, de->d_name);
43641 @@ -1198,7 +1410,7 @@
43642                                         buffer_reset(prop_404);
43643  
43644                                         webdav_get_props(srv, con, p, &d, req_props, prop_200, prop_404);
43645 -                                       
43646 +
43647                                         buffer_append_string(b,"<D:response>\n");
43648                                         buffer_append_string(b,"<D:href>");
43649                                         buffer_append_string_buffer(b, con->uri.scheme);
43650 @@ -1214,9 +1426,9 @@
43651                                                 buffer_append_string_buffer(b, prop_200);
43652  
43653                                                 buffer_append_string(b,"</D:prop>\n");
43654 -                       
43655 +
43656                                                 buffer_append_string(b,"<D:status>HTTP/1.1 200 OK</D:status>\n");
43657 -                       
43658 +
43659                                                 buffer_append_string(b,"</D:propstat>\n");
43660                                         }
43661                                         if (!buffer_is_empty(prop_404)) {
43662 @@ -1226,9 +1438,9 @@
43663                                                 buffer_append_string_buffer(b, prop_404);
43664  
43665                                                 buffer_append_string(b,"</D:prop>\n");
43666 -       
43667 +
43668                                                 buffer_append_string(b,"<D:status>HTTP/1.1 404 Not Found</D:status>\n");
43669 -       
43670 +
43671                                                 buffer_append_string(b,"</D:propstat>\n");
43672                                         }
43673  
43674 @@ -1275,7 +1487,7 @@
43675  
43676                         return HANDLER_FINISHED;
43677                 }
43678 -       
43679 +
43680                 /* let's create the directory */
43681  
43682                 if (-1 == mkdir(con->physical.path->ptr, 0700)) {
43683 @@ -1303,7 +1515,13 @@
43684                         con->http_status = 403;
43685                         return HANDLER_FINISHED;
43686                 }
43687 -               
43688 +
43689 +               /* does the client have a lock for this connection ? */
43690 +               if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43691 +                       con->http_status = 423;
43692 +                       return HANDLER_FINISHED;
43693 +               }
43694 +
43695                 /* stat and unlink afterwards */
43696                 if (-1 == stat(con->physical.path->ptr, &st)) {
43697                         /* don't about it yet, unlink will fail too */
43698 @@ -1323,7 +1541,7 @@
43699                                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
43700  
43701                                 b = chunkqueue_get_append_buffer(con->write_queue);
43702 -                       
43703 +
43704                                 buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
43705  
43706                                 buffer_append_string(b,"<D:multistatus xmlns:D=\"DAV:\">\n");
43707 @@ -1331,7 +1549,7 @@
43708                                 buffer_append_string_buffer(b, multi_status_resp);
43709  
43710                                 buffer_append_string(b,"</D:multistatus>\n");
43711 -                       
43712 +
43713                                 if (p->conf.log_xml) {
43714                                         log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b);
43715                                 }
43716 @@ -1340,7 +1558,7 @@
43717                                 con->file_finished = 1;
43718                         } else {
43719                                 /* everything went fine, remove the directory */
43720 -       
43721 +
43722                                 if (-1 == rmdir(con->physical.path->ptr)) {
43723                                         switch(errno) {
43724                                         case ENOENT:
43725 @@ -1375,97 +1593,174 @@
43726         case HTTP_METHOD_PUT: {
43727                 int fd;
43728                 chunkqueue *cq = con->request_content_queue;
43729 +               chunk *c;
43730 +               data_string *ds_range;
43731  
43732                 if (p->conf.is_readonly) {
43733                         con->http_status = 403;
43734                         return HANDLER_FINISHED;
43735                 }
43736  
43737 +               /* is a exclusive lock set on the source */
43738 +               if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43739 +                       con->http_status = 423;
43740 +                       return HANDLER_FINISHED;
43741 +               }
43742 +
43743 +
43744                 assert(chunkqueue_length(cq) == (off_t)con->request.content_length);
43745  
43746 -               /* taken what we have in the request-body and write it to a file */
43747 -               if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC, 0600))) {
43748 -                       /* we can't open the file */
43749 -                       con->http_status = 403;
43750 -               } else {
43751 -                       chunk *c;
43752 +               /* RFC2616 Section 9.6 PUT requires us to send 501 on all Content-* we don't support
43753 +                * - most important Content-Range
43754 +                *
43755 +                *
43756 +                * Example: Content-Range: bytes 100-1037/1038 */
43757  
43758 -                       con->http_status = 201; /* created */
43759 -                       con->file_finished = 1;
43760 +               if (NULL != (ds_range = (data_string *)array_get_element(con->request.headers, "Content-Range"))) {
43761 +                       const char *num = ds_range->value->ptr;
43762 +                       off_t offset;
43763 +                       char *err = NULL;
43764  
43765 -                       for (c = cq->first; c; c = cq->first) {
43766 -                               int r = 0; 
43767 +                       if (0 != strncmp(num, "bytes ", 6)) {
43768 +                               con->http_status = 501; /* not implemented */
43769  
43770 -                               /* copy all chunks */
43771 -                               switch(c->type) {
43772 -                               case FILE_CHUNK:
43773 -
43774 -                                       if (c->file.mmap.start == MAP_FAILED) {
43775 -                                               if (-1 == c->file.fd &&  /* open the file if not already open */
43776 -                                                   -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
43777 -                                                       log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
43778 -                                       
43779 -                                                       return -1;
43780 -                                               }
43781 -                               
43782 -                                               if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
43783 -                                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ", 
43784 -                                                                       strerror(errno), c->file.name,  c->file.fd);
43785 +                               return HANDLER_FINISHED;
43786 +                       }
43787  
43788 -                                                       return -1;
43789 -                                               }
43790 +                       /* we only support <num>- ... */
43791  
43792 -                                               c->file.mmap.length = c->file.length;
43793 +                       num += 6;
43794  
43795 -                                               close(c->file.fd);
43796 -                                               c->file.fd = -1;
43797 -       
43798 -                                               /* chunk_reset() or chunk_free() will cleanup for us */
43799 -                                       }
43800 -
43801 -                                       if ((r = write(fd, c->file.mmap.start + c->offset, c->file.length - c->offset)) < 0) {
43802 -                                               switch(errno) {
43803 -                                               case ENOSPC:
43804 -                                                       con->http_status = 507;
43805 -               
43806 -                                                       break;
43807 -                                               default:
43808 -                                                       con->http_status = 403;
43809 -                                                       break;
43810 -                                               }
43811 -                                       }
43812 -                                       break;
43813 -                               case MEM_CHUNK:
43814 -                                       if ((r = write(fd, c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) {
43815 -                                               switch(errno) {
43816 -                                               case ENOSPC:
43817 -                                                       con->http_status = 507;
43818 -               
43819 -                                                       break;
43820 -                                               default:
43821 -                                                       con->http_status = 403;
43822 -                                                       break;
43823 -                                               }
43824 -                                       }
43825 +                       /* skip WS */
43826 +                       while (*num == ' ' || *num == '\t') num++;
43827 +
43828 +                       if (*num == '\0') {
43829 +                               con->http_status = 501; /* not implemented */
43830 +
43831 +                               return HANDLER_FINISHED;
43832 +                       }
43833 +
43834 +                       offset = strtoll(num, &err, 10);
43835 +
43836 +                       if (*err != '-' || offset < 0) {
43837 +                               con->http_status = 501; /* not implemented */
43838 +
43839 +                               return HANDLER_FINISHED;
43840 +                       }
43841 +
43842 +                       if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY, 0600))) {
43843 +                               switch (errno) {
43844 +                               case ENOENT:
43845 +                                       con->http_status = 404; /* not found */
43846                                         break;
43847 -                               case UNUSED_CHUNK:
43848 +                               default:
43849 +                                       con->http_status = 403; /* not found */
43850                                         break;
43851                                 }
43852 +                               return HANDLER_FINISHED;
43853 +                       }
43854 +
43855 +                       if (-1 == lseek(fd, offset, SEEK_SET)) {
43856 +                               con->http_status = 501; /* not implemented */
43857 +
43858 +                               close(fd);
43859 +
43860 +                               return HANDLER_FINISHED;
43861 +                       }
43862 +                       con->http_status = 200; /* modified */
43863 +               } else {
43864 +                       /* take what we have in the request-body and write it to a file */
43865 +
43866 +                       /* if the file doesn't exist, create it */
43867 +                       if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_TRUNC, 0600))) {
43868 +                               if (errno == ENOENT &&
43869 +                                   -1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0600))) {
43870 +                                       /* we can't open the file */
43871 +                                       con->http_status = 403;
43872  
43873 -                               if (r > 0) {
43874 -                                       c->offset += r;
43875 -                                       cq->bytes_out += r;
43876 +                                       return HANDLER_FINISHED;
43877                                 } else {
43878 -                                       break;
43879 +                                       con->http_status = 201; /* created */
43880 +                               }
43881 +                       } else {
43882 +                               con->http_status = 200; /* modified */
43883 +                       }
43884 +               }
43885 +
43886 +               con->file_finished = 1;
43887 +
43888 +               for (c = cq->first; c; c = cq->first) {
43889 +                       int r = 0;
43890 +
43891 +                       /* copy all chunks */
43892 +                       switch(c->type) {
43893 +                       case FILE_CHUNK:
43894 +
43895 +                               if (c->file.mmap.start == MAP_FAILED) {
43896 +                                       if (-1 == c->file.fd &&  /* open the file if not already open */
43897 +                                           -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
43898 +                                               log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
43899 +
43900 +                                               return -1;
43901 +                                       }
43902 +
43903 +                                       if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
43904 +                                               log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
43905 +                                                               strerror(errno), c->file.name,  c->file.fd);
43906 +
43907 +                                               return -1;
43908 +                                       }
43909 +
43910 +                                       c->file.mmap.length = c->file.length;
43911 +
43912 +                                       close(c->file.fd);
43913 +                                       c->file.fd = -1;
43914 +
43915 +                                       /* chunk_reset() or chunk_free() will cleanup for us */
43916 +                               }
43917 +
43918 +                               if ((r = write(fd, c->file.mmap.start + c->offset, c->file.length - c->offset)) < 0) {
43919 +                                       switch(errno) {
43920 +                                       case ENOSPC:
43921 +                                               con->http_status = 507;
43922 +
43923 +                                               break;
43924 +                                       default:
43925 +                                               con->http_status = 403;
43926 +                                               break;
43927 +                                       }
43928                                 }
43929 -                               chunkqueue_remove_finished_chunks(cq);
43930 +                               break;
43931 +                       case MEM_CHUNK:
43932 +                               if ((r = write(fd, c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) {
43933 +                                       switch(errno) {
43934 +                                       case ENOSPC:
43935 +                                               con->http_status = 507;
43936 +
43937 +                                               break;
43938 +                                       default:
43939 +                                               con->http_status = 403;
43940 +                                               break;
43941 +                                       }
43942 +                               }
43943 +                               break;
43944 +                       case UNUSED_CHUNK:
43945 +                               break;
43946                         }
43947 -                       close(fd);
43948  
43949 +                       if (r > 0) {
43950 +                               c->offset += r;
43951 +                               cq->bytes_out += r;
43952 +                       } else {
43953 +                               break;
43954 +                       }
43955 +                       chunkqueue_remove_finished_chunks(cq);
43956                 }
43957 +               close(fd);
43958 +
43959                 return HANDLER_FINISHED;
43960         }
43961 -       case HTTP_METHOD_MOVE: 
43962 +       case HTTP_METHOD_MOVE:
43963         case HTTP_METHOD_COPY: {
43964                 buffer *destination = NULL;
43965                 char *sep, *start;
43966 @@ -1475,7 +1770,15 @@
43967                         con->http_status = 403;
43968                         return HANDLER_FINISHED;
43969                 }
43970 -               
43971 +
43972 +               /* is a exclusive lock set on the source */
43973 +               if (con->request.http_method == HTTP_METHOD_MOVE) {
43974 +                       if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43975 +                               con->http_status = 423;
43976 +                               return HANDLER_FINISHED;
43977 +                       }
43978 +               }
43979 +
43980                 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Destination"))) {
43981                         destination = ds->value;
43982                 } else {
43983 @@ -1549,10 +1852,10 @@
43984                 }
43985  
43986                 buffer_copy_string_buffer(p->physical.path, p->physical.doc_root);
43987 -               BUFFER_APPEND_SLASH(p->physical.path);
43988 +               PATHNAME_APPEND_SLASH(p->physical.path);
43989                 buffer_copy_string_buffer(p->physical.basedir, p->physical.path);
43990  
43991 -               /* don't add a second / */ 
43992 +               /* don't add a second / */
43993                 if (p->physical.rel_path->ptr[0] == '/') {
43994                         buffer_append_string_len(p->physical.path, p->physical.rel_path->ptr + 1, p->physical.rel_path->used - 2);
43995                 } else {
43996 @@ -1613,6 +1916,12 @@
43997                         /* it is just a file, good */
43998                         int r;
43999  
44000 +                       /* does the client have a lock for this connection ? */
44001 +                       if (!webdav_has_lock(srv, con, p, p->uri.path)) {
44002 +                               con->http_status = 423;
44003 +                               return HANDLER_FINISHED;
44004 +                       }
44005 +
44006                         /* destination exists */
44007                         if (0 == (r = stat(p->physical.path->ptr, &st))) {
44008                                 if (S_ISDIR(st.st_mode)) {
44009 @@ -1636,7 +1945,7 @@
44010                                         return HANDLER_FINISHED;
44011                                 }
44012                         } else if (overwrite == 0) {
44013 -                               /* destination exists, but overwrite is not set */ 
44014 +                               /* destination exists, but overwrite is not set */
44015                                 con->http_status = 412;
44016                                 return HANDLER_FINISHED;
44017                         } else {
44018 @@ -1655,16 +1964,16 @@
44019                                                 sqlite3_reset(stmt);
44020  
44021                                                 /* bind the values to the insert */
44022 -                                               sqlite3_bind_text(stmt, 1, 
44023 -                                                                 p->uri.path->ptr, 
44024 +                                               sqlite3_bind_text(stmt, 1,
44025 +                                                                 p->uri.path->ptr,
44026                                                                   p->uri.path->used - 1,
44027                                                                   SQLITE_TRANSIENT);
44028  
44029 -                                               sqlite3_bind_text(stmt, 2, 
44030 -                                                                 con->uri.path->ptr, 
44031 +                                               sqlite3_bind_text(stmt, 2,
44032 +                                                                 con->uri.path->ptr,
44033                                                                   con->uri.path->used - 1,
44034                                                                   SQLITE_TRANSIENT);
44035 -                                               
44036 +
44037                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {
44038                                                         log_error_write(srv, __FILE__, __LINE__, "ss", "sql-move failed:", sqlite3_errmsg(p->conf.sql));
44039                                                 }
44040 @@ -1691,12 +2000,17 @@
44041  
44042                 return HANDLER_FINISHED;
44043         }
44044 -       case HTTP_METHOD_PROPPATCH: {
44045 +       case HTTP_METHOD_PROPPATCH:
44046                 if (p->conf.is_readonly) {
44047                         con->http_status = 403;
44048                         return HANDLER_FINISHED;
44049                 }
44050  
44051 +               if (!webdav_has_lock(srv, con, p, con->uri.path)) {
44052 +                       con->http_status = 423;
44053 +                       return HANDLER_FINISHED;
44054 +               }
44055 +
44056                 /* check if destination exists */
44057                 if (-1 == stat(con->physical.path->ptr, &st)) {
44058                         switch(errno) {
44059 @@ -1737,7 +2051,7 @@
44060  
44061                                                         sqlite3_stmt *stmt;
44062  
44063 -                                                       stmt = (0 == xmlStrcmp(cmd->name, BAD_CAST "remove")) ? 
44064 +                                                       stmt = (0 == xmlStrcmp(cmd->name, BAD_CAST "remove")) ?
44065                                                                 p->conf.stmt_delete_prop : p->conf.stmt_update_prop;
44066  
44067                                                         for (props = cmd->children; props; props = props->next) {
44068 @@ -1762,34 +2076,35 @@
44069  
44070                                                                         /* bind the values to the insert */
44071  
44072 -                                                                       sqlite3_bind_text(stmt, 1, 
44073 -                                                                                         con->uri.path->ptr, 
44074 +                                                                       sqlite3_bind_text(stmt, 1,
44075 +                                                                                         con->uri.path->ptr,
44076                                                                                           con->uri.path->used - 1,
44077                                                                                           SQLITE_TRANSIENT);
44078 -                                                                       sqlite3_bind_text(stmt, 2, 
44079 +                                                                       sqlite3_bind_text(stmt, 2,
44080                                                                                           (char *)prop->name,
44081                                                                                           strlen((char *)prop->name),
44082                                                                                           SQLITE_TRANSIENT);
44083                                                                         if (prop->ns) {
44084 -                                                                               sqlite3_bind_text(stmt, 3, 
44085 +                                                                               sqlite3_bind_text(stmt, 3,
44086                                                                                                   (char *)prop->ns->href,
44087                                                                                                   strlen((char *)prop->ns->href),
44088                                                                                                   SQLITE_TRANSIENT);
44089                                                                         } else {
44090 -                                                                               sqlite3_bind_text(stmt, 3, 
44091 +                                                                               sqlite3_bind_text(stmt, 3,
44092                                                                                                   "",
44093                                                                                                   0,
44094                                                                                                   SQLITE_TRANSIENT);
44095                                                                         }
44096                                                                         if (stmt == p->conf.stmt_update_prop) {
44097 -                                                                               sqlite3_bind_text(stmt, 4, 
44098 +                                                                               sqlite3_bind_text(stmt, 4,
44099                                                                                           (char *)xmlNodeGetContent(prop),
44100                                                                                           strlen((char *)xmlNodeGetContent(prop)),
44101                                                                                           SQLITE_TRANSIENT);
44102                                                                         }
44103 -                                                               
44104 +
44105                                                                         if (SQLITE_DONE != (r = sqlite3_step(stmt))) {
44106 -                                                                               log_error_write(srv, __FILE__, __LINE__, "ss", "sql-set failed:", sqlite3_errmsg(p->conf.sql));
44107 +                                                                               log_error_write(srv, __FILE__, __LINE__, "ss",
44108 +                                                                                               "sql-set failed:", sqlite3_errmsg(p->conf.sql));
44109                                                                         }
44110                                                                 }
44111                                                         }
44112 @@ -1804,7 +2119,7 @@
44113  
44114                                                         goto propmatch_cleanup;
44115                                                 }
44116 -       
44117 +
44118                                                 con->http_status = 400;
44119                                         } else {
44120                                                 if (SQLITE_OK != sqlite3_exec(p->conf.sql, "COMMIT", NULL, NULL, &err)) {
44121 @@ -1821,6 +2136,7 @@
44122                                 }
44123  
44124  propmatch_cleanup:
44125 +
44126                                 xmlFreeDoc(xml);
44127                         } else {
44128                                 con->http_status = 400;
44129 @@ -1830,11 +2146,307 @@
44130  #endif
44131                 con->http_status = 501;
44132                 return HANDLER_FINISHED;
44133 -       }
44134 +       case HTTP_METHOD_LOCK:
44135 +               /**
44136 +                * a mac wants to write
44137 +                *
44138 +                * LOCK /dav/expire.txt HTTP/1.1\r\n
44139 +                * User-Agent: WebDAVFS/1.3 (01308000) Darwin/8.1.0 (Power Macintosh)\r\n
44140 +                * Accept: * / *\r\n
44141 +                * Depth: 0\r\n
44142 +                * Timeout: Second-600\r\n
44143 +                * Content-Type: text/xml; charset=\"utf-8\"\r\n
44144 +                * Content-Length: 229\r\n
44145 +                * Connection: keep-alive\r\n
44146 +                * Host: 192.168.178.23:1025\r\n
44147 +                * \r\n
44148 +                * <?xml version=\"1.0\" encoding=\"utf-8\"?>\n
44149 +                * <D:lockinfo xmlns:D=\"DAV:\">\n
44150 +                *  <D:lockscope><D:exclusive/></D:lockscope>\n
44151 +                *  <D:locktype><D:write/></D:locktype>\n
44152 +                *  <D:owner>\n
44153 +                *   <D:href>http://www.apple.com/webdav_fs/</D:href>\n
44154 +                *  </D:owner>\n
44155 +                * </D:lockinfo>\n
44156 +                */
44157 +
44158 +               if (depth != 0 && depth != -1) {
44159 +                       con->http_status = 400;
44160 +
44161 +                       return HANDLER_FINISHED;
44162 +               }
44163 +
44164 +#ifdef USE_LOCKS
44165 +               if (con->request.content_length) {
44166 +                       xmlDocPtr xml;
44167 +                       buffer *hdr_if = NULL;
44168 +
44169 +                       if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
44170 +                               hdr_if = ds->value;
44171 +                       }
44172 +
44173 +                       /* we don't support Depth: Infinity on locks */
44174 +                       if (hdr_if == NULL && depth == -1) {
44175 +                               con->http_status = 409; /* Conflict */
44176 +
44177 +                               return HANDLER_FINISHED;
44178 +                       }
44179 +
44180 +                       if (1 == webdav_parse_chunkqueue(srv, con, p, con->request_content_queue, &xml)) {
44181 +                               xmlNode *rootnode = xmlDocGetRootElement(xml);
44182 +
44183 +                               assert(rootnode);
44184 +
44185 +                               if (0 == xmlStrcmp(rootnode->name, BAD_CAST "lockinfo")) {
44186 +                                       xmlNode *lockinfo;
44187 +                                       const xmlChar *lockscope = NULL, *locktype = NULL, *owner = NULL;
44188 +
44189 +                                       for (lockinfo = rootnode->children; lockinfo; lockinfo = lockinfo->next) {
44190 +                                               if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "lockscope")) {
44191 +                                                       xmlNode *value;
44192 +                                                       for (value = lockinfo->children; value; value = value->next) {
44193 +                                                               if ((0 == xmlStrcmp(value->name, BAD_CAST "exclusive")) ||
44194 +                                                                   (0 == xmlStrcmp(value->name, BAD_CAST "shared"))) {
44195 +                                                                       lockscope = value->name;
44196 +                                                               } else {
44197 +                                                                       con->http_status = 400;
44198 +
44199 +                                                                       xmlFreeDoc(xml);
44200 +                                                                       return HANDLER_FINISHED;
44201 +                                                               }
44202 +                                                       }
44203 +                                               } else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "locktype")) {
44204 +                                                       xmlNode *value;
44205 +                                                       for (value = lockinfo->children; value; value = value->next) {
44206 +                                                               if ((0 == xmlStrcmp(value->name, BAD_CAST "write"))) {
44207 +                                                                       locktype = value->name;
44208 +                                                               } else {
44209 +                                                                       con->http_status = 400;
44210 +
44211 +                                                                       xmlFreeDoc(xml);
44212 +                                                                       return HANDLER_FINISHED;
44213 +                                                               }
44214 +                                                       }
44215 +
44216 +                                               } else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "owner")) {
44217 +                                               }
44218 +                                       }
44219 +
44220 +                                       if (lockscope && locktype) {
44221 +                                               sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
44222 +
44223 +                                               /* is this resourse already locked ? */
44224 +
44225 +                                               /* SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout
44226 +                                                *   FROM locks
44227 +                                                *  WHERE resource = ? */
44228 +
44229 +                                               if (stmt) {
44230 +
44231 +                                                       sqlite3_reset(stmt);
44232 +
44233 +                                                       sqlite3_bind_text(stmt, 1,
44234 +                                                                         p->uri.path->ptr,
44235 +                                                                         p->uri.path->used - 1,
44236 +                                                                         SQLITE_TRANSIENT);
44237 +
44238 +                                                       /* it is the PK */
44239 +                                                       while (SQLITE_ROW == sqlite3_step(stmt)) {
44240 +                                                               /* we found a lock
44241 +                                                                * 1. is it compatible ?
44242 +                                                                * 2. is it ours */
44243 +                                                               char *sql_lockscope = (char *)sqlite3_column_text(stmt, 2);
44244 +
44245 +                                                               if (strcmp(sql_lockscope, "exclusive")) {
44246 +                                                                       con->http_status = 423;
44247 +                                                               } else if (0 == xmlStrcmp(lockscope, BAD_CAST "exclusive")) {
44248 +                                                                       /* resourse is locked with a shared lock
44249 +                                                                        * client wants exclusive */
44250 +                                                                       con->http_status = 423;
44251 +                                                               }
44252 +                                                       }
44253 +                                                       if (con->http_status == 423) {
44254 +                                                               xmlFreeDoc(xml);
44255 +                                                               return HANDLER_FINISHED;
44256 +                                                       }
44257 +                                               }
44258 +
44259 +                                               stmt = p->conf.stmt_create_lock;
44260 +                                               if (stmt) {
44261 +                                                       /* create a lock-token */
44262 +                                                       uuid_t id;
44263 +                                                       char uuid[37] /* 36 + \0 */;
44264 +
44265 +                                                       uuid_generate(id);
44266 +                                                       uuid_unparse(id, uuid);
44267 +
44268 +                                                       buffer_copy_string(p->tmp_buf, "opaquelocktoken:");
44269 +                                                       buffer_append_string(p->tmp_buf, uuid);
44270 +
44271 +                                                       /* "CREATE TABLE locks ("
44272 +                                                        * "  locktoken TEXT NOT NULL,"
44273 +                                                        * "  resource TEXT NOT NULL,"
44274 +                                                        * "  lockscope TEXT NOT NULL,"
44275 +                                                        * "  locktype TEXT NOT NULL,"
44276 +                                                        * "  owner TEXT NOT NULL,"
44277 +                                                        * "  depth INT NOT NULL,"
44278 +                                                        */
44279 +
44280 +                                                       sqlite3_reset(stmt);
44281 +
44282 +                                                       sqlite3_bind_text(stmt, 1,
44283 +                                                                         CONST_BUF_LEN(p->tmp_buf),
44284 +                                                                         SQLITE_TRANSIENT);
44285 +
44286 +                                                       sqlite3_bind_text(stmt, 2,
44287 +                                                                         CONST_BUF_LEN(con->uri.path),
44288 +                                                                         SQLITE_TRANSIENT);
44289 +
44290 +                                                       sqlite3_bind_text(stmt, 3,
44291 +                                                                         lockscope,
44292 +                                                                         xmlStrlen(lockscope),
44293 +                                                                         SQLITE_TRANSIENT);
44294 +
44295 +                                                       sqlite3_bind_text(stmt, 4,
44296 +                                                                         locktype,
44297 +                                                                         xmlStrlen(locktype),
44298 +                                                                         SQLITE_TRANSIENT);
44299 +
44300 +                                                       /* owner */
44301 +                                                       sqlite3_bind_text(stmt, 5,
44302 +                                                                         "",
44303 +                                                                         0,
44304 +                                                                         SQLITE_TRANSIENT);
44305 +
44306 +                                                       /* depth */
44307 +                                                       sqlite3_bind_int(stmt, 6,
44308 +                                                                        depth);
44309 +
44310 +
44311 +                                                       if (SQLITE_DONE != sqlite3_step(stmt)) {
44312 +                                                               log_error_write(srv, __FILE__, __LINE__, "ss",
44313 +                                                                               "create lock:", sqlite3_errmsg(p->conf.sql));
44314 +                                                       }
44315 +
44316 +                                                       /* looks like we survived */
44317 +                                                       webdav_lockdiscovery(srv, con, p->tmp_buf, lockscope, locktype, depth);
44318 +
44319 +                                                       con->http_status = 201;
44320 +                                                       con->file_finished = 1;
44321 +                                               }
44322 +                                       }
44323 +                               }
44324 +
44325 +                               xmlFreeDoc(xml);
44326 +                               return HANDLER_FINISHED;
44327 +                       } else {
44328 +                               con->http_status = 400;
44329 +                               return HANDLER_FINISHED;
44330 +                       }
44331 +               } else {
44332 +
44333 +                       if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
44334 +                               buffer *locktoken = ds->value;
44335 +                               sqlite3_stmt *stmt = p->conf.stmt_refresh_lock;
44336 +
44337 +                               /* remove the < > around the token */
44338 +                               if (locktoken->used < 6) {
44339 +                                       con->http_status = 400;
44340 +
44341 +                                       return HANDLER_FINISHED;
44342 +                               }
44343 +
44344 +                               buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 2, locktoken->used - 5);
44345 +
44346 +                               sqlite3_reset(stmt);
44347 +
44348 +                               sqlite3_bind_text(stmt, 1,
44349 +                                         CONST_BUF_LEN(p->tmp_buf),
44350 +                                         SQLITE_TRANSIENT);
44351 +
44352 +                               if (SQLITE_DONE != sqlite3_step(stmt)) {
44353 +                                       log_error_write(srv, __FILE__, __LINE__, "ss",
44354 +                                               "refresh lock:", sqlite3_errmsg(p->conf.sql));
44355 +                               }
44356 +
44357 +                               webdav_lockdiscovery(srv, con, p->tmp_buf, "exclusive", "write", 0);
44358 +
44359 +                               con->http_status = 200;
44360 +                               con->file_finished = 1;
44361 +                               return HANDLER_FINISHED;
44362 +                       } else {
44363 +                               /* we need a lock-token to refresh */
44364 +                               con->http_status = 400;
44365 +
44366 +                               return HANDLER_FINISHED;
44367 +                       }
44368 +               }
44369 +               break;
44370 +#else
44371 +               con->http_status = 501;
44372 +               return HANDLER_FINISHED;
44373 +#endif
44374 +       case HTTP_METHOD_UNLOCK:
44375 +#ifdef USE_LOCKS
44376 +               if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Lock-Token"))) {
44377 +                       buffer *locktoken = ds->value;
44378 +                       sqlite3_stmt *stmt = p->conf.stmt_remove_lock;
44379 +
44380 +                       /* remove the < > around the token */
44381 +                       if (locktoken->used < 4) {
44382 +                               con->http_status = 400;
44383 +
44384 +                               return HANDLER_FINISHED;
44385 +                       }
44386 +
44387 +                       /**
44388 +                        * FIXME:
44389 +                        *
44390 +                        * if the resourse is locked:
44391 +                        * - by us: unlock
44392 +                        * - by someone else: 401
44393 +                        * if the resource is not locked:
44394 +                        * - 412
44395 +                        *  */
44396 +
44397 +                       buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 1, locktoken->used - 3);
44398 +
44399 +                       sqlite3_reset(stmt);
44400 +
44401 +                       sqlite3_bind_text(stmt, 1,
44402 +                                 CONST_BUF_LEN(p->tmp_buf),
44403 +                                 SQLITE_TRANSIENT);
44404 +
44405 +                       sqlite3_bind_text(stmt, 2,
44406 +                                 CONST_BUF_LEN(con->uri.path),
44407 +                                 SQLITE_TRANSIENT);
44408 +
44409 +                       if (SQLITE_DONE != sqlite3_step(stmt)) {
44410 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
44411 +                                       "remove lock:", sqlite3_errmsg(p->conf.sql));
44412 +                       }
44413 +
44414 +                       if (0 == sqlite3_changes(p->conf.sql)) {
44415 +                               con->http_status = 401;
44416 +                       } else {
44417 +                               con->http_status = 204;
44418 +                       }
44419 +                       return HANDLER_FINISHED;
44420 +               } else {
44421 +                       /* we need a lock-token to unlock */
44422 +                       con->http_status = 400;
44423 +
44424 +                       return HANDLER_FINISHED;
44425 +               }
44426 +               break;
44427 +#else
44428 +               con->http_status = 501;
44429 +               return HANDLER_FINISHED;
44430 +#endif
44431         default:
44432                 break;
44433         }
44434 -       
44435 +
44436         /* not found */
44437         return HANDLER_GO_ON;
44438  }
44439 @@ -1845,14 +2457,14 @@
44440  int mod_webdav_plugin_init(plugin *p) {
44441         p->version     = LIGHTTPD_VERSION_ID;
44442         p->name        = buffer_init_string("webdav");
44443 -       
44444 +
44445         p->init        = mod_webdav_init;
44446         p->handle_uri_clean  = mod_webdav_uri_handler;
44447         p->handle_physical   = mod_webdav_subrequest_handler;
44448         p->set_defaults  = mod_webdav_set_defaults;
44449         p->cleanup     = mod_webdav_free;
44450 -       
44451 +
44452         p->data        = NULL;
44453 -       
44454 +
44455         return 0;
44456  }
44457 --- ../lighttpd-1.4.11/src/network.c    2006-03-04 16:45:46.000000000 +0200
44458 +++ lighttpd-1.4.12/src/network.c       2006-07-18 13:03:40.000000000 +0300
44459 @@ -1,14 +1,14 @@
44460  #include <sys/types.h>
44461  #include <sys/stat.h>
44462 -#include <sys/time.h>
44463  
44464  #include <errno.h>
44465  #include <fcntl.h>
44466 -#include <unistd.h>
44467  #include <string.h>
44468  #include <stdlib.h>
44469  #include <assert.h>
44470  
44471 +#include <stdio.h>
44472 +
44473  #include "network.h"
44474  #include "fdevent.h"
44475  #include "log.h"
44476 @@ -19,11 +19,12 @@
44477  #include "network_backends.h"
44478  #include "sys-mmap.h"
44479  #include "sys-socket.h"
44480 +#include "sys-files.h"
44481  
44482  #ifdef USE_OPENSSL
44483 -# include <openssl/ssl.h> 
44484 -# include <openssl/err.h> 
44485 -# include <openssl/rand.h> 
44486 +# include <openssl/ssl.h>
44487 +# include <openssl/err.h>
44488 +# include <openssl/rand.h>
44489  #endif
44490  
44491  handler_t network_server_handle_fdevent(void *s, void *context, int revents) {
44492 @@ -31,25 +32,25 @@
44493         server_socket *srv_socket = (server_socket *)context;
44494         connection *con;
44495         int loops = 0;
44496 -       
44497 +
44498         UNUSED(context);
44499 -       
44500 +
44501         if (revents != FDEVENT_IN) {
44502 -               log_error_write(srv, __FILE__, __LINE__, "sdd", 
44503 +               log_error_write(srv, __FILE__, __LINE__, "sdd",
44504                                 "strange event for server socket",
44505 -                               srv_socket->fd,
44506 +                               srv_socket->sock->fd,
44507                                 revents);
44508                 return HANDLER_ERROR;
44509         }
44510  
44511         /* accept()s at most 100 connections directly
44512          *
44513 -        * we jump out after 100 to give the waiting connections a chance */    
44514 +        * we jump out after 100 to give the waiting connections a chance */
44515         for (loops = 0; loops < 100 && NULL != (con = connection_accept(srv, srv_socket)); loops++) {
44516                 handler_t r;
44517 -               
44518 +
44519                 connection_state_machine(srv, con);
44520 -               
44521 +
44522                 switch(r = plugins_call_handle_joblist(srv, con)) {
44523                 case HANDLER_FINISHED:
44524                 case HANDLER_GO_ON:
44525 @@ -72,18 +73,18 @@
44526         buffer *b;
44527         int is_unix_domain_socket = 0;
44528         int fd;
44529 -       
44530 +
44531  #ifdef SO_ACCEPTFILTER
44532         struct accept_filter_arg afa;
44533  #endif
44534  
44535 -#ifdef __WIN32
44536 +#ifdef _WIN32
44537         WORD wVersionRequested;
44538         WSADATA wsaData;
44539         int err;
44540 -        
44541 +
44542         wVersionRequested = MAKEWORD( 2, 2 );
44543 -        
44544 +
44545         err = WSAStartup( wVersionRequested, &wsaData );
44546         if ( err != 0 ) {
44547                     /* Tell the user that we could not find a usable */
44548 @@ -91,37 +92,37 @@
44549                     return -1;
44550         }
44551  #endif
44552 -       
44553 +
44554         srv_socket = calloc(1, sizeof(*srv_socket));
44555 -       srv_socket->fd = -1;
44556 -       
44557 +       srv_socket->sock = iosocket_init();
44558 +
44559         srv_socket->srv_token = buffer_init();
44560         buffer_copy_string_buffer(srv_socket->srv_token, host_token);
44561 -       
44562 +
44563         b = buffer_init();
44564         buffer_copy_string_buffer(b, host_token);
44565 -       
44566 -       /* ipv4:port 
44567 +
44568 +       /* ipv4:port
44569          * [ipv6]:port
44570          */
44571         if (NULL == (sp = strrchr(b->ptr, ':'))) {
44572                 log_error_write(srv, __FILE__, __LINE__, "sb", "value of $SERVER[\"socket\"] has to be \"ip:port\".", b);
44573 -               
44574 +
44575                 return -1;
44576         }
44577 -       
44578 +
44579         host = b->ptr;
44580 -       
44581 +
44582         /* check for [ and ] */
44583         if (b->ptr[0] == '[' && *(sp-1) == ']') {
44584                 *(sp-1) = '\0';
44585                 host++;
44586 -               
44587 +
44588                 s->use_ipv6 = 1;
44589         }
44590 -       
44591 +
44592         *(sp++) = '\0';
44593 -       
44594 +
44595         port = strtol(sp, NULL, 10);
44596  
44597         if (host[0] == '/') {
44598 @@ -129,18 +130,18 @@
44599                 is_unix_domain_socket = 1;
44600         } else if (port == 0 || port > 65535) {
44601                 log_error_write(srv, __FILE__, __LINE__, "sd", "port out of range:", port);
44602 -       
44603 +
44604                 return -1;
44605         }
44606 -       
44607 +
44608         if (*host == '\0') host = NULL;
44609  
44610         if (is_unix_domain_socket) {
44611  #ifdef HAVE_SYS_UN_H
44612  
44613                 srv_socket->addr.plain.sa_family = AF_UNIX;
44614 -               
44615 -               if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
44616 +
44617 +               if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
44618                         log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
44619                         return -1;
44620                 }
44621 @@ -154,32 +155,32 @@
44622  #ifdef HAVE_IPV6
44623         if (s->use_ipv6) {
44624                 srv_socket->addr.plain.sa_family = AF_INET6;
44625 -               
44626 -               if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44627 +
44628 +               if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44629                         log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
44630                         return -1;
44631                 }
44632                 srv_socket->use_ipv6 = 1;
44633         }
44634  #endif
44635 -                               
44636 -       if (srv_socket->fd == -1) {
44637 +
44638 +       if (srv_socket->sock->fd == -1) {
44639                 srv_socket->addr.plain.sa_family = AF_INET;
44640 -               if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44641 +               if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44642                         log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
44643                         return -1;
44644                 }
44645         }
44646 -       
44647 +
44648         /* */
44649 -       srv->cur_fds = srv_socket->fd;
44650 -       
44651 +       srv->cur_fds = srv_socket->sock->fd;
44652 +
44653         val = 1;
44654 -       if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
44655 +       if (setsockopt(srv_socket->sock->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
44656                 log_error_write(srv, __FILE__, __LINE__, "ss", "socketsockopt failed:", strerror(errno));
44657                 return -1;
44658         }
44659 -       
44660 +
44661         switch(srv_socket->addr.plain.sa_family) {
44662  #ifdef HAVE_IPV6
44663         case AF_INET6:
44664 @@ -190,23 +191,23 @@
44665                 } else {
44666                         struct addrinfo hints, *res;
44667                         int r;
44668 -                       
44669 +
44670                         memset(&hints, 0, sizeof(hints));
44671 -                       
44672 +
44673                         hints.ai_family   = AF_INET6;
44674                         hints.ai_socktype = SOCK_STREAM;
44675                         hints.ai_protocol = IPPROTO_TCP;
44676 -                       
44677 +
44678                         if (0 != (r = getaddrinfo(host, NULL, &hints, &res))) {
44679 -                               log_error_write(srv, __FILE__, __LINE__, 
44680 -                                               "sssss", "getaddrinfo failed: ", 
44681 +                               log_error_write(srv, __FILE__, __LINE__,
44682 +                                               "sssss", "getaddrinfo failed: ",
44683                                                 gai_strerror(r), "'", host, "'");
44684 -                               
44685 +
44686                                 return -1;
44687                         }
44688 -                       
44689 +
44690                         memcpy(&(srv_socket->addr), res->ai_addr, res->ai_addrlen);
44691 -                       
44692 +
44693                         freeaddrinfo(res);
44694                 }
44695                 srv_socket->addr.ipv6.sin6_port = htons(port);
44696 @@ -221,33 +222,34 @@
44697                 } else {
44698                         struct hostent *he;
44699                         if (NULL == (he = gethostbyname(host))) {
44700 -                               log_error_write(srv, __FILE__, __LINE__, 
44701 -                                               "sds", "gethostbyname failed: ", 
44702 +                               log_error_write(srv, __FILE__, __LINE__,
44703 +                                               "sds", "gethostbyname failed: ",
44704                                                 h_errno, host);
44705                                 return -1;
44706                         }
44707 -                       
44708 +
44709                         if (he->h_addrtype != AF_INET) {
44710                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
44711                                 return -1;
44712                         }
44713 -                       
44714 +
44715                         if (he->h_length != sizeof(struct in_addr)) {
44716                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
44717                                 return -1;
44718                         }
44719 -                       
44720 +
44721                         memcpy(&(srv_socket->addr.ipv4.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
44722                 }
44723                 srv_socket->addr.ipv4.sin_port = htons(port);
44724 -               
44725 +
44726                 addr_len = sizeof(struct sockaddr_in);
44727 -               
44728 +
44729                 break;
44730 +#ifndef _WIN32
44731         case AF_UNIX:
44732                 srv_socket->addr.un.sun_family = AF_UNIX;
44733                 strcpy(srv_socket->addr.un.sun_path, host);
44734 -               
44735 +
44736  #ifdef SUN_LEN
44737                 addr_len = SUN_LEN(&srv_socket->addr.un);
44738  #else
44739 @@ -256,11 +258,11 @@
44740  #endif
44741  
44742                 /* check if the socket exists and try to connect to it. */
44743 -               if (-1 != (fd = connect(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {
44744 +               if (-1 != (fd = connect(srv_socket->sock->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {
44745                         close(fd);
44746  
44747 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
44748 -                               "server socket is still in use:", 
44749 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
44750 +                               "server socket is still in use:",
44751                                 host);
44752  
44753  
44754 @@ -275,88 +277,89 @@
44755                 case ENOENT:
44756                         break;
44757                 default:
44758 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
44759 -                               "testing socket failed:", 
44760 +                       log_error_write(srv, __FILE__, __LINE__, "sds",
44761 +                               "testing socket failed:",
44762                                 host, strerror(errno));
44763  
44764                         return -1;
44765                 }
44766  
44767                 break;
44768 +#endif
44769         default:
44770                 addr_len = 0;
44771 -               
44772 +
44773                 return -1;
44774         }
44775 -       
44776 -       if (0 != bind(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
44777 +
44778 +       if (0 != bind(srv_socket->sock->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
44779                 switch(srv_socket->addr.plain.sa_family) {
44780                 case AF_UNIX:
44781 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
44782 -                                       "can't bind to socket:", 
44783 +                       log_error_write(srv, __FILE__, __LINE__, "sds",
44784 +                                       "can't bind to socket:",
44785                                         host, strerror(errno));
44786                         break;
44787                 default:
44788 -                       log_error_write(srv, __FILE__, __LINE__, "ssds", 
44789 -                                       "can't bind to port:", 
44790 +                       log_error_write(srv, __FILE__, __LINE__, "ssds",
44791 +                                       "can't bind to port:",
44792                                         host, port, strerror(errno));
44793                         break;
44794                 }
44795                 return -1;
44796         }
44797 -       
44798 -       if (-1 == listen(srv_socket->fd, 128 * 8)) {
44799 +
44800 +       if (-1 == listen(srv_socket->sock->fd, 128 * 8)) {
44801                 log_error_write(srv, __FILE__, __LINE__, "ss", "listen failed: ", strerror(errno));
44802                 return -1;
44803         }
44804 -       
44805 +
44806         if (s->is_ssl) {
44807  #ifdef USE_OPENSSL
44808                 if (srv->ssl_is_init == 0) {
44809                         SSL_load_error_strings();
44810                         SSL_library_init();
44811                         srv->ssl_is_init = 1;
44812 -                       
44813 +
44814                         if (0 == RAND_status()) {
44815 -                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
44816 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44817                                                 "not enough entropy in the pool");
44818                                 return -1;
44819                         }
44820                 }
44821 -               
44822 +
44823                 if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {
44824 -                       log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
44825 +                       log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44826                                         ERR_error_string(ERR_get_error(), NULL));
44827                         return -1;
44828                 }
44829 -               
44830 +
44831                 if (buffer_is_empty(s->ssl_pemfile)) {
44832                         log_error_write(srv, __FILE__, __LINE__, "s", "ssl.pemfile has to be set");
44833                         return -1;
44834                 }
44835 -               
44836 +
44837                 if (!buffer_is_empty(s->ssl_ca_file)) {
44838                         if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s->ssl_ca_file->ptr, NULL)) {
44839 -                               log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", 
44840 +                               log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44841                                                 ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);
44842                                 return -1;
44843                         }
44844                 }
44845 -               
44846 +
44847                 if (SSL_CTX_use_certificate_file(s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
44848 -                       log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", 
44849 +                       log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44850                                         ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
44851                         return -1;
44852                 }
44853 -               
44854 +
44855                 if (SSL_CTX_use_PrivateKey_file (s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
44856 -                       log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", 
44857 +                       log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44858                                         ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
44859                         return -1;
44860                 }
44861 -               
44862 +
44863                 if (SSL_CTX_check_private_key(s->ssl_ctx) != 1) {
44864 -                       log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:", 
44865 +                       log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:",
44866                                         "Private key does not match the certificate public key, reason:",
44867                                         ERR_error_string(ERR_get_error(), NULL),
44868                                         s->ssl_pemfile);
44869 @@ -364,15 +367,15 @@
44870                 }
44871                 srv_socket->ssl_ctx = s->ssl_ctx;
44872  #else
44873 -               
44874 +
44875                 buffer_free(srv_socket->srv_token);
44876                 free(srv_socket);
44877 -               
44878 +
44879                 buffer_free(b);
44880 -               
44881 -               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
44882 +
44883 +               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44884                                 "ssl requested but openssl support is not compiled in");
44885 -               
44886 +
44887                 return -1;
44888  #endif
44889         } else {
44890 @@ -383,17 +386,16 @@
44891                  */
44892                 memset(&afa, 0, sizeof(afa));
44893                 strcpy(afa.af_name, "httpready");
44894 -               if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
44895 +               if (setsockopt(srv_socket->sock->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
44896                         if (errno != ENOENT) {
44897                                 log_error_write(srv, __FILE__, __LINE__, "ss", "can't set accept-filter 'httpready': ", strerror(errno));
44898                         }
44899                 }
44900  #endif
44901         }
44902 -       
44903 +
44904         srv_socket->is_ssl = s->is_ssl;
44905 -       srv_socket->fde_ndx = -1;
44906 -       
44907 +
44908         if (srv->srv_sockets.size == 0) {
44909                 srv->srv_sockets.size = 4;
44910                 srv->srv_sockets.used = 0;
44911 @@ -402,11 +404,10 @@
44912                 srv->srv_sockets.size += 4;
44913                 srv->srv_sockets.ptr = realloc(srv->srv_sockets.ptr, srv->srv_sockets.size * sizeof(server_socket));
44914         }
44915 -       
44916 +
44917         srv->srv_sockets.ptr[srv->srv_sockets.used++] = srv_socket;
44918 -       
44919         buffer_free(b);
44920 -       
44921 +
44922         return 0;
44923  }
44924  
44925 @@ -414,45 +415,60 @@
44926         size_t i;
44927         for (i = 0; i < srv->srv_sockets.used; i++) {
44928                 server_socket *srv_socket = srv->srv_sockets.ptr[i];
44929 -               
44930 -               if (srv_socket->fd != -1) {
44931 +
44932 +               if (srv_socket->sock->fd != -1) {
44933                         /* check if server fd are already registered */
44934 -                       if (srv_socket->fde_ndx != -1) {
44935 -                               fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
44936 -                               fdevent_unregister(srv->ev, srv_socket->fd);
44937 +                       if (srv_socket->sock->fde_ndx != -1) {
44938 +                               fdevent_event_del(srv->ev, srv_socket->sock);
44939 +                               fdevent_unregister(srv->ev, srv_socket->sock);
44940                         }
44941 -               
44942 -                       close(srv_socket->fd);
44943 +
44944 +                       closesocket(srv_socket->sock->fd);
44945 +               }
44946 +
44947 +               if (srv_socket->is_ssl) {
44948 +#ifdef USE_OPENSSL
44949 +                       SSL_CTX_free(srv_socket->ssl_ctx);
44950 +#endif
44951                 }
44952 -               
44953 +
44954 +               iosocket_free(srv_socket->sock);
44955 +
44956                 buffer_free(srv_socket->srv_token);
44957 -               
44958 +
44959                 free(srv_socket);
44960         }
44961 -       
44962 +
44963 +#ifdef USE_OPENSSL
44964 +       ERR_free_strings();
44965 +#endif
44966         free(srv->srv_sockets.ptr);
44967 -       
44968 +
44969         return 0;
44970  }
44971  
44972  typedef enum {
44973         NETWORK_BACKEND_UNSET,
44974 +
44975         NETWORK_BACKEND_WRITE,
44976         NETWORK_BACKEND_WRITEV,
44977         NETWORK_BACKEND_LINUX_SENDFILE,
44978         NETWORK_BACKEND_FREEBSD_SENDFILE,
44979 -       NETWORK_BACKEND_SOLARIS_SENDFILEV
44980 +       NETWORK_BACKEND_SOLARIS_SENDFILEV,
44981 +
44982 +    NETWORK_BACKEND_WIN32_SEND,
44983 +    NETWORK_BACKEND_WIN32_TRANSMITFILE,
44984  } network_backend_t;
44985  
44986  int network_init(server *srv) {
44987         buffer *b;
44988         size_t i;
44989         network_backend_t backend;
44990 -       
44991 -       struct nb_map { 
44992 -               network_backend_t nb; 
44993 -               const char *name; 
44994 -       } network_backends[] = { 
44995 +
44996 +       struct nb_map {
44997 +               network_backend_t nb;
44998 +               const char *name;
44999 +       } network_backends[] = {
45000                 /* lowest id wins */
45001  #if defined USE_LINUX_SENDFILE
45002                 { NETWORK_BACKEND_LINUX_SENDFILE,       "linux-sendfile" },
45003 @@ -466,21 +482,30 @@
45004  #if defined USE_WRITEV
45005                 { NETWORK_BACKEND_WRITEV,               "writev" },
45006  #endif
45007 +#if defined USE_WRITE
45008                 { NETWORK_BACKEND_WRITE,                "write" },
45009 +#endif
45010 +#if defined USE_WIN32_TRANSMITFILE
45011 +               { NETWORK_BACKEND_WIN32_TRANSMITFILE,   "win32-transmitfile" },
45012 +#endif
45013 +#if defined USE_WIN32_SEND
45014 +               { NETWORK_BACKEND_WIN32_SEND,           "win32-send" },
45015 +#endif
45016 +
45017                 { NETWORK_BACKEND_UNSET,                NULL }
45018         };
45019 -       
45020 +
45021         b = buffer_init();
45022 -               
45023 +
45024         buffer_copy_string_buffer(b, srv->srvconf.bindhost);
45025         buffer_append_string(b, ":");
45026         buffer_append_long(b, srv->srvconf.port);
45027 -       
45028 +
45029         if (0 != network_server_init(srv, b, srv->config_storage[0])) {
45030                 return -1;
45031         }
45032         buffer_free(b);
45033 -               
45034 +
45035  #ifdef USE_OPENSSL
45036         srv->network_ssl_backend_write = network_write_chunkqueue_openssl;
45037  #endif
45038 @@ -500,54 +525,80 @@
45039                 if (NULL == network_backends[i].name) {
45040                         /* we don't know it */
45041  
45042 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
45043 -                                       "server.network-backend has a unknown value:", 
45044 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
45045 +                                       "server.network-backend has a unknown value:",
45046                                         srv->srvconf.network_backend);
45047  
45048                         return -1;
45049                 }
45050         }
45051  
45052 +#define SET_NETWORK_BACKEND(read, write) \
45053 +    srv->network_backend_write = network_write_chunkqueue_##write;\
45054 +    srv->network_backend_read = network_read_chunkqueue_##read
45055 +
45056 +#define SET_NETWORK_BACKEND_SSL(read, write) \
45057 +    srv->network_ssl_backend_write = network_write_chunkqueue_##write;\
45058 +    srv->network_ssl_backend_read = network_read_chunkqueue_##read
45059 +
45060         switch(backend) {
45061 +
45062 +#ifdef USE_WIN32_SEND
45063 +       case NETWORK_BACKEND_WIN32_SEND:
45064 +        SET_NETWORK_BACKEND(win32recv, win32send);
45065 +               break;
45066 +#ifdef USE_WIN32_TRANSMITFILE
45067 +       case NETWORK_BACKEND_WIN32_TRANSMITFILE:
45068 +        SET_NETWORK_BACKEND(win32recv, win32transmitfile);
45069 +               break;
45070 +#endif
45071 +#endif
45072 +
45073 +#ifdef USE_WRITE
45074         case NETWORK_BACKEND_WRITE:
45075 -               srv->network_backend_write = network_write_chunkqueue_write;
45076 +        SET_NETWORK_BACKEND(read, write);
45077                 break;
45078 +
45079  #ifdef USE_WRITEV
45080         case NETWORK_BACKEND_WRITEV:
45081 -               srv->network_backend_write = network_write_chunkqueue_writev;
45082 +        SET_NETWORK_BACKEND(read, writev);
45083                 break;
45084  #endif
45085  #ifdef USE_LINUX_SENDFILE
45086         case NETWORK_BACKEND_LINUX_SENDFILE:
45087 -               srv->network_backend_write = network_write_chunkqueue_linuxsendfile; 
45088 +        SET_NETWORK_BACKEND(read, linuxsendfile);
45089                 break;
45090  #endif
45091  #ifdef USE_FREEBSD_SENDFILE
45092         case NETWORK_BACKEND_FREEBSD_SENDFILE:
45093 -               srv->network_backend_write = network_write_chunkqueue_freebsdsendfile; 
45094 +        SET_NETWORK_BACKEND(read, freebsdsendfile);
45095                 break;
45096  #endif
45097  #ifdef USE_SOLARIS_SENDFILEV
45098         case NETWORK_BACKEND_SOLARIS_SENDFILEV:
45099 -               srv->network_backend_write = network_write_chunkqueue_solarissendfilev; 
45100 +        SET_NETWORK_BACKEND(read, solarissendfilev);
45101                 break;
45102  #endif
45103 +#endif
45104         default:
45105                 return -1;
45106         }
45107 +#ifdef USE_OPENSSL
45108 +        SET_NETWORK_BACKEND_SSL(openssl, openssl);
45109 +#endif
45110  
45111         /* check for $SERVER["socket"] */
45112         for (i = 1; i < srv->config_context->used; i++) {
45113                 data_config *dc = (data_config *)srv->config_context->data[i];
45114                 specific_config *s = srv->config_storage[i];
45115                 size_t j;
45116 -               
45117 +
45118                 /* not our stage */
45119                 if (COMP_SERVER_SOCKET != dc->comp) continue;
45120 -               
45121 +
45122                 if (dc->cond != CONFIG_COND_EQ) {
45123                         log_error_write(srv, __FILE__, __LINE__, "s", "only == is allowed for $SERVER[\"socket\"].");
45124 -                       
45125 +
45126                         return -1;
45127                 }
45128  
45129 @@ -558,36 +609,47 @@
45130                                 break;
45131                         }
45132                 }
45133 -               
45134 +
45135                 if (j == srv->srv_sockets.used) {
45136                         if (0 != network_server_init(srv, dc->string, s)) return -1;
45137                 }
45138         }
45139 -       
45140 +
45141         return 0;
45142  }
45143  
45144  int network_register_fdevents(server *srv) {
45145         size_t i;
45146 -       
45147         if (-1 == fdevent_reset(srv->ev)) {
45148                 return -1;
45149         }
45150 -       
45151         /* register fdevents after reset */
45152         for (i = 0; i < srv->srv_sockets.used; i++) {
45153                 server_socket *srv_socket = srv->srv_sockets.ptr[i];
45154 -               
45155 -               fdevent_register(srv->ev, srv_socket->fd, network_server_handle_fdevent, srv_socket);
45156 -               fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
45157 +               fdevent_register(srv->ev, srv_socket->sock, network_server_handle_fdevent, srv_socket);
45158 +               fdevent_event_add(srv->ev, srv_socket->sock, FDEVENT_IN);
45159         }
45160         return 0;
45161  }
45162  
45163 -int network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
45164 -       int ret = -1;
45165 +network_status_t network_read_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
45166 +       server_socket *srv_socket = con->srv_socket;
45167 +
45168 +       if (srv_socket->is_ssl) {
45169 +#ifdef USE_OPENSSL
45170 +               return srv->network_ssl_backend_read(srv, con, con->sock, cq);
45171 +#else
45172 +               return NETWORK_STATUS_FATAL_ERROR;
45173 +#endif
45174 +       } else {
45175 +               return srv->network_backend_read(srv, con, con->sock, cq);
45176 +       }
45177 +}
45178 +
45179 +network_status_t network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
45180 +       network_status_t ret = NETWORK_STATUS_UNSET;
45181         off_t written = 0;
45182 -#ifdef TCP_CORK        
45183 +#ifdef TCP_CORK
45184         int corked = 0;
45185  #endif
45186         server_socket *srv_socket = con->srv_socket;
45187 @@ -600,37 +662,42 @@
45188                 joblist_append(srv, con);
45189  
45190                 return 1;
45191 -       }  
45192 +       }
45193  
45194         written = cq->bytes_out;
45195  
45196 -#ifdef TCP_CORK        
45197 +#ifdef TCP_CORK
45198         /* Linux: put a cork into the socket as we want to combine the write() calls
45199          * but only if we really have multiple chunks
45200          */
45201         if (cq->first && cq->first->next) {
45202                 corked = 1;
45203 -               setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
45204 +               setsockopt(con->sock->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
45205         }
45206  #endif
45207 -       
45208 +
45209         if (srv_socket->is_ssl) {
45210  #ifdef USE_OPENSSL
45211 -               ret = srv->network_ssl_backend_write(srv, con, con->ssl, cq);
45212 +               ret = srv->network_ssl_backend_write(srv, con, con->sock, cq);
45213  #endif
45214         } else {
45215 -               ret = srv->network_backend_write(srv, con, con->fd, cq);
45216 +               ret = srv->network_backend_write(srv, con, con->sock, cq);
45217         }
45218 -       
45219 -       if (ret >= 0) {
45220 +
45221 +    switch (ret) {
45222 +    case NETWORK_STATUS_WAIT_FOR_EVENT:
45223 +    case NETWORK_STATUS_SUCCESS:
45224                 chunkqueue_remove_finished_chunks(cq);
45225 -               ret = chunkqueue_is_empty(cq) ? 0 : 1;
45226 +
45227 +        break;
45228 +    default:
45229 +        break;
45230         }
45231 -       
45232 +
45233  #ifdef TCP_CORK
45234         if (corked) {
45235                 corked = 0;
45236 -               setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
45237 +               setsockopt(con->sock->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
45238         }
45239  #endif
45240  
45241 @@ -639,13 +706,13 @@
45242         con->bytes_written_cur_second += written;
45243  
45244         *(con->conf.global_bytes_per_second_cnt_ptr) += written;
45245 -       
45246 +
45247         if (con->conf.kbytes_per_second &&
45248             (con->bytes_written_cur_second > con->conf.kbytes_per_second * 1024)) {
45249                 /* we reached the traffic limit */
45250  
45251                 con->traffic_limit_reached = 1;
45252                 joblist_append(srv, con);
45253 -       }  
45254 +       }
45255         return ret;
45256  }
45257 --- ../lighttpd-1.4.11/src/network.h    2005-08-11 01:26:42.000000000 +0300
45258 +++ lighttpd-1.4.12/src/network.h       2006-07-18 13:03:40.000000000 +0300
45259 @@ -3,11 +3,13 @@
45260  
45261  #include "server.h"
45262  
45263 -int network_write_chunkqueue(server *srv, connection *con, chunkqueue *c);
45264 +network_status_t network_write_chunkqueue(server *srv, connection *con, chunkqueue *c);
45265 +network_status_t network_read_chunkqueue(server *srv, connection *con, chunkqueue *c);
45266  
45267  int network_init(server *srv);
45268  int network_close(server *srv);
45269  
45270  int network_register_fdevents(server *srv);
45271 +handler_t network_server_handle_fdevent(void *s, void *context, int revents);
45272  
45273  #endif
45274 --- ../lighttpd-1.4.11/src/network_backends.h   2005-10-24 15:13:51.000000000 +0300
45275 +++ lighttpd-1.4.12/src/network_backends.h      2006-07-18 13:03:40.000000000 +0300
45276 @@ -43,16 +43,47 @@
45277  # define USE_AIX_SENDFILE
45278  #endif
45279  
45280 +/**
45281 +* unix can use read/write or recv/send on sockets
45282 +* win32 only recv/send
45283 +*/
45284 +#ifdef _WIN32
45285 +# define USE_WIN32_SEND
45286 +/* wait for async-io support
45287 +# define USE_WIN32_TRANSMITFILE
45288 +*/
45289 +#else
45290 +# define USE_WRITE
45291 +#endif
45292 +
45293  #include "base.h"
45294 +#include "network.h"
45295 +
45296 +#define NETWORK_BACKEND_WRITE_CHUNK(x) \
45297 +    network_status_t network_write_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq, chunk *c)
45298 +
45299 +#define NETWORK_BACKEND_WRITE(x) \
45300 +    network_status_t network_write_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq)
45301 +#define NETWORK_BACKEND_READ(x) \
45302 +    network_status_t network_read_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq)
45303 +
45304 +NETWORK_BACKEND_WRITE_CHUNK(writev_mem);
45305 +
45306 +NETWORK_BACKEND_WRITE(write);
45307 +NETWORK_BACKEND_WRITE(writev);
45308 +NETWORK_BACKEND_WRITE(linuxsendfile);
45309 +NETWORK_BACKEND_WRITE(freebsdsendfile);
45310 +NETWORK_BACKEND_WRITE(solarissendfilev);
45311 +
45312 +NETWORK_BACKEND_WRITE(win32transmitfile);
45313 +NETWORK_BACKEND_WRITE(win32send);
45314  
45315 +NETWORK_BACKEND_READ(read);
45316 +NETWORK_BACKEND_READ(win32recv);
45317  
45318 -int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq);
45319 -int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq);
45320 -int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq);
45321 -int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq);
45322 -int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq);
45323  #ifdef USE_OPENSSL
45324 -int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq);
45325 +NETWORK_BACKEND_WRITE(openssl);
45326 +NETWORK_BACKEND_READ(openssl);
45327  #endif
45328  
45329  #endif
45330 --- ../lighttpd-1.4.11/src/network_freebsd_sendfile.c   2005-10-22 12:28:18.000000000 +0300
45331 +++ lighttpd-1.4.12/src/network_freebsd_sendfile.c      2006-07-16 00:26:04.000000000 +0300
45332 @@ -26,142 +26,61 @@
45333  
45334  #ifndef UIO_MAXIOV
45335  # ifdef __FreeBSD__
45336 -/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */ 
45337 +/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */
45338  #  define UIO_MAXIOV 1024
45339  # endif
45340  #endif
45341  
45342 -int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq) {
45343 +NETWORK_BACKEND_WRITE(freebsdsendfile) {
45344         chunk *c;
45345         size_t chunks_written = 0;
45346 -       
45347 +
45348         for(c = cq->first; c; c = c->next, chunks_written++) {
45349                 int chunk_finished = 0;
45350 -               
45351 +               network_status_t ret;
45352 +
45353                 switch(c->type) {
45354 -               case MEM_CHUNK: {
45355 -                       char * offset;
45356 -                       size_t toSend;
45357 -                       ssize_t r;
45358 -                       
45359 -                       size_t num_chunks, i;
45360 -                       struct iovec chunks[UIO_MAXIOV];
45361 -                       chunk *tc;
45362 -                       size_t num_bytes = 0;
45363 -                       
45364 -                       /* we can't send more then SSIZE_MAX bytes in one chunk */
45365 -                       
45366 -                       /* build writev list 
45367 -                        * 
45368 -                        * 1. limit: num_chunks < UIO_MAXIOV
45369 -                        * 2. limit: num_bytes < SSIZE_MAX
45370 -                        */
45371 -                       for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
45372 -                       
45373 -                       for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
45374 -                               if (tc->mem->used == 0) {
45375 -                                       chunks[i].iov_base = tc->mem->ptr;
45376 -                                       chunks[i].iov_len  = 0;
45377 -                               } else {
45378 -                                       offset = tc->mem->ptr + tc->offset;
45379 -                                       toSend = tc->mem->used - 1 - tc->offset;
45380 -                                       
45381 -                                       chunks[i].iov_base = offset;
45382 -                                       
45383 -                                       /* protect the return value of writev() */
45384 -                                       if (toSend > SSIZE_MAX ||
45385 -                                           num_bytes + toSend > SSIZE_MAX) {
45386 -                                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
45387 -                                               
45388 -                                               num_chunks = i + 1;
45389 -                                               break;
45390 -                                       } else {
45391 -                                               chunks[i].iov_len = toSend;
45392 -                                       }
45393 -                                
45394 -                                       num_bytes += toSend;
45395 -                               }
45396 -                       }
45397 -                       
45398 -                       if ((r = writev(fd, chunks, num_chunks)) < 0) {
45399 -                               switch (errno) {
45400 -                               case EAGAIN:
45401 -                               case EINTR:
45402 -                                       r = 0;
45403 -                                       break;
45404 -                               case EPIPE:
45405 -                               case ECONNRESET:
45406 -                                       return -2;
45407 -                               default:
45408 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
45409 -                                                       "writev failed:", strerror(errno), fd);
45410 -                                       
45411 -                                       return -1;
45412 -                               }
45413 +               case MEM_CHUNK:
45414 +                       ret = network_write_chunkqueue_writev_mem(srv, con, fd, cq, &c);
45415  
45416 -                               r = 0;
45417 -                       }
45418 -                       
45419 -                       /* check which chunks have been written */
45420 -                       cq->bytes_out += r;
45421 -                       
45422 -                       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
45423 -                               if (r >= (ssize_t)chunks[i].iov_len) {
45424 -                                       /* written */
45425 -                                       r -= chunks[i].iov_len;
45426 -                                       tc->offset += chunks[i].iov_len;
45427 -                                       
45428 -                                       if (chunk_finished) {
45429 -                                               /* skip the chunks from further touches */
45430 -                                               chunks_written++;
45431 -                                               c = c->next;
45432 -                                       } else {
45433 -                                               /* chunks_written + c = c->next is done in the for()*/
45434 -                                               chunk_finished++;
45435 -                                       }
45436 -                               } else {
45437 -                                       /* partially written */
45438 -                                       
45439 -                                       tc->offset += r;
45440 -                                       chunk_finished = 0;
45441 -                                       
45442 -                                       break;
45443 -                               }
45444 +                       if (ret != NETWORK_STATUS_SUCCESS) {
45445 +                               return ret;
45446                         }
45447 -                       
45448 +
45449 +                       chunk_finished = 1;
45450 +
45451                         break;
45452 -               }
45453                 case FILE_CHUNK: {
45454                         off_t offset, r;
45455                         size_t toSend;
45456                         stat_cache_entry *sce = NULL;
45457                         int ifd;
45458 -                       
45459 +
45460                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
45461                                 log_error_write(srv, __FILE__, __LINE__, "sb",
45462                                                 strerror(errno), c->file.name);
45463 -                               return -1;
45464 +                               return NETWORK_STATUS_FATAL_ERROR;
45465                         }
45466 -                       
45467 +
45468                         offset = c->file.start + c->offset;
45469                         /* limit the toSend to 2^31-1 bytes in a chunk */
45470 -                       toSend = c->file.length - c->offset > ((1 << 30) - 1) ? 
45471 +                       toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
45472                                 ((1 << 30) - 1) : c->file.length - c->offset;
45473 -                               
45474 +
45475                         if (offset > sce->st.st_size) {
45476                                 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
45477 -                               
45478 -                               return -1;
45479 +
45480 +                               return NETWORK_STATUS_FATAL_ERROR;
45481                         }
45482 -                       
45483 +
45484                         if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
45485                                 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
45486 -                               
45487 -                               return -1;
45488 +
45489 +                               return NETWORK_STATUS_FATAL_ERROR;
45490                         }
45491 -                       
45492 +
45493                         r = 0;
45494 -                       
45495 +
45496                         /* FreeBSD sendfile() */
45497                         if (-1 == sendfile(ifd, fd, offset, toSend, NULL, &r, 0)) {
45498                                 switch(errno) {
45499 @@ -169,39 +88,39 @@
45500                                         break;
45501                                 case ENOTCONN:
45502                                         close(ifd);
45503 -                                       return -2;
45504 +                                       return NETWORK_STATUS_CONNECTION_CLOSE;
45505                                 default:
45506                                         log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
45507                                         close(ifd);
45508 -                                       return -1;
45509 +                                       return NETWORK_STATUS_FATAL_ERROR;
45510                                 }
45511                         }
45512                         close(ifd);
45513 -                       
45514 +
45515                         c->offset += r;
45516                         cq->bytes_out += r;
45517 -                       
45518 +
45519                         if (c->offset == c->file.length) {
45520                                 chunk_finished = 1;
45521                         }
45522 -                       
45523 +
45524                         break;
45525                 }
45526                 default:
45527 -                       
45528 +
45529                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
45530 -                       
45531 +
45532                         return -1;
45533                 }
45534 -               
45535 +
45536                 if (!chunk_finished) {
45537                         /* not finished yet */
45538 -                       
45539 +
45540                         break;
45541                 }
45542         }
45543  
45544 -       return chunks_written;
45545 +       return NETWORK_STATUS_SUCCESS;
45546  }
45547  
45548  #endif
45549 --- ../lighttpd-1.4.11/src/network_linux_sendfile.c     2006-02-15 20:02:36.000000000 +0200
45550 +++ lighttpd-1.4.12/src/network_linux_sendfile.c        2006-07-18 13:03:40.000000000 +0300
45551 @@ -26,122 +26,54 @@
45552  /* on linux 2.4.29 + debian/ubuntu we have crashes if this is enabled */
45553  #undef HAVE_POSIX_FADVISE
45554  
45555 -int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq) {
45556 -       chunk *c;
45557 +NETWORK_BACKEND_WRITE(linuxsendfile) {
45558 +       chunk *c, *tc;
45559         size_t chunks_written = 0;
45560 -       
45561 +
45562         for(c = cq->first; c; c = c->next, chunks_written++) {
45563                 int chunk_finished = 0;
45564 -               
45565 +               network_status_t ret;
45566 +
45567                 switch(c->type) {
45568 -               case MEM_CHUNK: {
45569 -                       char * offset;
45570 -                       size_t toSend;
45571 -                       ssize_t r;
45572 -                       
45573 -                       size_t num_chunks, i;
45574 -                       struct iovec chunks[UIO_MAXIOV];
45575 -                       chunk *tc;
45576 -                       size_t num_bytes = 0;
45577 -                       
45578 -                       /* we can't send more then SSIZE_MAX bytes in one chunk */
45579 -                       
45580 -                       /* build writev list 
45581 -                        * 
45582 -                        * 1. limit: num_chunks < UIO_MAXIOV
45583 -                        * 2. limit: num_bytes < SSIZE_MAX
45584 -                        */
45585 -                       for (num_chunks = 0, tc = c; 
45586 -                            tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; 
45587 -                            tc = tc->next, num_chunks++);
45588 -                       
45589 -                       for (tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
45590 -                               if (tc->mem->used == 0) {
45591 -                                       chunks[i].iov_base = tc->mem->ptr;
45592 -                                       chunks[i].iov_len  = 0;
45593 -                               } else {
45594 -                                       offset = tc->mem->ptr + tc->offset;
45595 -                                       toSend = tc->mem->used - 1 - tc->offset;
45596 -                               
45597 -                                       chunks[i].iov_base = offset;
45598 -                                       
45599 -                                       /* protect the return value of writev() */
45600 -                                       if (toSend > SSIZE_MAX ||
45601 -                                           num_bytes + toSend > SSIZE_MAX) {
45602 -                                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
45603 -                                               
45604 -                                               num_chunks = i + 1;
45605 -                                               break;
45606 -                                       } else {
45607 -                                               chunks[i].iov_len = toSend;
45608 -                                       }
45609 -                                
45610 -                                       num_bytes += toSend;
45611 -                               }
45612 -                       }
45613 -                       
45614 -                       if ((r = writev(fd, chunks, num_chunks)) < 0) {
45615 -                               switch (errno) {
45616 -                               case EAGAIN:
45617 -                               case EINTR:
45618 -                                       r = 0;
45619 -                                       break;
45620 -                               case EPIPE:
45621 -                               case ECONNRESET:
45622 -                                       return -2;
45623 -                               default:
45624 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
45625 -                                                       "writev failed:", strerror(errno), fd);
45626 -                               
45627 -                                       return -1;
45628 -                               }
45629 -                       }
45630 -                       
45631 -                       /* check which chunks have been written */
45632 -                       cq->bytes_out += r;
45633 +               case MEM_CHUNK:
45634 +                       ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
45635  
45636 -                       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
45637 -                               if (r >= (ssize_t)chunks[i].iov_len) {
45638 -                                       /* written */
45639 -                                       r -= chunks[i].iov_len;
45640 -                                       tc->offset += chunks[i].iov_len;
45641 -                                       
45642 +                       /* check which chunks are finished now */
45643 +                       for (tc = c; tc; tc = tc->next) {
45644 +                               /* finished the chunk */
45645 +                               if (tc->offset == tc->mem->used - 1) {
45646 +                                       /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
45647                                         if (chunk_finished) {
45648 -                                               /* skip the chunks from further touches */
45649 -                                               chunks_written++;
45650                                                 c = c->next;
45651                                         } else {
45652 -                                               /* chunks_written + c = c->next is done in the for()*/
45653 -                                               chunk_finished++;
45654 +                                               chunk_finished = 1;
45655                                         }
45656                                 } else {
45657 -                                       /* partially written */
45658 -                                       
45659 -                                       tc->offset += r;
45660 -                                       chunk_finished = 0;
45661 -                                       
45662                                         break;
45663                                 }
45664                         }
45665 -                       
45666 +
45667 +                       if (ret != NETWORK_STATUS_SUCCESS) {
45668 +                               return ret;
45669 +                       }
45670 +
45671                         break;
45672 -               }
45673                 case FILE_CHUNK: {
45674                         ssize_t r;
45675                         off_t offset;
45676                         size_t toSend;
45677                         stat_cache_entry *sce = NULL;
45678 -                       
45679 +
45680                         offset = c->file.start + c->offset;
45681                         /* limit the toSend to 2^31-1 bytes in a chunk */
45682 -                       toSend = c->file.length - c->offset > ((1 << 30) - 1) ? 
45683 +                       toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
45684                                 ((1 << 30) - 1) : c->file.length - c->offset;
45685 -                               
45686 -                       /* open file if not already opened */   
45687 +
45688 +                       /* open file if not already opened */
45689                         if (-1 == c->file.fd) {
45690                                 if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
45691                                         log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
45692 -                               
45693 +
45694                                         return -1;
45695                                 }
45696  #ifdef FD_CLOEXEC
45697 @@ -151,14 +83,14 @@
45698                                 /* tell the kernel that we want to stream the file */
45699                                 if (-1 == posix_fadvise(c->file.fd, 0, 0, POSIX_FADV_SEQUENTIAL)) {
45700                                         if (ENOSYS != errno) {
45701 -                                               log_error_write(srv, __FILE__, __LINE__, "ssd", 
45702 +                                               log_error_write(srv, __FILE__, __LINE__, "ssd",
45703                                                         "posix_fadvise failed:", strerror(errno), c->file.fd);
45704                                         }
45705                                 }
45706  #endif
45707                         }
45708  
45709 -                       if (-1 == (r = sendfile(fd, c->file.fd, &offset, toSend))) {
45710 +                       if (-1 == (r = sendfile(sock->fd, c->file.fd, &offset, toSend))) {
45711                                 switch (errno) {
45712                                 case EAGAIN:
45713                                 case EINTR:
45714 @@ -166,11 +98,11 @@
45715                                         break;
45716                                 case EPIPE:
45717                                 case ECONNRESET:
45718 -                                       return -2;
45719 +                                       return NETWORK_STATUS_CONNECTION_CLOSE;
45720                                 default:
45721 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
45722 -                                                       "sendfile failed:", strerror(errno), fd);
45723 -                                       return -1;
45724 +                                       log_error_write(srv, __FILE__, __LINE__, "ssd",
45725 +                                                       "sendfile failed:", strerror(errno), sock->fd);
45726 +                                       return NETWORK_STATUS_FATAL_ERROR;
45727                                 }
45728                         }
45729  
45730 @@ -179,39 +111,39 @@
45731                                  *
45732                                  * - the file shrinked -> error
45733                                  * - the remote side closed inbetween -> remote-close */
45734 -       
45735 +
45736                                 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
45737                                         /* file is gone ? */
45738 -                                       return -1;
45739 +                                       return NETWORK_STATUS_FATAL_ERROR;
45740                                 }
45741  
45742                                 if (offset > sce->st.st_size) {
45743                                         /* file shrinked, close the connection */
45744 -                                       return -1;
45745 +                                       return NETWORK_STATUS_FATAL_ERROR;
45746                                 }
45747  
45748 -                               return -2;
45749 +                               return NETWORK_STATUS_CONNECTION_CLOSE;
45750                         }
45751  
45752  #ifdef HAVE_POSIX_FADVISE
45753  #if 0
45754  #define K * 1024
45755 -#define M * 1024 K     
45756 +#define M * 1024 K
45757  #define READ_AHEAD 4 M
45758                         /* check if we need a new chunk */
45759                         if ((c->offset & ~(READ_AHEAD - 1)) != ((c->offset + r) & ~(READ_AHEAD - 1))) {
45760                                 /* tell the kernel that we want to stream the file */
45761                                 if (-1 == posix_fadvise(c->file.fd, (c->offset + r) & ~(READ_AHEAD - 1), READ_AHEAD, POSIX_FADV_NOREUSE)) {
45762 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
45763 +                                       log_error_write(srv, __FILE__, __LINE__, "ssd",
45764                                                 "posix_fadvise failed:", strerror(errno), c->file.fd);
45765                                 }
45766                         }
45767  #endif
45768  #endif
45769 -                       
45770 +
45771                         c->offset += r;
45772                         cq->bytes_out += r;
45773 -                       
45774 +
45775                         if (c->offset == c->file.length) {
45776                                 chunk_finished = 1;
45777  
45778 @@ -222,24 +154,24 @@
45779                                         c->file.fd = -1;
45780                                 }
45781                         }
45782 -                       
45783 +
45784                         break;
45785                 }
45786                 default:
45787 -                       
45788 +
45789                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
45790 -                       
45791 -                       return -1;
45792 +
45793 +                       return NETWORK_STATUS_FATAL_ERROR;
45794                 }
45795 -               
45796 +
45797                 if (!chunk_finished) {
45798                         /* not finished yet */
45799 -                       
45800 -                       break;
45801 +
45802 +                       return NETWORK_STATUS_WAIT_FOR_EVENT;
45803                 }
45804         }
45805  
45806 -       return chunks_written;
45807 +       return NETWORK_STATUS_SUCCESS;
45808  }
45809  
45810  #endif
45811 --- ../lighttpd-1.4.11/src/network_openssl.c    2005-11-17 14:53:29.000000000 +0200
45812 +++ lighttpd-1.4.12/src/network_openssl.c       2006-07-18 13:03:40.000000000 +0300
45813 @@ -23,17 +23,87 @@
45814  #include "log.h"
45815  #include "stat_cache.h"
45816  
45817 -# include <openssl/ssl.h> 
45818 -# include <openssl/err.h> 
45819 +# include <openssl/ssl.h>
45820 +# include <openssl/err.h>
45821  
45822 -int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq) {
45823 +NETWORK_BACKEND_READ(openssl) {
45824 +       buffer *b;
45825 +       off_t len;
45826 +
45827 +       b = chunkqueue_get_append_buffer(cq);
45828 +       buffer_prepare_copy(b, 8192);
45829 +       len = SSL_read(sock->ssl, b->ptr, b->size - 1);
45830 +
45831 +       log_error_write(srv, __FILE__, __LINE__, "so", "SSL:", len);
45832 +
45833 +       if (len < 0) {
45834 +               int r, ssl_err;
45835 +
45836 +               switch ((r = SSL_get_error(sock->ssl, len))) {
45837 +               case SSL_ERROR_WANT_READ:
45838 +                       return NETWORK_STATUS_WAIT_FOR_EVENT;
45839 +               case SSL_ERROR_SYSCALL:
45840 +                       /**
45841 +                        * man SSL_get_error()
45842 +                        *
45843 +                        * SSL_ERROR_SYSCALL
45844 +                        *   Some I/O error occurred.  The OpenSSL error queue may contain more
45845 +                        *   information on the error.  If the error queue is empty (i.e.
45846 +                        *   ERR_get_error() returns 0), ret can be used to find out more about
45847 +                        *   the error: If ret == 0, an EOF was observed that violates the
45848 +                        *   protocol.  If ret == -1, the underlying BIO reported an I/O error
45849 +                        *   (for socket I/O on Unix systems, consult errno for details).
45850 +                        *
45851 +                        */
45852 +                       while((ssl_err = ERR_get_error())) {
45853 +                               /* get all errors from the error-queue */
45854 +                               log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
45855 +                                               r, ERR_error_string(ssl_err, NULL));
45856 +                       }
45857 +
45858 +                       switch(errno) {
45859 +                       default:
45860 +                               log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
45861 +                                               len, r, errno,
45862 +                                               strerror(errno));
45863 +                               break;
45864 +                       }
45865 +
45866 +                       break;
45867 +               case SSL_ERROR_ZERO_RETURN:
45868 +                       /* clean shutdown on the remote side */
45869 +
45870 +                       if (r == 0) {
45871 +                               /* FIXME: later */
45872 +                       }
45873 +
45874 +                       /* fall thourgh */
45875 +               default:
45876 +                       while((ssl_err = ERR_get_error())) {
45877 +                               /* get all errors from the error-queue */
45878 +                               log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
45879 +                                               r, ERR_error_string(ssl_err, NULL));
45880 +                       }
45881 +                       break;
45882 +               }
45883 +       }
45884 +
45885 +       assert(len > 0);
45886 +       b->used += len;
45887 +       b->ptr[b->used - 1] = '\0';
45888 +
45889 +       return NETWORK_STATUS_SUCCESS;
45890 +}
45891 +
45892 +
45893 +NETWORK_BACKEND_WRITE(openssl) {
45894         int ssl_r;
45895         chunk *c;
45896         size_t chunks_written = 0;
45897  
45898         /* this is a 64k sendbuffer
45899          *
45900 -        * it has to stay at the same location all the time to satisfy the needs 
45901 +        * it has to stay at the same location all the time to satisfy the needs
45902          * of SSL_write to pass the SAME parameter in case of a _WANT_WRITE
45903          *
45904          * the buffer is allocated once, is NOT realloced and is NOT freed at shutdown
45905 @@ -43,59 +113,61 @@
45906          * In reality we would like to use mmap() but we don't have a guarantee that
45907          * we get the same mmap() address for each call. On openbsd the mmap() address
45908          * even randomized.
45909 -        *   That means either we keep the mmap() open or we do a read() into a 
45910 -        * constant buffer 
45911 +        *   That means either we keep the mmap() open or we do a read() into a
45912 +        * constant buffer
45913          * */
45914  #define LOCAL_SEND_BUFSIZE (64 * 1024)
45915         static char *local_send_buffer = NULL;
45916  
45917         /* the remote side closed the connection before without shutdown request
45918 -        * - IE 
45919 +        * - IE
45920          * - wget
45921          * if keep-alive is disabled */
45922  
45923         if (con->keep_alive == 0) {
45924 -               SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
45925 +               SSL_set_shutdown(sock->ssl, SSL_RECEIVED_SHUTDOWN);
45926         }
45927  
45928         for(c = cq->first; c; c = c->next) {
45929                 int chunk_finished = 0;
45930 -               
45931 +
45932                 switch(c->type) {
45933                 case MEM_CHUNK: {
45934                         char * offset;
45935                         size_t toSend;
45936 -                       ssize_t r;
45937 -                       
45938 +                       ssize_t r = 0;
45939 +
45940                         if (c->mem->used == 0) {
45941                                 chunk_finished = 1;
45942                                 break;
45943                         }
45944 -                       
45945 +
45946                         offset = c->mem->ptr + c->offset;
45947                         toSend = c->mem->used - 1 - c->offset;
45948 -                       
45949 +
45950                         /**
45951                          * SSL_write man-page
45952 -                        * 
45953 +                        *
45954                          * WARNING
45955                          *        When an SSL_write() operation has to be repeated because of
45956                          *        SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be
45957                          *        repeated with the same arguments.
45958 -                        * 
45959 +                        *
45960 +                        * SSL_write(..., 0) return 0 which is handle as an error (Success)
45961 +                        * checking toSend and not calling SSL_write() is simpler
45962                          */
45963 -                       
45964 -                       if ((r = SSL_write(ssl, offset, toSend)) <= 0) {
45965 +
45966 +                       if (toSend != 0 && (r = SSL_write(sock->ssl, offset, toSend)) <= 0) {
45967                                 unsigned long err;
45968  
45969 -                               switch ((ssl_r = SSL_get_error(ssl, r))) {
45970 +                               switch ((ssl_r = SSL_get_error(sock->ssl, r))) {
45971                                 case SSL_ERROR_WANT_WRITE:
45972                                         break;
45973                                 case SSL_ERROR_SYSCALL:
45974                                         /* perhaps we have error waiting in our error-queue */
45975                                         if (0 != (err = ERR_get_error())) {
45976                                                 do {
45977 -                                                       log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", 
45978 +                                                       log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45979                                                                         ssl_r, r,
45980                                                                         ERR_error_string(err, NULL));
45981                                                 } while((err = ERR_get_error()));
45982 @@ -105,43 +177,43 @@
45983                                                 case EPIPE:
45984                                                         return -2;
45985                                                 default:
45986 -                                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", 
45987 +                                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
45988                                                                         ssl_r, r, errno,
45989                                                                         strerror(errno));
45990                                                         break;
45991                                                 }
45992                                         } else {
45993                                                 /* neither error-queue nor errno ? */
45994 -                                               log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):", 
45995 +                                               log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
45996                                                                 ssl_r, r, errno,
45997                                                                 strerror(errno));
45998                                         }
45999 -                                       
46000 +
46001                                         return  -1;
46002                                 case SSL_ERROR_ZERO_RETURN:
46003                                         /* clean shutdown on the remote side */
46004 -                                       
46005 +
46006                                         if (r == 0) return -2;
46007 -                                       
46008 +
46009                                         /* fall through */
46010                                 default:
46011                                         while((err = ERR_get_error())) {
46012 -                                               log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", 
46013 +                                               log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
46014                                                                 ssl_r, r,
46015                                                                 ERR_error_string(err, NULL));
46016                                         }
46017 -                                       
46018 +
46019                                         return  -1;
46020                                 }
46021                         } else {
46022                                 c->offset += r;
46023                                 cq->bytes_out += r;
46024                         }
46025 -                       
46026 +
46027                         if (c->offset == (off_t)c->mem->used - 1) {
46028                                 chunk_finished = 1;
46029                         }
46030 -                       
46031 +
46032                         break;
46033                 }
46034                 case FILE_CHUNK: {
46035 @@ -150,7 +222,7 @@
46036                         stat_cache_entry *sce = NULL;
46037                         int ifd;
46038                         int write_wait = 0;
46039 -                       
46040 +
46041                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
46042                                 log_error_write(srv, __FILE__, __LINE__, "sb",
46043                                                 strerror(errno), c->file.name);
46044 @@ -164,13 +236,13 @@
46045  
46046                         do {
46047                                 off_t offset = c->file.start + c->offset;
46048 -                               off_t toSend = c->file.length - c->offset; 
46049 +                               off_t toSend = c->file.length - c->offset;
46050  
46051                                 if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE;
46052 -                       
46053 +
46054                                 if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
46055                                         log_error_write(srv, __FILE__, __LINE__, "ss", "open failed:", strerror(errno));
46056 -                               
46057 +
46058                                         return -1;
46059                                 }
46060  
46061 @@ -183,13 +255,13 @@
46062                                 }
46063  
46064                                 s = local_send_buffer;
46065 -                       
46066 +
46067                                 close(ifd);
46068 -                       
46069 -                               if ((r = SSL_write(ssl, s, toSend)) <= 0) {
46070 +
46071 +                               if ((r = SSL_write(sock->ssl, s, toSend)) <= 0) {
46072                                         unsigned long err;
46073  
46074 -                                       switch ((ssl_r = SSL_get_error(ssl, r))) {
46075 +                                       switch ((ssl_r = SSL_get_error(sock->ssl, r))) {
46076                                         case SSL_ERROR_WANT_WRITE:
46077                                                 write_wait = 1;
46078                                                 break;
46079 @@ -197,7 +269,7 @@
46080                                                 /* perhaps we have error waiting in our error-queue */
46081                                                 if (0 != (err = ERR_get_error())) {
46082                                                         do {
46083 -                                                               log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", 
46084 +                                                               log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
46085                                                                                 ssl_r, r,
46086                                                                                 ERR_error_string(err, NULL));
46087                                                         } while((err = ERR_get_error()));
46088 @@ -207,62 +279,62 @@
46089                                                         case EPIPE:
46090                                                                 return -2;
46091                                                         default:
46092 -                                                               log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", 
46093 +                                                               log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
46094                                                                                 ssl_r, r, errno,
46095                                                                                 strerror(errno));
46096                                                                 break;
46097                                                         }
46098                                                 } else {
46099                                                         /* neither error-queue nor errno ? */
46100 -                                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):", 
46101 +                                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
46102                                                                         ssl_r, r, errno,
46103                                                                         strerror(errno));
46104                                                 }
46105 -                                       
46106 +
46107                                                 return  -1;
46108                                         case SSL_ERROR_ZERO_RETURN:
46109                                                 /* clean shutdown on the remote side */
46110 -                                       
46111 +
46112                                                 if (r == 0)  return -2;
46113 -                                       
46114 +
46115                                                 /* fall thourgh */
46116                                         default:
46117                                                 while((err = ERR_get_error())) {
46118 -                                                       log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", 
46119 +                                                       log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
46120                                                                         ssl_r, r,
46121                                                                         ERR_error_string(err, NULL));
46122                                                 }
46123 -                                       
46124 +
46125                                                 return -1;
46126                                         }
46127                                 } else {
46128                                         c->offset += r;
46129                                         cq->bytes_out += r;
46130                                 }
46131 -                       
46132 +
46133                                 if (c->offset == c->file.length) {
46134                                         chunk_finished = 1;
46135                                 }
46136                         } while(!chunk_finished && !write_wait);
46137 -                       
46138 +
46139                         break;
46140                 }
46141                 default:
46142                         log_error_write(srv, __FILE__, __LINE__, "s", "type not known");
46143 -                       
46144 +
46145                         return -1;
46146                 }
46147 -                       
46148 +
46149                 if (!chunk_finished) {
46150                         /* not finished yet */
46151 -                       
46152 +
46153                         break;
46154                 }
46155 -                       
46156 +
46157                 chunks_written++;
46158         }
46159  
46160 -       return chunks_written;
46161 +       return NETWORK_STATUS_SUCCESS;
46162  }
46163  #endif
46164  
46165 --- ../lighttpd-1.4.11/src/network_solaris_sendfilev.c  2005-10-22 12:28:27.000000000 +0300
46166 +++ lighttpd-1.4.12/src/network_solaris_sendfilev.c     2006-07-16 00:26:04.000000000 +0300
46167 @@ -29,114 +29,34 @@
46168  #endif
46169  
46170  /**
46171 - * a very simple sendfilev() interface for solaris which can be optimised a lot more 
46172 + * a very simple sendfilev() interface for solaris which can be optimised a lot more
46173   * as solaris sendfilev() supports 'sending everythin in one syscall()'
46174 - * 
46175 - * If you want such an interface and need the performance, just give me an account on 
46176 - * a solaris box. 
46177 + *
46178 + * If you want such an interface and need the performance, just give me an account on
46179 + * a solaris box.
46180   *   - jan@kneschke.de
46181   */
46182  
46183  
46184 -int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq) {
46185 +NETWORK_BACKEND_WRITE(solarissendfilev) {
46186         chunk *c;
46187         size_t chunks_written = 0;
46188 -       
46189 +
46190         for(c = cq->first; c; c = c->next, chunks_written++) {
46191                 int chunk_finished = 0;
46192 -               
46193 +               network_status_t ret;
46194 +
46195                 switch(c->type) {
46196 -               case MEM_CHUNK: {
46197 -                       char * offset;
46198 -                       size_t toSend;
46199 -                       ssize_t r;
46200 -                       
46201 -                       size_t num_chunks, i;
46202 -                       struct iovec chunks[UIO_MAXIOV];
46203 -                       chunk *tc;
46204 -                       
46205 -                       size_t num_bytes = 0;
46206 -                       
46207 -                       /* we can't send more then SSIZE_MAX bytes in one chunk */
46208 -                       
46209 -                       /* build writev list 
46210 -                        * 
46211 -                        * 1. limit: num_chunks < UIO_MAXIOV
46212 -                        * 2. limit: num_bytes < SSIZE_MAX
46213 -                        */
46214 -                       for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
46215 -                       
46216 -                       for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
46217 -                               if (tc->mem->used == 0) {
46218 -                                       chunks[i].iov_base = tc->mem->ptr;
46219 -                                       chunks[i].iov_len  = 0;
46220 -                               } else {
46221 -                                       offset = tc->mem->ptr + tc->offset;
46222 -                                       toSend = tc->mem->used - 1 - tc->offset;
46223 -                               
46224 -                                       chunks[i].iov_base = offset;
46225 -                                       
46226 -                                       /* protect the return value of writev() */
46227 -                                       if (toSend > SSIZE_MAX ||
46228 -                                           num_bytes + toSend > SSIZE_MAX) {
46229 -                                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
46230 -                                               
46231 -                                               num_chunks = i + 1;
46232 -                                               break;
46233 -                                       } else {
46234 -                                               chunks[i].iov_len = toSend;
46235 -                                       }
46236 -                                       
46237 -                                       num_bytes += toSend;
46238 -                               }
46239 -                       }
46240 -                       
46241 -                       if ((r = writev(fd, chunks, num_chunks)) < 0) {
46242 -                               switch (errno) {
46243 -                               case EAGAIN:
46244 -                               case EINTR:
46245 -                                       r = 0;
46246 -                                       break;
46247 -                               case EPIPE:
46248 -                               case ECONNRESET:
46249 -                                       return -2;
46250 -                               default:
46251 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
46252 -                                                       "writev failed:", strerror(errno), fd);
46253 -                               
46254 -                                       return -1;
46255 -                               }
46256 -                       }
46257 -                       
46258 -                       /* check which chunks have been written */
46259 -                       cq->bytes_out += r;
46260 -                       
46261 -                       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
46262 -                               if (r >= (ssize_t)chunks[i].iov_len) {
46263 -                                       /* written */
46264 -                                       r -= chunks[i].iov_len;
46265 -                                       tc->offset += chunks[i].iov_len;
46266 -                                       
46267 -                                       if (chunk_finished) {
46268 -                                               /* skip the chunks from further touches */
46269 -                                               chunks_written++;
46270 -                                               c = c->next;
46271 -                                       } else {
46272 -                                               /* chunks_written + c = c->next is done in the for()*/
46273 -                                               chunk_finished++;
46274 -                                       }
46275 -                               } else {
46276 -                                       /* partially written */
46277 -                                       
46278 -                                       tc->offset += r;
46279 -                                       chunk_finished = 0;
46280 -                                       
46281 -                                       break;
46282 -                               }
46283 +               case MEM_CHUNK:
46284 +                       ret = network_write_chunkqueue_writev_mem(srv, con, fd, cq, &c);
46285 +
46286 +                       if (ret != NETWORK_STATUS_SUCCESS) {
46287 +                               return ret;
46288                         }
46289 -                       
46290 +
46291 +                       chunk_finished = 1;
46292 +
46293                         break;
46294 -               }
46295                 case FILE_CHUNK: {
46296                         ssize_t r;
46297                         off_t offset;
46298 @@ -144,25 +64,25 @@
46299                         sendfilevec_t fvec;
46300                         stat_cache_entry *sce = NULL;
46301                         int ifd;
46302 -                       
46303 +
46304                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
46305                                 log_error_write(srv, __FILE__, __LINE__, "sb",
46306                                                 strerror(errno), c->file.name);
46307                                 return -1;
46308                         }
46309 -                                       
46310 +
46311                         offset = c->file.start + c->offset;
46312                         toSend = c->file.length - c->offset;
46313 -                       
46314 +
46315                         if (offset > sce->st.st_size) {
46316                                 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
46317 -                               
46318 +
46319                                 return -1;
46320                         }
46321  
46322                         if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
46323                                 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
46324 -                               
46325 +
46326                                 return -1;
46327                         }
46328  
46329 @@ -170,44 +90,43 @@
46330                         fvec.sfv_flag = 0;
46331                         fvec.sfv_off = offset;
46332                         fvec.sfv_len = toSend;
46333 -                       
46334 +
46335                         /* Solaris sendfilev() */
46336                         if (-1 == (r = sendfilev(fd, &fvec, 1, &written))) {
46337                                 if (errno != EAGAIN) {
46338                                         log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
46339 -                                       
46340 +
46341                                         close(ifd);
46342 -                                       return -1;
46343 +                                       return NETWORK_STATUS_FATAL_ERROR;
46344                                 }
46345 -                               
46346 +
46347                                 r = 0;
46348                         }
46349 -                       
46350 +
46351                         close(ifd);
46352                         c->offset += written;
46353                         cq->bytes_out += written;
46354 -                       
46355 +
46356                         if (c->offset == c->file.length) {
46357                                 chunk_finished = 1;
46358                         }
46359 -                       
46360 +
46361                         break;
46362                 }
46363                 default:
46364 -                       
46365                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
46366 -                       
46367 -                       return -1;
46368 +
46369 +                       return NETWORK_STATUS_FATAL_ERROR;
46370                 }
46371 -               
46372 +
46373                 if (!chunk_finished) {
46374                         /* not finished yet */
46375 -                       
46376 +
46377                         break;
46378                 }
46379         }
46380  
46381 -       return chunks_written;
46382 +       return NETWORK_STATUS_SUCCESS;
46383  }
46384  
46385  #endif
46386 --- ../lighttpd-1.4.11/src/network_write.c      2005-10-22 12:27:56.000000000 +0300
46387 +++ lighttpd-1.4.12/src/network_write.c 2006-07-18 13:03:40.000000000 +0300
46388 @@ -1,11 +1,11 @@
46389  #include <sys/types.h>
46390  #include <sys/stat.h>
46391 -#include <sys/time.h>
46392 +
46393  #include <errno.h>
46394  #include <fcntl.h>
46395 -#include <unistd.h>
46396  #include <string.h>
46397  #include <stdlib.h>
46398 +#include <assert.h>
46399  
46400  #include "network.h"
46401  #include "fdevent.h"
46402 @@ -13,9 +13,12 @@
46403  #include "stat_cache.h"
46404  
46405  #include "sys-socket.h"
46406 +#include "sys-files.h"
46407  
46408  #include "network_backends.h"
46409  
46410 +#ifdef USE_WRITE
46411 +
46412  #ifdef HAVE_SYS_FILIO_H
46413  # include <sys/filio.h>
46414  #endif
46415 @@ -24,47 +27,92 @@
46416  #include <sys/resource.h>
46417  #endif
46418  
46419 -int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq) {
46420 +
46421 +/**
46422 +* fill the chunkqueue will all the data that we can get
46423 +*
46424 +* this might be optimized into a readv() which uses the chunks
46425 +* as vectors
46426 +*/
46427 +NETWORK_BACKEND_READ(read) {
46428 +       int toread;
46429 +       buffer *b;
46430 +       off_t r;
46431 +
46432 +       /**
46433 +        * a EAGAIN is a successful read if we already read something to the chunkqueue
46434 +        */
46435 +       int read_something = 0;
46436 +
46437 +       /* use a chunk-size of 8k */
46438 +       do {
46439 +               toread = 8192;
46440 +
46441 +               b = chunkqueue_get_append_buffer(cq);
46442 +
46443 +               buffer_prepare_copy(b, toread);
46444 +
46445 +               if (-1 == (r = read(sock->fd, b->ptr, toread))) {
46446 +                       switch (errno) {
46447 +                       case EAGAIN:
46448 +                               /* remove the last chunk from the chunkqueue */
46449 +                               chunkqueue_remove_empty_last_chunk(cq);
46450 +                               return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_WAIT_FOR_EVENT;
46451 +                       default:
46452 +                               ERROR("oops, read from fd=%d failed: %s (%d)", sock->fd, strerror(errno), errno );
46453 +
46454 +                               return NETWORK_STATUS_FATAL_ERROR;
46455 +                       }
46456 +               }
46457 +
46458 +               if (r == 0) {
46459 +                       chunkqueue_remove_empty_last_chunk(cq);
46460 +                       return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_CONNECTION_CLOSE;
46461 +               }
46462 +
46463 +               read_something = 1;
46464 +
46465 +               b->used = r;
46466 +               b->ptr[b->used++] = '\0';
46467 +       } while (r == toread); 
46468 +
46469 +       return NETWORK_STATUS_SUCCESS;
46470 +}
46471 +
46472 +NETWORK_BACKEND_WRITE(write) {
46473         chunk *c;
46474         size_t chunks_written = 0;
46475 -       
46476 +
46477         for(c = cq->first; c; c = c->next) {
46478                 int chunk_finished = 0;
46479 -               
46480 +
46481                 switch(c->type) {
46482                 case MEM_CHUNK: {
46483                         char * offset;
46484                         size_t toSend;
46485                         ssize_t r;
46486 -                       
46487 +
46488                         if (c->mem->used == 0) {
46489                                 chunk_finished = 1;
46490                                 break;
46491                         }
46492 -                       
46493 +
46494                         offset = c->mem->ptr + c->offset;
46495                         toSend = c->mem->used - 1 - c->offset;
46496 -#ifdef __WIN32 
46497 -                       if ((r = send(fd, offset, toSend, 0)) < 0) {
46498 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd);
46499 -                               
46500 -                               return -1;
46501 -                       }
46502 -#else
46503 -                       if ((r = write(fd, offset, toSend)) < 0) {
46504 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd);
46505 -                               
46506 -                               return -1;
46507 +
46508 +                       if ((r = write(sock->fd, offset, toSend)) < 0) {
46509 +                               log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), sock->fd);
46510 +
46511 +                               return NETWORK_STATUS_FATAL_ERROR;
46512                         }
46513 -#endif
46514 -                       
46515 +
46516                         c->offset += r;
46517                         cq->bytes_out += r;
46518 -                       
46519 +
46520                         if (c->offset == (off_t)c->mem->used - 1) {
46521                                 chunk_finished = 1;
46522                         }
46523 -                       
46524 +
46525                         break;
46526                 }
46527                 case FILE_CHUNK: {
46528 @@ -76,93 +124,89 @@
46529                         size_t toSend;
46530                         stat_cache_entry *sce = NULL;
46531                         int ifd;
46532 -                       
46533 +
46534                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
46535                                 log_error_write(srv, __FILE__, __LINE__, "sb",
46536                                                 strerror(errno), c->file.name);
46537 -                               return -1;
46538 +                               return NETWORK_STATUS_FATAL_ERROR;
46539                         }
46540 -                       
46541 +
46542                         offset = c->file.start + c->offset;
46543                         toSend = c->file.length - c->offset;
46544 -                       
46545 +
46546                         if (offset > sce->st.st_size) {
46547                                 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
46548 -                               
46549 -                               return -1;
46550 +
46551 +                               return NETWORK_STATUS_FATAL_ERROR;
46552                         }
46553  
46554                         if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
46555                                 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
46556 -                               
46557 -                               return -1;
46558 +
46559 +                               return NETWORK_STATUS_FATAL_ERROR;
46560                         }
46561 -                       
46562 +
46563  #if defined USE_MMAP
46564                         if (MAP_FAILED == (p = mmap(0, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
46565                                 log_error_write(srv, __FILE__, __LINE__, "ss", "mmap failed: ", strerror(errno));
46566  
46567                                 close(ifd);
46568 -                               
46569 -                               return -1;
46570 +
46571 +                               return NETWORK_STATUS_FATAL_ERROR;
46572                         }
46573                         close(ifd);
46574  
46575 -                       if ((r = write(fd, p + offset, toSend)) <= 0) {
46576 +                       if ((r = write(sock->fd, p + offset, toSend)) <= 0) {
46577                                 log_error_write(srv, __FILE__, __LINE__, "ss", "write failed: ", strerror(errno));
46578                                 munmap(p, sce->st.st_size);
46579 -                               return -1;
46580 +                               return NETWORK_STATUS_FATAL_ERROR;
46581                         }
46582 -                       
46583 +
46584                         munmap(p, sce->st.st_size);
46585  #else
46586                         buffer_prepare_copy(srv->tmp_buf, toSend);
46587 -                       
46588 +
46589                         lseek(ifd, offset, SEEK_SET);
46590                         if (-1 == (toSend = read(ifd, srv->tmp_buf->ptr, toSend))) {
46591                                 log_error_write(srv, __FILE__, __LINE__, "ss", "read: ", strerror(errno));
46592                                 close(ifd);
46593 -                               
46594 -                               return -1;
46595 +
46596 +                               return NETWORK_STATUS_FATAL_ERROR;
46597                         }
46598                         close(ifd);
46599  
46600 -                       if (-1 == (r = send(fd, srv->tmp_buf->ptr, toSend, 0))) {
46601 +                       if (-1 == (r = send(sock->fd, srv->tmp_buf->ptr, toSend, 0))) {
46602                                 log_error_write(srv, __FILE__, __LINE__, "ss", "write: ", strerror(errno));
46603 -                               
46604 -                               return -1;
46605 +
46606 +                               return NETWORK_STATUS_FATAL_ERROR;
46607                         }
46608  #endif
46609                         c->offset += r;
46610                         cq->bytes_out += r;
46611 -                       
46612 +
46613                         if (c->offset == c->file.length) {
46614                                 chunk_finished = 1;
46615                         }
46616 -                       
46617 +
46618                         break;
46619                 }
46620                 default:
46621 -                       
46622 +
46623                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
46624 -                       
46625 -                       return -1;
46626 +
46627 +                       return NETWORK_STATUS_FATAL_ERROR;
46628                 }
46629 -               
46630 +
46631                 if (!chunk_finished) {
46632                         /* not finished yet */
46633 -                       
46634 +
46635                         break;
46636                 }
46637 -               
46638 +
46639                 chunks_written++;
46640         }
46641  
46642 -       return chunks_written;
46643 +       return NETWORK_STATUS_SUCCESS;
46644  }
46645  
46646 -#if 0
46647 -network_write_init(void) {
46648 -       p->write = network_write_write_chunkset;
46649 -}
46650  #endif
46651 --- ../lighttpd-1.4.11/src/network_writev.c     2006-02-15 01:02:36.000000000 +0200
46652 +++ lighttpd-1.4.12/src/network_writev.c        2006-07-18 13:03:40.000000000 +0300
46653 @@ -28,10 +28,10 @@
46654  
46655  #ifndef UIO_MAXIOV
46656  # if defined(__FreeBSD__) || defined(__APPLE__) || defined(__NetBSD__)
46657 -/* FreeBSD 4.7 defines it in sys/uio.h only if _KERNEL is specified */ 
46658 +/* FreeBSD 4.7 defines it in sys/uio.h only if _KERNEL is specified */
46659  #  define UIO_MAXIOV 1024
46660  # elif defined(__sgi)
46661 -/* IRIX 6.5 has sysconf(_SC_IOV_MAX) which might return 512 or bigger */ 
46662 +/* IRIX 6.5 has sysconf(_SC_IOV_MAX) which might return 512 or bigger */
46663  #  define UIO_MAXIOV 512
46664  # elif defined(__sun)
46665  /* Solaris (and SunOS?) defines IOV_MAX instead */
46666 @@ -51,105 +51,121 @@
46667  #define LOCAL_BUFFERING 1
46668  #endif
46669  
46670 -int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq) {
46671 -       chunk *c;
46672 +NETWORK_BACKEND_WRITE_CHUNK(writev_mem) {
46673 +       char * offset;
46674 +       size_t toSend;
46675 +       ssize_t r;
46676 +
46677 +       size_t num_chunks, i;
46678 +       struct iovec chunks[UIO_MAXIOV];
46679 +       chunk *tc; /* transfer chunks */
46680 +       size_t num_bytes = 0;
46681 +
46682 +       /* we can't send more then SSIZE_MAX bytes in one chunk */
46683 +
46684 +       /* build writev list
46685 +        *
46686 +        * 1. limit: num_chunks < UIO_MAXIOV
46687 +        * 2. limit: num_bytes < SSIZE_MAX
46688 +        */
46689 +       for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
46690 +
46691 +       for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
46692 +               if (tc->mem->used == 0) {
46693 +                       chunks[i].iov_base = tc->mem->ptr;
46694 +                       chunks[i].iov_len  = 0;
46695 +               } else {
46696 +                       offset = tc->mem->ptr + tc->offset;
46697 +                       toSend = tc->mem->used - 1 - tc->offset;
46698 +
46699 +                       chunks[i].iov_base = offset;
46700 +
46701 +                       /* protect the return value of writev() */
46702 +                       if (toSend > SSIZE_MAX ||
46703 +                           num_bytes + toSend > SSIZE_MAX) {
46704 +                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
46705 +
46706 +                               num_chunks = i + 1;
46707 +                               break;
46708 +                       } else {
46709 +                               chunks[i].iov_len = toSend;
46710 +                       }
46711 +
46712 +                       num_bytes += toSend;
46713 +               }
46714 +       }
46715 +
46716 +       if ((r = writev(sock->fd, chunks, num_chunks)) < 0) {
46717 +               switch (errno) {
46718 +               case EAGAIN:
46719 +                       return NETWORK_STATUS_WAIT_FOR_EVENT;
46720 +               case EINTR:
46721 +                       return NETWORK_STATUS_INTERRUPTED;
46722 +               case EPIPE:
46723 +               case ECONNRESET:
46724 +                       return NETWORK_STATUS_CONNECTION_CLOSE;
46725 +               default:
46726 +                       log_error_write(srv, __FILE__, __LINE__, "ssd",
46727 +                                       "writev failed:", strerror(errno), sock->fd);
46728 +
46729 +                       return NETWORK_STATUS_FATAL_ERROR;
46730 +               }
46731 +       }
46732 +
46733 +       cq->bytes_out += r;
46734 +
46735 +       /* check which chunks have been written */
46736 +
46737 +       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
46738 +               if (r >= (ssize_t)chunks[i].iov_len) {
46739 +                       /* written */
46740 +                       r -= chunks[i].iov_len;
46741 +                       tc->offset += chunks[i].iov_len;
46742 +               } else {
46743 +                       /* partially written */
46744 +
46745 +                       tc->offset += r;
46746 +
46747 +                       return NETWORK_STATUS_WAIT_FOR_EVENT;
46748 +               }
46749 +       }
46750 +
46751 +       /* all chunks have been pushed out */
46752 +       return NETWORK_STATUS_SUCCESS;
46753 +}
46754 +
46755 +NETWORK_BACKEND_WRITE(writev) {
46756 +       chunk *c, *tc;
46757         size_t chunks_written = 0;
46758 -       
46759 +
46760         for(c = cq->first; c; c = c->next) {
46761                 int chunk_finished = 0;
46762 -               
46763 +               network_status_t ret;
46764 +
46765                 switch(c->type) {
46766 -               case MEM_CHUNK: {
46767 -                       char * offset;
46768 -                       size_t toSend;
46769 -                       ssize_t r;
46770 -                       
46771 -                       size_t num_chunks, i;
46772 -                       struct iovec chunks[UIO_MAXIOV];
46773 -                       chunk *tc;
46774 -                       size_t num_bytes = 0;
46775 -                       
46776 -                       /* we can't send more then SSIZE_MAX bytes in one chunk */
46777 -                       
46778 -                       /* build writev list 
46779 -                        * 
46780 -                        * 1. limit: num_chunks < UIO_MAXIOV
46781 -                        * 2. limit: num_bytes < SSIZE_MAX
46782 -                        */
46783 -                       for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
46784 -                       
46785 -                       for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
46786 -                               if (tc->mem->used == 0) {
46787 -                                       chunks[i].iov_base = tc->mem->ptr;
46788 -                                       chunks[i].iov_len  = 0;
46789 -                               } else {
46790 -                                       offset = tc->mem->ptr + tc->offset;
46791 -                                       toSend = tc->mem->used - 1 - tc->offset;
46792 -                               
46793 -                                       chunks[i].iov_base = offset;
46794 -                                       
46795 -                                       /* protect the return value of writev() */
46796 -                                       if (toSend > SSIZE_MAX ||
46797 -                                           num_bytes + toSend > SSIZE_MAX) {
46798 -                                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
46799 -                                               
46800 -                                               num_chunks = i + 1;
46801 -                                               break;
46802 -                                       } else {
46803 -                                               chunks[i].iov_len = toSend;
46804 -                                       }
46805 -                                       
46806 -                                       num_bytes += toSend;
46807 -                               }
46808 -                       }
46809 -                       
46810 -                       if ((r = writev(fd, chunks, num_chunks)) < 0) {
46811 -                               switch (errno) {
46812 -                               case EAGAIN:
46813 -                               case EINTR:
46814 -                                       r = 0;
46815 -                                       break;
46816 -                               case EPIPE:
46817 -                               case ECONNRESET:
46818 -                                       return -2;
46819 -                               default:
46820 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
46821 -                                                       "writev failed:", strerror(errno), fd);
46822 -                               
46823 -                                       return -1;
46824 -                               }
46825 -                       }
46826 -                       
46827 -                       cq->bytes_out += r;
46828 +               case MEM_CHUNK:
46829 +                       ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
46830  
46831 -                       /* check which chunks have been written */
46832 -                       
46833 -                       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
46834 -                               if (r >= (ssize_t)chunks[i].iov_len) {
46835 -                                       /* written */
46836 -                                       r -= chunks[i].iov_len;
46837 -                                       tc->offset += chunks[i].iov_len;
46838 -                                       
46839 +                       /* check which chunks are finished now */
46840 +                       for (tc = c; tc; tc = tc->next) {
46841 +                               /* finished the chunk */
46842 +                               if (tc->offset == tc->mem->used - 1) {
46843 +                                       /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
46844                                         if (chunk_finished) {
46845 -                                               /* skip the chunks from further touches */
46846 -                                               chunks_written++;
46847                                                 c = c->next;
46848                                         } else {
46849 -                                               /* chunks_written + c = c->next is done in the for()*/
46850 -                                               chunk_finished++;
46851 +                                               chunk_finished = 1;
46852                                         }
46853                                 } else {
46854 -                                       /* partially written */
46855 -                                       
46856 -                                       tc->offset += r;
46857 -                                       chunk_finished = 0;
46858 -
46859                                         break;
46860                                 }
46861                         }
46862 -                       
46863 +
46864 +                       if (ret != NETWORK_STATUS_SUCCESS) {
46865 +                               return ret;
46866 +                       }
46867 +
46868                         break;
46869 -               }
46870                 case FILE_CHUNK: {
46871                         ssize_t r;
46872                         off_t abs_offset;
46873 @@ -159,26 +175,26 @@
46874  #define KByte * 1024
46875  #define MByte * 1024 KByte
46876  #define GByte * 1024 MByte
46877 -                       const off_t we_want_to_mmap = 512 KByte; 
46878 +                       const off_t we_want_to_mmap = 512 KByte;
46879                         char *start = NULL;
46880  
46881                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
46882                                 log_error_write(srv, __FILE__, __LINE__, "sb",
46883                                                 strerror(errno), c->file.name);
46884 -                               return -1;
46885 +                               return NETWORK_STATUS_FATAL_ERROR;
46886                         }
46887  
46888                         abs_offset = c->file.start + c->offset;
46889 -                       
46890 +
46891                         if (abs_offset > sce->st.st_size) {
46892 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
46893 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
46894                                                 "file was shrinked:", c->file.name);
46895 -                               
46896 -                               return -1;
46897 +
46898 +                               return NETWORK_STATUS_FATAL_ERROR;
46899                         }
46900  
46901 -                       /* mmap the buffer 
46902 -                        * - first mmap 
46903 +                       /* mmap the buffer
46904 +                        * - first mmap
46905                          * - new mmap as the we are at the end of the last one */
46906                         if (c->file.mmap.start == MAP_FAILED ||
46907                             abs_offset == (off_t)(c->file.mmap.offset + c->file.mmap.length)) {
46908 @@ -188,7 +204,7 @@
46909                                  * adaptive mem-mapping
46910                                  *   the problem:
46911                                  *     we mmap() the whole file. If someone has alot large files and 32bit
46912 -                                *     machine the virtual address area will be unrun and we will have a failing 
46913 +                                *     machine the virtual address area will be unrun and we will have a failing
46914                                  *     mmap() call.
46915                                  *   solution:
46916                                  *     only mmap 16M in one chunk and move the window as soon as we have finished
46917 @@ -234,8 +250,8 @@
46918                                 if (-1 == c->file.fd) {  /* open the file if not already open */
46919                                         if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
46920                                                 log_error_write(srv, __FILE__, __LINE__, "sbs", "open failed for:", c->file.name, strerror(errno));
46921 -                               
46922 -                                               return -1;
46923 +
46924 +                                               return NETWORK_STATUS_FATAL_ERROR;
46925                                         }
46926  #ifdef FD_CLOEXEC
46927                                         fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
46928 @@ -245,10 +261,10 @@
46929                                 if (MAP_FAILED == (c->file.mmap.start = mmap(0, to_mmap, PROT_READ, MAP_SHARED, c->file.fd, c->file.mmap.offset))) {
46930                                         /* close it here, otherwise we'd have to set FD_CLOEXEC */
46931  
46932 -                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:", 
46933 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:",
46934                                                         strerror(errno), c->file.name, c->file.fd);
46935  
46936 -                                       return -1;
46937 +                                       return NETWORK_STATUS_FATAL_ERROR;
46938                                 }
46939  
46940                                 c->file.mmap.length = to_mmap;
46941 @@ -258,7 +274,7 @@
46942  #ifdef HAVE_MADVISE
46943                                 /* don't advise files < 64Kb */
46944                                 if (c->file.mmap.length > (64 KByte)) {
46945 -                                       /* darwin 7 is returning EINVAL all the time and I don't know how to 
46946 +                                       /* darwin 7 is returning EINVAL all the time and I don't know how to
46947                                          * detect this at runtime.i
46948                                          *
46949                                          * ignore the return value for now */
46950 @@ -274,12 +290,12 @@
46951                         toSend = (c->file.mmap.offset + c->file.mmap.length) - (abs_offset);
46952  
46953                         if (toSend < 0) {
46954 -                               log_error_write(srv, __FILE__, __LINE__, "soooo", 
46955 +                               log_error_write(srv, __FILE__, __LINE__, "soooo",
46956                                                 "toSend is negative:",
46957                                                 toSend,
46958                                                 c->file.mmap.length,
46959                                                 abs_offset,
46960 -                                               c->file.mmap.offset); 
46961 +                                               c->file.mmap.offset);
46962                                 assert(toSend < 0);
46963                         }
46964  
46965 @@ -289,7 +305,7 @@
46966                         start = c->file.mmap.start;
46967  #endif
46968  
46969 -                       if ((r = write(fd, start + (abs_offset - c->file.mmap.offset), toSend)) < 0) {
46970 +                       if ((r = write(sock->fd, start + (abs_offset - c->file.mmap.offset), toSend)) < 0) {
46971                                 switch (errno) {
46972                                 case EAGAIN:
46973                                 case EINTR:
46974 @@ -297,18 +313,18 @@
46975                                         break;
46976                                 case EPIPE:
46977                                 case ECONNRESET:
46978 -                                       return -2;
46979 +                                       return NETWORK_STATUS_CONNECTION_CLOSE;
46980                                 default:
46981 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
46982 -                                                       "write failed:", strerror(errno), fd);
46983 -                                       
46984 -                                       return -1;
46985 +                                       log_error_write(srv, __FILE__, __LINE__, "ssd",
46986 +                                                       "write failed:", strerror(errno), sock->fd);
46987 +
46988 +                                       return NETWORK_STATUS_FATAL_ERROR;
46989                                 }
46990                         }
46991 -                       
46992 +
46993                         c->offset += r;
46994                         cq->bytes_out += r;
46995 -                       
46996 +
46997                         if (c->offset == c->file.length) {
46998                                 chunk_finished = 1;
46999  
47000 @@ -318,26 +334,26 @@
47001                                         c->file.mmap.start = MAP_FAILED;
47002                                 }
47003                         }
47004 -                       
47005 +
47006                         break;
47007                 }
47008                 default:
47009 -                       
47010 +
47011                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
47012 -                       
47013 -                       return -1;
47014 +
47015 +                       return NETWORK_STATUS_FATAL_ERROR;
47016                 }
47017 -               
47018 +
47019                 if (!chunk_finished) {
47020                         /* not finished yet */
47021 -                       
47022 +
47023                         break;
47024                 }
47025 -               
47026 +
47027                 chunks_written++;
47028         }
47029  
47030 -       return chunks_written;
47031 +       return NETWORK_STATUS_SUCCESS;
47032  }
47033  
47034  #endif
47035 --- ../lighttpd-1.4.11/src/plugin.c     2006-02-08 14:00:54.000000000 +0200
47036 +++ lighttpd-1.4.12/src/plugin.c        2006-07-16 00:26:04.000000000 +0300
47037 @@ -13,27 +13,27 @@
47038  #include <valgrind/valgrind.h>
47039  #endif
47040  
47041 -#ifndef __WIN32
47042 +#ifndef _WIN32
47043  #include <dlfcn.h>
47044  #endif
47045  /*
47046 - * 
47047 + *
47048   * if you change this enum to add a new callback, be sure
47049   * - that PLUGIN_FUNC_SIZEOF is the last entry
47050   * - that you add PLUGIN_TO_SLOT twice:
47051 - *   1. as callback-dispatcher 
47052 + *   1. as callback-dispatcher
47053   *   2. in plugins_call_init()
47054 - * 
47055 + *
47056   */
47057  
47058  typedef struct {
47059         PLUGIN_DATA;
47060  } plugin_data;
47061  
47062 -typedef enum { 
47063 +typedef enum {
47064         PLUGIN_FUNC_UNSET,
47065 -               PLUGIN_FUNC_HANDLE_URI_CLEAN, 
47066 -               PLUGIN_FUNC_HANDLE_URI_RAW, 
47067 +               PLUGIN_FUNC_HANDLE_URI_CLEAN,
47068 +               PLUGIN_FUNC_HANDLE_URI_RAW,
47069                 PLUGIN_FUNC_HANDLE_REQUEST_DONE,
47070                 PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE,
47071                 PLUGIN_FUNC_HANDLE_TRIGGER,
47072 @@ -44,38 +44,42 @@
47073                 PLUGIN_FUNC_HANDLE_DOCROOT,
47074                 PLUGIN_FUNC_HANDLE_PHYSICAL,
47075                 PLUGIN_FUNC_CONNECTION_RESET,
47076 -               PLUGIN_FUNC_INIT, 
47077 +               PLUGIN_FUNC_INIT,
47078                 PLUGIN_FUNC_CLEANUP,
47079                 PLUGIN_FUNC_SET_DEFAULTS,
47080 -               
47081 +
47082                 PLUGIN_FUNC_SIZEOF
47083  } plugin_t;
47084  
47085  static plugin *plugin_init(void) {
47086         plugin *p;
47087 -       
47088 +
47089         p = calloc(1, sizeof(*p));
47090 -       
47091 +
47092 +       p->required_plugins = array_init();
47093 +
47094         return p;
47095  }
47096  
47097  static void plugin_free(plugin *p) {
47098         int use_dlclose = 1;
47099         if (p->name) buffer_free(p->name);
47100 +
47101 +       array_free(p->required_plugins);
47102  #ifdef HAVE_VALGRIND_VALGRIND_H
47103         /*if (RUNNING_ON_VALGRIND) use_dlclose = 0;*/
47104  #endif
47105  
47106  #ifndef LIGHTTPD_STATIC
47107 -       if (use_dlclose && p->lib) {    
47108 -#ifdef __WIN32
47109 +       if (use_dlclose && p->lib) {
47110 +#ifdef _WIN32
47111                 FreeLibrary(p->lib);
47112  #else
47113                 dlclose(p->lib);
47114  #endif
47115         }
47116  #endif
47117 -               
47118 +
47119         free(p);
47120  }
47121  
47122 @@ -89,17 +93,17 @@
47123                 srv->plugins.size += 4;
47124                 srv->plugins.ptr   = realloc(srv->plugins.ptr, srv->plugins.size * sizeof(*ps));
47125         }
47126 -       
47127 +
47128         ps = srv->plugins.ptr;
47129         ps[srv->plugins.used++] = p;
47130 -       
47131 +
47132         return 0;
47133  }
47134  
47135  /**
47136 - * 
47137 - * 
47138 - * 
47139 + *
47140 + *
47141 + *
47142   */
47143  
47144  #ifdef LIGHTTPD_STATIC
47145 @@ -121,30 +125,35 @@
47146  #else
47147  int plugins_load(server *srv) {
47148         plugin *p;
47149 +#ifdef _WIN32
47150 +    FARPROC init;
47151 +#else
47152         int (*init)(plugin *pl);
47153 +#endif
47154 +
47155         const char *error;
47156 -       size_t i;
47157 -       
47158 +       size_t i, j, k;
47159 +
47160         for (i = 0; i < srv->srvconf.modules->used; i++) {
47161                 data_string *d = (data_string *)srv->srvconf.modules->data[i];
47162                 char *modules = d->value->ptr;
47163 -       
47164 +
47165                 buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.modules_dir);
47166  
47167                 buffer_append_string(srv->tmp_buf, "/");
47168                 buffer_append_string(srv->tmp_buf, modules);
47169 -#if defined(__WIN32) || defined(__CYGWIN__)
47170 +#if defined(_WIN32) || defined(__CYGWIN__)
47171                 buffer_append_string(srv->tmp_buf, ".dll");
47172  #else
47173                 buffer_append_string(srv->tmp_buf, ".so");
47174  #endif
47175 -       
47176 +
47177                 p = plugin_init();
47178 -#ifdef __WIN32
47179 +#ifdef _WIN32
47180                 if (NULL == (p->lib = LoadLibrary(srv->tmp_buf->ptr))) {
47181                         LPVOID lpMsgBuf;
47182                         FormatMessage(
47183 -                               FORMAT_MESSAGE_ALLOCATE_BUFFER | 
47184 +                               FORMAT_MESSAGE_ALLOCATE_BUFFER |
47185                                 FORMAT_MESSAGE_FROM_SYSTEM,
47186                                 NULL,
47187                                 GetLastError(),
47188 @@ -152,36 +161,36 @@
47189                                 (LPTSTR) &lpMsgBuf,
47190                                 0, NULL );
47191  
47192 -                       log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed", 
47193 +                       log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
47194                                         lpMsgBuf, srv->tmp_buf);
47195 -                       
47196 +
47197                         plugin_free(p);
47198 -                       
47199 +
47200                         return -1;
47201  
47202                 }
47203 -#else  
47204 +#else
47205                 if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_LAZY))) {
47206 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:", 
47207 +                       log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:",
47208                                         srv->tmp_buf, dlerror());
47209 -                       
47210 +
47211                         plugin_free(p);
47212 -                       
47213 +
47214                         return -1;
47215                 }
47216 -               
47217 +
47218  #endif
47219                 buffer_reset(srv->tmp_buf);
47220                 buffer_copy_string(srv->tmp_buf, modules);
47221                 buffer_append_string(srv->tmp_buf, "_plugin_init");
47222  
47223 -#ifdef __WIN32
47224 +#ifdef _WIN32
47225                 init = GetProcAddress(p->lib, srv->tmp_buf->ptr);
47226  
47227                 if (init == NULL)  {
47228                         LPVOID lpMsgBuf;
47229                         FormatMessage(
47230 -                               FORMAT_MESSAGE_ALLOCATE_BUFFER | 
47231 +                               FORMAT_MESSAGE_ALLOCATE_BUFFER |
47232                                 FORMAT_MESSAGE_FROM_SYSTEM,
47233                                 NULL,
47234                                 GetLastError(),
47235 @@ -190,7 +199,7 @@
47236                                 0, NULL );
47237  
47238                         log_error_write(srv, __FILE__, __LINE__, "sbs", "getprocaddress failed:", srv->tmp_buf, lpMsgBuf);
47239 -                       
47240 +
47241                         plugin_free(p);
47242                         return -1;
47243                 }
47244 @@ -203,24 +212,43 @@
47245  #endif
47246                 if ((error = dlerror()) != NULL)  {
47247                         log_error_write(srv, __FILE__, __LINE__, "s", error);
47248 -                       
47249 +
47250                         plugin_free(p);
47251                         return -1;
47252                 }
47253 -       
47254 +
47255  #endif
47256                 if ((*init)(p)) {
47257                         log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin init failed" );
47258 -                       
47259 +
47260                         plugin_free(p);
47261                         return -1;
47262                 }
47263  #if 0
47264                 log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin loaded" );
47265  #endif
47266 +               /* check if the required plugin is loaded */
47267 +               for (k = 0; k < p->required_plugins->used; k++) {
47268 +                       data_string *req = (data_string *)p->required_plugins->data[k];
47269 +
47270 +                       for (j = 0; j < i; j++) {
47271 +                               data_string *mod = (data_string *)srv->srvconf.modules->data[j];
47272 +
47273 +                               if (buffer_is_equal(req->value, mod->value)) break;
47274 +                       }
47275 +
47276 +                       if (j == i) {
47277 +                               /* not found */
47278 +                               log_error_write(srv, __FILE__, __LINE__, "ssbs", modules, "failed to load. required plugin", req->value, "was not loaded" );
47279 +
47280 +                               plugin_free(p);
47281 +                       
47282 +                               return -1;
47283 +                       }
47284 +               }
47285                 plugins_register(srv, p);
47286         }
47287 -       
47288 +
47289         return 0;
47290  }
47291  #endif
47292 @@ -253,8 +281,8 @@
47293         }
47294  
47295  /**
47296 - * plugins that use 
47297 - * 
47298 + * plugins that use
47299 + *
47300   * - server *srv
47301   * - connection *con
47302   * - void *p_d (plugin_data *)
47303 @@ -301,12 +329,12 @@
47304         }
47305  
47306  /**
47307 - * plugins that use 
47308 - * 
47309 + * plugins that use
47310 + *
47311   * - server *srv
47312   * - void *p_d (plugin_data *)
47313   */
47314 -                                                                       
47315 +
47316  PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger)
47317  PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup)
47318  PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup)
47319 @@ -314,18 +342,18 @@
47320  
47321  #undef PLUGIN_TO_SLOT
47322  
47323 -#if 0                                                                  
47324 +#if 0
47325  /**
47326 - * 
47327 + *
47328   * special handler
47329 - * 
47330 + *
47331   */
47332  handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) {
47333         size_t i;
47334         plugin **ps;
47335 -       
47336 +
47337         ps = srv->plugins.ptr;
47338 -       
47339 +
47340         for (i = 0; i < srv->plugins.used; i++) {
47341                 plugin *p = ps[i];
47342                 if (p->handle_fdevent) {
47343 @@ -344,34 +372,34 @@
47344                         }
47345                 }
47346         }
47347 -       
47348 +
47349         return HANDLER_GO_ON;
47350  }
47351  #endif
47352  /**
47353 - * 
47354 + *
47355   * - call init function of all plugins to init the plugin-internals
47356   * - added each plugin that supports has callback to the corresponding slot
47357 - * 
47358 + *
47359   * - is only called once.
47360   */
47361  
47362  handler_t plugins_call_init(server *srv) {
47363         size_t i;
47364         plugin **ps;
47365 -       
47366 +
47367         ps = srv->plugins.ptr;
47368 -       
47369 +
47370         /* fill slots */
47371 -       
47372 +
47373         srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps));
47374 -       
47375 +
47376         for (i = 0; i < srv->plugins.used; i++) {
47377                 size_t j;
47378                 /* check which calls are supported */
47379 -               
47380 +
47381                 plugin *p = ps[i];
47382 -               
47383 +
47384  #define PLUGIN_TO_SLOT(x, y) \
47385         if (p->y) { \
47386                 plugin **slot = ((plugin ***)(srv->plugin_slots))[x]; \
47387 @@ -384,11 +412,11 @@
47388                         slot[j] = p;\
47389                         break;\
47390                 }\
47391 -       } 
47392 -               
47393 -               
47394 -               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean); 
47395 -               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw); 
47396 +       }
47397 +
47398 +
47399 +               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean);
47400 +               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw);
47401                 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done);
47402                 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close);
47403                 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger);
47404 @@ -402,19 +430,19 @@
47405                 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup);
47406                 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults);
47407  #undef PLUGIN_TO_SLOT
47408 -               
47409 +
47410                 if (p->init) {
47411                         if (NULL == (p->data = p->init())) {
47412 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
47413 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
47414                                                 "plugin-init failed for module", p->name);
47415                                 return HANDLER_ERROR;
47416                         }
47417 -                       
47418 +
47419                         /* used for con->mode, DIRECT == 0, plugins above that */
47420                         ((plugin_data *)(p->data))->id = i + 1;
47421 -                       
47422 +
47423                         if (p->version != LIGHTTPD_VERSION_ID) {
47424 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
47425 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
47426                                                 "plugin-version doesn't match lighttpd-version for", p->name);
47427                                 return HANDLER_ERROR;
47428                         }
47429 @@ -422,29 +450,46 @@
47430                         p->data = NULL;
47431                 }
47432         }
47433 -       
47434 +
47435         return HANDLER_GO_ON;
47436  }
47437  
47438 +/**
47439 + * get the config-storage of the named plugin 
47440 + */
47441 +void *plugin_get_config(server *srv, const char *name) {
47442 +       size_t i;
47443 +
47444 +       for (i = 0; i < srv->plugins.used; i++) {
47445 +               plugin *p = ((plugin **)srv->plugins.ptr)[i];
47446 +
47447 +               if (buffer_is_equal_string(p->name, name, strlen(name))) {
47448 +                       return p->data;
47449 +               }
47450 +       }
47451 +
47452 +       return NULL;
47453 +}
47454 +
47455  void plugins_free(server *srv) {
47456         size_t i;
47457         plugins_call_cleanup(srv);
47458 -       
47459 +
47460         for (i = 0; i < srv->plugins.used; i++) {
47461                 plugin *p = ((plugin **)srv->plugins.ptr)[i];
47462 -               
47463 +
47464                 plugin_free(p);
47465         }
47466 -       
47467 +
47468         for (i = 0; srv->plugin_slots && i < PLUGIN_FUNC_SIZEOF; i++) {
47469                 plugin **slot = ((plugin ***)(srv->plugin_slots))[i];
47470 -               
47471 +
47472                 if (slot) free(slot);
47473         }
47474 -       
47475 +
47476         free(srv->plugin_slots);
47477         srv->plugin_slots = NULL;
47478 -       
47479 +
47480         free(srv->plugins.ptr);
47481         srv->plugins.ptr = NULL;
47482         srv->plugins.used = 0;
47483 --- ../lighttpd-1.4.11/src/plugin.h     2005-08-15 12:28:56.000000000 +0300
47484 +++ lighttpd-1.4.12/src/plugin.h        2006-07-16 00:26:04.000000000 +0300
47485 @@ -12,6 +12,12 @@
47486  
47487  #define INIT_FUNC(x) \
47488                 static void *x()
47489 +/*
47490 + * The PATCH_OPTION() macro is used in the patch_connection() functions
47491 + * of the modules to update the config object for the current request.
47492 + */
47493 +#define PATCH_OPTION(x) \
47494 +               p->conf.x = s->x
47495  
47496  #define FREE_FUNC          SERVER_FUNC
47497  #define TRIGGER_FUNC       SERVER_FUNC
47498 @@ -25,19 +31,19 @@
47499  #define URIHANDLER_FUNC    CONNECTION_FUNC
47500  
47501  #define PLUGIN_DATA        size_t id
47502 -                                                                                                                                               
47503 +
47504  typedef struct {
47505         size_t version;
47506 -       
47507 +
47508         buffer *name; /* name of the plugin */
47509 -       
47510 +
47511         void *(* init)                       ();
47512         handler_t (* set_defaults)           (server *srv, void *p_d);
47513         handler_t (* cleanup)                (server *srv, void *p_d);
47514                                                                                            /* is called ... */
47515         handler_t (* handle_trigger)         (server *srv, void *p_d);                     /* once a second */
47516         handler_t (* handle_sighup)          (server *srv, void *p_d);                     /* at a signup */
47517 -       
47518 +
47519         handler_t (* handle_uri_raw)         (server *srv, connection *con, void *p_d);    /* after uri_raw is set */
47520         handler_t (* handle_uri_clean)       (server *srv, connection *con, void *p_d);    /* after uri is set */
47521         handler_t (* handle_docroot)         (server *srv, connection *con, void *p_d);    /* getting the document-root */
47522 @@ -45,20 +51,22 @@
47523         handler_t (* handle_request_done)    (server *srv, connection *con, void *p_d);    /* at the end of a request */
47524         handler_t (* handle_connection_close)(server *srv, connection *con, void *p_d);    /* at the end of a connection */
47525         handler_t (* handle_joblist)         (server *srv, connection *con, void *p_d);    /* after all events are handled */
47526 -       
47527 -       
47528 -       
47529 -       handler_t (* handle_subrequest_start)(server *srv, connection *con, void *p_d);   
47530 -       
47531 -                                                                                          /* when a handler for the request 
47532 +
47533 +
47534 +
47535 +       handler_t (* handle_subrequest_start)(server *srv, connection *con, void *p_d);
47536 +
47537 +                                                                                          /* when a handler for the request
47538                                                                                             * has to be found
47539                                                                                             */
47540         handler_t (* handle_subrequest)      (server *srv, connection *con, void *p_d);    /* */
47541         handler_t (* connection_reset)       (server *srv, connection *con, void *p_d);    /* */
47542         void *data;
47543 -       
47544 +
47545         /* dlopen handle */
47546         void *lib;
47547 +
47548 +       array *required_plugins;
47549  } plugin;
47550  
47551  int plugins_load(server *srv);
47552 @@ -88,5 +96,8 @@
47553  int config_patch_connection(server *srv, connection *con, comp_key_t comp);
47554  int config_check_cond(server *srv, connection *con, data_config *dc);
47555  int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n);
47556 +int config_exec_pcre_keyvalue_buffer(connection *con, pcre_keyvalue_buffer *kvb, data_config *context, buffer *match_buf, buffer *result);
47557 +
47558 +void *plugin_get_config(server *srv, const char *name);
47559  
47560  #endif
47561 --- ../lighttpd-1.4.11/src/proc_open.c  2005-08-11 01:26:39.000000000 +0300
47562 +++ lighttpd-1.4.12/src/proc_open.c     2006-07-16 00:26:04.000000000 +0300
47563 @@ -13,13 +13,13 @@
47564  #endif
47565  
47566  
47567 -#ifdef WIN32
47568 +#ifdef _WIN32
47569  /* {{{ win32 stuff */
47570  # define SHELLENV "ComSpec"
47571  # define SECURITY_DC , SECURITY_ATTRIBUTES *security
47572  # define SECURITY_CC , security
47573  # define pipe(pair) (CreatePipe(&pair[0], &pair[1], security, 2048L) ? 0 : -1)
47574 -static inline HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig)
47575 +static HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig)
47576  {
47577         HANDLE copy, self = GetCurrentProcess();
47578  
47579 @@ -148,11 +148,14 @@
47580         STARTUPINFO si;
47581         BOOL procok;
47582         SECURITY_ATTRIBUTES security;
47583 -       const char *shell;
47584 +       const char *shell = NULL;
47585 +       const char *windir = NULL;
47586         buffer *cmdline;
47587  
47588 -       if (NULL == (shell = getenv(SHELLENV))) {
47589 -               fprintf(stderr, "env %s is required", SHELLENV);
47590 +       if (NULL == (shell = getenv(SHELLENV)) &&
47591 +                       NULL == (windir = getenv("SystemRoot")) &&
47592 +                       NULL == (windir = getenv("windir"))) {
47593 +               fprintf(stderr, "One of %s,%%SystemRoot,%%windir is required", SHELLENV);
47594                 return -1;
47595         }
47596  
47597 @@ -177,17 +180,23 @@
47598         memset(&pi, 0, sizeof(pi));
47599  
47600         cmdline = buffer_init();
47601 -       buffer_append_string(cmdline, shell);
47602 +       if (shell) {
47603 +               buffer_append_string(cmdline, shell);
47604 +       } else {
47605 +               buffer_append_string(cmdline, windir);
47606 +               buffer_append_string(cmdline, "\\system32\\cmd.exe");
47607 +       }
47608         buffer_append_string_len(cmdline, CONST_STR_LEN(" /c "));
47609         buffer_append_string(cmdline, command);
47610         procok = CreateProcess(NULL, cmdline->ptr, &security, &security, TRUE,
47611                         NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
47612 -       buffer_free(cmdline);
47613  
47614         if (FALSE == procok) {
47615 -               fprintf(stderr, "failed to CreateProcess");
47616 +               fprintf(stderr, "failed to CreateProcess: %s", cmdline->ptr);
47617 +               buffer_free(cmdline);
47618                 return -1;
47619         }
47620 +       buffer_free(cmdline);
47621  
47622         proc->child = pi.hProcess;
47623         CloseHandle(pi.hThread);
47624 @@ -226,8 +235,7 @@
47625         const char *shell;
47626  
47627         if (NULL == (shell = getenv(SHELLENV))) {
47628 -               fprintf(stderr, "env %s is required", SHELLENV);
47629 -               return -1;
47630 +               shell = "/bin/sh";
47631         }
47632  
47633         if (proc_open_pipes(proc) != 0) {
47634 @@ -262,11 +270,11 @@
47635         }
47636  }
47637  /* }}} */
47638 -#endif /* WIN32 */
47639 +#endif /* _WIN32 */
47640  
47641  /* {{{ proc_read_fd_to_buffer */
47642  static void proc_read_fd_to_buffer(int fd, buffer *b) {
47643 -       ssize_t s;
47644 +       int s; /* win32 has not ssize_t */
47645  
47646         for (;;) {
47647                 buffer_prepare_append(b, 512);
47648 --- ../lighttpd-1.4.11/src/proc_open.h  2005-08-11 01:26:39.000000000 +0300
47649 +++ lighttpd-1.4.12/src/proc_open.h     2006-07-16 00:26:04.000000000 +0300
47650 @@ -1,7 +1,7 @@
47651  
47652  #include "buffer.h"
47653  
47654 -#ifdef WIN32
47655 +#ifdef _WIN32
47656  #include <windows.h>
47657  typedef HANDLE descriptor_t;
47658  typedef HANDLE proc_pid_t;
47659 --- ../lighttpd-1.4.11/src/request.c    2006-03-05 11:58:09.000000000 +0200
47660 +++ lighttpd-1.4.12/src/request.c       2006-07-18 13:03:40.000000000 +0300
47661 @@ -10,15 +10,17 @@
47662  #include "keyvalue.h"
47663  #include "log.h"
47664  
47665 +#include "sys-strings.h"
47666 +
47667  static int request_check_hostname(server *srv, connection *con, buffer *host) {
47668         enum { DOMAINLABEL, TOPLABEL } stage = TOPLABEL;
47669         size_t i;
47670         int label_len = 0;
47671         size_t host_len;
47672         char *colon;
47673 -       int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */ 
47674 +       int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */
47675         int level = 0;
47676 -       
47677 +
47678         UNUSED(srv);
47679         UNUSED(con);
47680  
47681 @@ -32,17 +34,17 @@
47682          *       IPv6address   = "[" ... "]"
47683          *       port          = *digit
47684          */
47685 -       
47686 +
47687         /* no Host: */
47688         if (!host || host->used == 0) return 0;
47689 -       
47690 +
47691         host_len = host->used - 1;
47692 -       
47693 +
47694         /* IPv6 adress */
47695         if (host->ptr[0] == '[') {
47696                 char *c = host->ptr + 1;
47697                 int colon_cnt = 0;
47698 -               
47699 +
47700                 /* check portnumber */
47701                 for (; *c && *c != ']'; c++) {
47702                         if (*c == ':') {
47703 @@ -53,12 +55,12 @@
47704                                 return -1;
47705                         }
47706                 }
47707 -               
47708 +
47709                 /* missing ] */
47710                 if (!*c) {
47711                         return -1;
47712                 }
47713 -               
47714 +
47715                 /* check port */
47716                 if (*(c+1) == ':') {
47717                         for (c += 2; *c; c++) {
47718 @@ -69,39 +71,39 @@
47719                 }
47720                 return 0;
47721         }
47722 -       
47723 +
47724         if (NULL != (colon = memchr(host->ptr, ':', host_len))) {
47725                 char *c = colon + 1;
47726 -               
47727 +
47728                 /* check portnumber */
47729                 for (; *c; c++) {
47730                         if (!light_isdigit(*c)) return -1;
47731                 }
47732 -               
47733 +
47734                 /* remove the port from the host-len */
47735                 host_len = colon - host->ptr;
47736         }
47737 -       
47738 +
47739         /* Host is empty */
47740         if (host_len == 0) return -1;
47741 -       
47742 +
47743         /* scan from the right and skip the \0 */
47744         for (i = host_len - 1; i + 1 > 0; i--) {
47745                 const char c = host->ptr[i];
47746  
47747                 switch (stage) {
47748 -               case TOPLABEL: 
47749 +               case TOPLABEL:
47750                         if (c == '.') {
47751                                 /* only switch stage, if this is not the last character */
47752                                 if (i != host_len - 1) {
47753                                         if (label_len == 0) {
47754                                                 return -1;
47755                                         }
47756 -                                       
47757 +
47758                                         /* check the first character at right of the dot */
47759                                         if (is_ip == 0) {
47760                                                 if (!light_isalpha(host->ptr[i+1])) {
47761 -                                                       return -1; 
47762 +                                                       return -1;
47763                                                 }
47764                                         } else if (!light_isdigit(host->ptr[i+1])) {
47765                                                 is_ip = 0;
47766 @@ -111,9 +113,9 @@
47767                                                 /* just digits */
47768                                                 is_ip = 1;
47769                                         }
47770 -                                               
47771 +
47772                                         stage = DOMAINLABEL;
47773 -                                       
47774 +
47775                                         label_len = 0;
47776                                         level++;
47777                                 } else if (i == 0) {
47778 @@ -135,7 +137,7 @@
47779                                 }
47780                                 label_len++;
47781                         }
47782 -                       
47783 +
47784                         break;
47785                 case DOMAINLABEL:
47786                         if (is_ip == 1) {
47787 @@ -143,7 +145,7 @@
47788                                         if (label_len == 0) {
47789                                                 return -1;
47790                                         }
47791 -                                       
47792 +
47793                                         label_len = 0;
47794                                         level++;
47795                                 } else if (!light_isdigit(c)) {
47796 @@ -156,12 +158,12 @@
47797                                         if (label_len == 0) {
47798                                                 return -1;
47799                                         }
47800 -                                       
47801 +
47802                                         /* c is either - or alphanum here */
47803                                         if ('-' == host->ptr[i+1]) {
47804                                                 return -1;
47805                                         }
47806 -                                       
47807 +
47808                                         label_len = 0;
47809                                         level++;
47810                                 } else if (i == 0) {
47811 @@ -176,20 +178,20 @@
47812                                         label_len++;
47813                                 }
47814                         }
47815 -                       
47816 +
47817                         break;
47818                 }
47819         }
47820 -       
47821 +
47822         /* a IP has to consist of 4 parts */
47823         if (is_ip == 1 && level != 3) {
47824                 return -1;
47825         }
47826 -       
47827 +
47828         if (label_len == 0) {
47829                 return -1;
47830         }
47831 -       
47832 +
47833         return 0;
47834  }
47835  
47836 @@ -201,53 +203,53 @@
47837         char *s;
47838         size_t i;
47839         int state = 0;
47840 -       /*  
47841 -        * parse 
47842 -        * 
47843 +       /*
47844 +        * parse
47845 +        *
47846          * val1, val2, val3, val4
47847 -        * 
47848 +        *
47849          * into a array (more or less a explode() incl. striping of whitespaces
47850          */
47851 -       
47852 +
47853         if (b->used == 0) return 0;
47854 -       
47855 +
47856         s = b->ptr;
47857 -       
47858 +
47859         for (i =0; i < b->used - 1; ) {
47860                 char *start = NULL, *end = NULL;
47861                 data_string *ds;
47862 -               
47863 +
47864                 switch (state) {
47865                 case 0: /* ws */
47866 -                       
47867 +
47868                         /* skip ws */
47869                         for (; (*s == ' ' || *s == '\t') && i < b->used - 1; i++, s++);
47870 -                       
47871 -                       
47872 +
47873 +
47874                         state = 1;
47875                         break;
47876                 case 1: /* value */
47877                         start = s;
47878 -                       
47879 +
47880                         for (; *s != ',' && i < b->used - 1; i++, s++);
47881                         end = s - 1;
47882 -                       
47883 +
47884                         for (; (*end == ' ' || *end == '\t') && end > start; end--);
47885 -                       
47886 +
47887                         if (NULL == (ds = (data_string *)array_get_unused_element(vals, TYPE_STRING))) {
47888                                 ds = data_string_init();
47889                         }
47890  
47891                         buffer_copy_string_len(ds->value, start, end-start+1);
47892                         array_insert_unique(vals, (data_unset *)ds);
47893 -                       
47894 +
47895                         if (*s == ',') {
47896                                 state = 0;
47897                                 i++;
47898                                 s++;
47899                         } else {
47900                                 /* end of string */
47901 -                               
47902 +
47903                                 state = 2;
47904                         }
47905                         break;
47906 @@ -263,7 +265,7 @@
47907         if (c <= 32) return 0;
47908         if (c == 127) return 0;
47909         if (c == 255) return 0;
47910 -       
47911 +
47912         return 1;
47913  }
47914  
47915 @@ -271,28 +273,28 @@
47916         char *uri = NULL, *proto = NULL, *method = NULL, con_length_set;
47917         int is_key = 1, key_len = 0, is_ws_after_key = 0, in_folding;
47918         char *value = NULL, *key = NULL;
47919 -       
47920 +
47921         enum { HTTP_CONNECTION_UNSET, HTTP_CONNECTION_KEEPALIVE, HTTP_CONNECTION_CLOSE } keep_alive_set = HTTP_CONNECTION_UNSET;
47922 -       
47923 +
47924         int line = 0;
47925 -       
47926 +
47927         int request_line_stage = 0;
47928         size_t i, first;
47929 -       
47930 +
47931         int done = 0;
47932 -       
47933 +
47934         data_string *ds = NULL;
47935 -       
47936 -       /* 
47937 -        * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$" 
47938 -        * Option : "^([-a-zA-Z]+): (.+)$"                    
47939 +
47940 +       /*
47941 +        * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$"
47942 +        * Option : "^([-a-zA-Z]+): (.+)$"
47943          * End    : "^$"
47944          */
47945  
47946         if (con->conf.log_request_header) {
47947 -               log_error_write(srv, __FILE__, __LINE__, "sdsdSb", 
47948 -                               "fd:", con->fd, 
47949 -                               "request-len:", con->request.request->used, 
47950 +               log_error_write(srv, __FILE__, __LINE__, "sdsdSb",
47951 +                               "fd:", con->sock->fd,
47952 +                               "request-len:", con->request.request->used,
47953                                 "\n", con->request.request);
47954         }
47955  
47956 @@ -300,13 +302,13 @@
47957             con->request.request->ptr[0] == '\r' &&
47958             con->request.request->ptr[1] == '\n') {
47959                 /* we are in keep-alive and might get \r\n after a previous POST request.*/
47960 -               
47961 +
47962                 buffer_copy_string_len(con->parse_request, con->request.request->ptr + 2, con->request.request->used - 1 - 2);
47963         } else {
47964                 /* fill the local request buffer */
47965                 buffer_copy_string_buffer(con->parse_request, con->request.request);
47966         }
47967 -       
47968 +
47969         keep_alive_set = 0;
47970         con_length_set = 0;
47971  
47972 @@ -318,25 +320,25 @@
47973          * */
47974         for (i = 0, first = 0; i < con->parse_request->used && line == 0; i++) {
47975                 char *cur = con->parse_request->ptr + i;
47976 -               
47977 +
47978                 switch(*cur) {
47979 -               case '\r': 
47980 +               case '\r':
47981                         if (con->parse_request->ptr[i+1] == '\n') {
47982                                 http_method_t r;
47983                                 char *nuri = NULL;
47984                                 size_t j;
47985 -                               
47986 +
47987                                 /* \r\n -> \0\0 */
47988                                 con->parse_request->ptr[i] = '\0';
47989                                 con->parse_request->ptr[i+1] = '\0';
47990 -                               
47991 +
47992                                 buffer_copy_string_len(con->request.request_line, con->parse_request->ptr, i);
47993 -                               
47994 +
47995                                 if (request_line_stage != 2) {
47996                                         con->http_status = 400;
47997                                         con->response.keep_alive = 0;
47998                                         con->keep_alive = 0;
47999 -                                       
48000 +
48001                                         if (srv->srvconf.log_request_header_on_error) {
48002                                                 log_error_write(srv, __FILE__, __LINE__, "s", "incomplete request line -> 400");
48003                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48004 @@ -345,36 +347,36 @@
48005                                         }
48006                                         return 0;
48007                                 }
48008 -                               
48009 +
48010                                 proto = con->parse_request->ptr + first;
48011 -                               
48012 +
48013                                 *(uri - 1) = '\0';
48014                                 *(proto - 1) = '\0';
48015 -                               
48016 +
48017                                 /* we got the first one :) */
48018                                 if (-1 == (r = get_http_method_key(method))) {
48019                                         con->http_status = 501;
48020                                         con->response.keep_alive = 0;
48021                                         con->keep_alive = 0;
48022 -                                       
48023 +
48024                                         if (srv->srvconf.log_request_header_on_error) {
48025                                                 log_error_write(srv, __FILE__, __LINE__, "s", "unknown http-method -> 501");
48026                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48027                                                                 "request-header:\n",
48028                                                                 con->request.request);
48029                                         }
48030 -                               
48031 +
48032                                         return 0;
48033                                 }
48034 -                               
48035 +
48036                                 con->request.http_method = r;
48037 -                       
48038 -                               /* 
48039 +
48040 +                               /*
48041                                  * RFC2616 says:
48042                                  *
48043                                  * HTTP-Version   = "HTTP" "/" 1*DIGIT "." 1*DIGIT
48044                                  *
48045 -                                * */   
48046 +                                * */
48047                                 if (0 == strncmp(proto, "HTTP/", sizeof("HTTP/") - 1)) {
48048                                         char * major = proto + sizeof("HTTP/") - 1;
48049                                         char * minor = strchr(major, '.');
48050 @@ -413,10 +415,10 @@
48051                                         }
48052  
48053                                         if (major_num == 1 && minor_num == 1) {
48054 -                                               con->request.http_version = con->conf.allow_http11 ? HTTP_VERSION_1_1 : HTTP_VERSION_1_0;
48055 +                                               con->request.http_version = HTTP_VERSION_1_1;
48056                                         } else if (major_num == 1 && minor_num == 0) {
48057                                                 con->request.http_version = HTTP_VERSION_1_0;
48058 -                                       } else { 
48059 +                                       } else {
48060                                                 con->http_status = 505;
48061  
48062                                                 if (srv->srvconf.log_request_header_on_error) {
48063 @@ -439,30 +441,30 @@
48064                                         }
48065                                         return 0;
48066                                 }
48067 -                               
48068 +
48069                                 if (0 == strncmp(uri, "http://", 7) &&
48070                                     NULL != (nuri = strchr(uri + 7, '/'))) {
48071                                         /* ignore the host-part */
48072 -                                       
48073 +
48074                                         buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
48075                                 } else {
48076                                         /* everything looks good so far */
48077                                         buffer_copy_string_len(con->request.uri, uri, proto - uri - 1);
48078                                 }
48079 -                               
48080 +
48081                                 /* check uri for invalid characters */
48082                                 for (j = 0; j < con->request.uri->used - 1; j++) {
48083                                         if (!request_uri_is_valid_char(con->request.uri->ptr[j])) {
48084                                                 unsigned char buf[2];
48085                                                 con->http_status = 400;
48086                                                 con->keep_alive = 0;
48087 -                                               
48088 +
48089                                                 if (srv->srvconf.log_request_header_on_error) {
48090                                                         buf[0] = con->request.uri->ptr[j];
48091                                                         buf[1] = '\0';
48092 -                                       
48093 +
48094                                                         if (con->request.uri->ptr[j] > 32 &&
48095 -                                                           con->request.uri->ptr[j] != 127) {  
48096 +                                                           con->request.uri->ptr[j] != 127) {
48097                                                                 /* the character is printable -> print it */
48098                                                                 log_error_write(srv, __FILE__, __LINE__, "ss",
48099                                                                                 "invalid character in URI -> 400",
48100 @@ -473,20 +475,20 @@
48101                                                                                 "invalid character in URI -> 400",
48102                                                                                 con->request.uri->ptr[j]);
48103                                                         }
48104 -                                               
48105 +
48106                                                         log_error_write(srv, __FILE__, __LINE__, "Sb",
48107                                                                         "request-header:\n",
48108                                                                         con->request.request);
48109                                                 }
48110 -                                               
48111 +
48112                                                 return 0;
48113                                         }
48114                                 }
48115 -                               
48116 +
48117                                 buffer_copy_string_buffer(con->request.orig_uri, con->request.uri);
48118 -                               
48119 +
48120                                 con->http_status = 0;
48121 -                               
48122 +
48123                                 i++;
48124                                 line++;
48125                                 first = i+1;
48126 @@ -494,14 +496,14 @@
48127                         break;
48128                 case ' ':
48129                         switch(request_line_stage) {
48130 -                       case 0: 
48131 +                       case 0:
48132                                 /* GET|POST|... */
48133 -                               method = con->parse_request->ptr + first; 
48134 +                               method = con->parse_request->ptr + first;
48135                                 first = i + 1;
48136                                 break;
48137                         case 1:
48138                                 /* /foobar/... */
48139 -                               uri = con->parse_request->ptr + first; 
48140 +                               uri = con->parse_request->ptr + first;
48141                                 first = i + 1;
48142                                 break;
48143                         default:
48144 @@ -509,7 +511,7 @@
48145                                 con->http_status = 400;
48146                                 con->response.keep_alive = 0;
48147                                 con->keep_alive = 0;
48148 -                               
48149 +
48150                                 if (srv->srvconf.log_request_header_on_error) {
48151                                         log_error_write(srv, __FILE__, __LINE__, "s", "overlong request line -> 400");
48152                                         log_error_write(srv, __FILE__, __LINE__, "Sb",
48153 @@ -518,12 +520,12 @@
48154                                 }
48155                                 return 0;
48156                         }
48157 -                       
48158 +
48159                         request_line_stage++;
48160                         break;
48161                 }
48162         }
48163 -       
48164 +
48165         in_folding = 0;
48166  
48167         if (con->request.uri->used == 1) {
48168 @@ -540,30 +542,30 @@
48169                 return 0;
48170         }
48171  
48172 -       
48173 +
48174         for (; i < con->parse_request->used && !done; i++) {
48175                 char *cur = con->parse_request->ptr + i;
48176 -               
48177 +
48178                 if (is_key) {
48179                         size_t j;
48180                         int got_colon = 0;
48181 -                       
48182 +
48183                         /**
48184                          * 1*<any CHAR except CTLs or separators>
48185                          * CTLs == 0-31 + 127
48186 -                        * 
48187 +                        *
48188                          */
48189                         switch(*cur) {
48190                         case ':':
48191                                 is_key = 0;
48192 -                               
48193 +
48194                                 value = cur + 1;
48195 -                               
48196 +
48197                                 if (is_ws_after_key == 0) {
48198                                         key_len = i - first;
48199                                 }
48200                                 is_ws_after_key = 0;
48201 -                                       
48202 +
48203                                 break;
48204                         case '(':
48205                         case ')':
48206 @@ -584,8 +586,8 @@
48207                                 con->http_status = 400;
48208                                 con->keep_alive = 0;
48209                                 con->response.keep_alive = 0;
48210 -                               
48211 -                               log_error_write(srv, __FILE__, __LINE__, "sbsds", 
48212 +
48213 +                               log_error_write(srv, __FILE__, __LINE__, "sbsds",
48214                                                 "invalid character in key", con->request.request, cur, *cur, "-> 400");
48215                                 return 0;
48216                         case ' ':
48217 @@ -594,13 +596,13 @@
48218                                         is_key = 0;
48219                                         in_folding = 1;
48220                                         value = cur;
48221 -                                       
48222 +
48223                                         break;
48224                                 }
48225 -                               
48226 -                               
48227 +
48228 +
48229                                 key_len = i - first;
48230 -                               
48231 +
48232                                 /* skip every thing up to the : */
48233                                 for (j = 1; !got_colon; j++) {
48234                                         switch(con->parse_request->ptr[j + i]) {
48235 @@ -610,40 +612,40 @@
48236                                                 continue;
48237                                         case ':':
48238                                                 /* ok, done */
48239 -                                               
48240 +
48241                                                 i += j - 1;
48242                                                 got_colon = 1;
48243 -                                               
48244 +
48245                                                 break;
48246                                         default:
48247                                                 /* error */
48248 -                                               
48249 +
48250                                                 if (srv->srvconf.log_request_header_on_error) {
48251                                                         log_error_write(srv, __FILE__, __LINE__, "s", "WS character in key -> 400");
48252                                                         log_error_write(srv, __FILE__, __LINE__, "Sb",
48253                                                                 "request-header:\n",
48254                                                                 con->request.request);
48255                                                 }
48256 -                                       
48257 +
48258                                                 con->http_status = 400;
48259                                                 con->response.keep_alive = 0;
48260                                                 con->keep_alive = 0;
48261 -                                               
48262 +
48263                                                 return 0;
48264                                         }
48265                                 }
48266 -                               
48267 +
48268                                 break;
48269                         case '\r':
48270                                 if (con->parse_request->ptr[i+1] == '\n' && i == first) {
48271                                         /* End of Header */
48272                                         con->parse_request->ptr[i] = '\0';
48273                                         con->parse_request->ptr[i+1] = '\0';
48274 -                                       
48275 +
48276                                         i++;
48277 -                                       
48278 +
48279                                         done = 1;
48280 -                                       
48281 +
48282                                         break;
48283                                 } else {
48284                                         if (srv->srvconf.log_request_header_on_error) {
48285 @@ -652,7 +654,7 @@
48286                                                         "request-header:\n",
48287                                                         con->request.request);
48288                                         }
48289 -                                       
48290 +
48291                                         con->http_status = 400;
48292                                         con->keep_alive = 0;
48293                                         con->response.keep_alive = 0;
48294 @@ -693,16 +695,16 @@
48295                                 con->http_status = 400;
48296                                 con->keep_alive = 0;
48297                                 con->response.keep_alive = 0;
48298 -                               
48299 +
48300                                 if (srv->srvconf.log_request_header_on_error) {
48301 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsds", 
48302 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsds",
48303                                                 "CTL character in key", con->request.request, cur, *cur, "-> 400");
48304  
48305                                         log_error_write(srv, __FILE__, __LINE__, "Sb",
48306                                                 "request-header:\n",
48307                                                 con->request.request);
48308                                 }
48309 -                               
48310 +
48311                                 return 0;
48312                         default:
48313                                 /* ok */
48314 @@ -710,25 +712,25 @@
48315                         }
48316                 } else {
48317                         switch(*cur) {
48318 -                       case '\r': 
48319 +                       case '\r':
48320                                 if (con->parse_request->ptr[i+1] == '\n') {
48321                                         /* End of Headerline */
48322                                         con->parse_request->ptr[i] = '\0';
48323                                         con->parse_request->ptr[i+1] = '\0';
48324 -                                       
48325 +
48326                                         if (in_folding) {
48327                                                 if (!ds) {
48328                                                         /* 400 */
48329 -                                       
48330 +
48331                                                         if (srv->srvconf.log_request_header_on_error) {
48332                                                                 log_error_write(srv, __FILE__, __LINE__, "s", "WS at the start of first line -> 400");
48333 -                                                       
48334 +
48335                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48336                                                                         "request-header:\n",
48337                                                                         con->request.request);
48338                                                         }
48339  
48340 -                                       
48341 +
48342                                                         con->http_status = 400;
48343                                                         con->keep_alive = 0;
48344                                                         con->response.keep_alive = 0;
48345 @@ -738,9 +740,9 @@
48346                                         } else {
48347                                                 int s_len;
48348                                                 key = con->parse_request->ptr + first;
48349 -                                       
48350 +
48351                                                 s_len = cur - value;
48352 -                                               
48353 +
48354                                                 if (s_len > 0) {
48355                                                         int cmp = 0;
48356                                                         if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
48357 @@ -748,86 +750,87 @@
48358                                                         }
48359                                                         buffer_copy_string_len(ds->key, key, key_len);
48360                                                         buffer_copy_string_len(ds->value, value, s_len);
48361 -                                                       
48362 -                                                       /* retreive values 
48363 -                                                        * 
48364 -                                                        * 
48365 +
48366 +                                                       /* retreive values
48367 +                                                        *
48368 +                                                        *
48369                                                          * the list of options is sorted to simplify the search
48370                                                          */
48371 -                                                       
48372 +
48373                                                         if (0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Connection")))) {
48374                                                                 array *vals;
48375                                                                 size_t vi;
48376 -                                                               
48377 +
48378                                                                 /* split on , */
48379 -                                                               
48380 +
48381                                                                 vals = srv->split_vals;
48382  
48383                                                                 array_reset(vals);
48384 -                                                               
48385 +
48386                                                                 http_request_split_value(vals, ds->value);
48387 -                                                               
48388 +
48389                                                                 for (vi = 0; vi < vals->used; vi++) {
48390                                                                         data_string *dsv = (data_string *)vals->data[vi];
48391 -                                                                       
48392 +
48393                                                                         if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("keep-alive"))) {
48394                                                                                 keep_alive_set = HTTP_CONNECTION_KEEPALIVE;
48395 -                                                                               
48396 +
48397                                                                                 break;
48398                                                                         } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("close"))) {
48399                                                                                 keep_alive_set = HTTP_CONNECTION_CLOSE;
48400 -                                                                               
48401 +
48402                                                                                 break;
48403                                                                         }
48404                                                                 }
48405 -                                                               
48406 +
48407                                                         } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) {
48408                                                                 char *err;
48409                                                                 unsigned long int r;
48410                                                                 size_t j;
48411 -                                                               
48412 +
48413                                                                 if (con_length_set) {
48414                                                                         con->http_status = 400;
48415                                                                         con->keep_alive = 0;
48416 -                                                                       
48417 +
48418                                                                         if (srv->srvconf.log_request_header_on_error) {
48419 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
48420 +                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
48421                                                                                                 "duplicate Content-Length-header -> 400");
48422                                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48423                                                                                                 "request-header:\n",
48424                                                                                                 con->request.request);
48425                                                                         }
48426 +                                                                       ds->free((data_unset *) ds);
48427                                                                         return 0;
48428                                                                 }
48429 -                                                               
48430 +
48431                                                                 if (ds->value->used == 0) SEGFAULT();
48432 -                                                               
48433 +
48434                                                                 for (j = 0; j < ds->value->used - 1; j++) {
48435                                                                         char c = ds->value->ptr[j];
48436                                                                         if (!isdigit((unsigned char)c)) {
48437 -                                                                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
48438 +                                                                               log_error_write(srv, __FILE__, __LINE__, "sbs",
48439                                                                                                 "content-length broken:", ds->value, "-> 400");
48440 -                                                                               
48441 +
48442                                                                                 con->http_status = 400;
48443                                                                                 con->keep_alive = 0;
48444 -                                                                               
48445 +
48446                                                                                 array_insert_unique(con->request.headers, (data_unset *)ds);
48447                                                                                 return 0;
48448                                                                         }
48449                                                                 }
48450 -                                                               
48451 +
48452                                                                 r = strtoul(ds->value->ptr, &err, 10);
48453 -                                                               
48454 +
48455                                                                 if (*err == '\0') {
48456                                                                         con_length_set = 1;
48457                                                                         con->request.content_length = r;
48458                                                                 } else {
48459 -                                                                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
48460 +                                                                       log_error_write(srv, __FILE__, __LINE__, "sbs",
48461                                                                                         "content-length broken:", ds->value, "-> 400");
48462 -                                                                       
48463 +
48464                                                                         con->http_status = 400;
48465                                                                         con->keep_alive = 0;
48466 -                                                                       
48467 +
48468                                                                         array_insert_unique(con->request.headers, (data_unset *)ds);
48469                                                                         return 0;
48470                                                                 }
48471 @@ -838,23 +841,24 @@
48472                                                                 } else {
48473                                                                         con->http_status = 400;
48474                                                                         con->keep_alive = 0;
48475 -                                                                       
48476 +
48477                                                                         if (srv->srvconf.log_request_header_on_error) {
48478 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
48479 +                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
48480                                                                                                 "duplicate Content-Type-header -> 400");
48481                                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48482                                                                                                 "request-header:\n",
48483                                                                                                 con->request.request);
48484                                                                         }
48485 +                                                                       ds->free((data_unset *) ds);
48486                                                                         return 0;
48487                                                                 }
48488                                                         } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Expect")))) {
48489 -                                                               /* HTTP 2616 8.2.3 
48490 +                                                               /* HTTP 2616 8.2.3
48491                                                                  * Expect: 100-continue
48492 -                                                                * 
48493 +                                                                *
48494                                                                  *   -> (10.1.1)  100 (read content, process request, send final status-code)
48495                                                                  *   -> (10.4.18) 417 (close)
48496 -                                                                * 
48497 +                                                                *
48498                                                                  * (not handled at all yet, we always send 417 here)
48499                                                                  *
48500                                                                  * What has to be added ?
48501 @@ -863,10 +867,10 @@
48502                                                                  *    header
48503                                                                  *
48504                                                                  */
48505 -                                                               
48506 +
48507                                                                 con->http_status = 417;
48508                                                                 con->keep_alive = 0;
48509 -                                                               
48510 +
48511                                                                 array_insert_unique(con->request.headers, (data_unset *)ds);
48512                                                                 return 0;
48513                                                         } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Host")))) {
48514 @@ -875,14 +879,15 @@
48515                                                                 } else {
48516                                                                         con->http_status = 400;
48517                                                                         con->keep_alive = 0;
48518 -                                                                       
48519 +
48520                                                                         if (srv->srvconf.log_request_header_on_error) {
48521 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
48522 +                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
48523                                                                                                 "duplicate Host-header -> 400");
48524                                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48525                                                                                                 "request-header:\n",
48526                                                                                                 con->request.request);
48527                                                                         }
48528 +                                                                       ds->free((data_unset *) ds);
48529                                                                         return 0;
48530                                                                 }
48531                                                         } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) {
48532 @@ -897,14 +902,15 @@
48533                                                                 } else {
48534                                                                         con->http_status = 400;
48535                                                                         con->keep_alive = 0;
48536 -                                                                       
48537 +
48538                                                                         if (srv->srvconf.log_request_header_on_error) {
48539 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
48540 +                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
48541                                                                                                 "duplicate If-Modified-Since header -> 400");
48542                                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48543                                                                                                 "request-header:\n",
48544                                                                                                 con->request.request);
48545                                                                         }
48546 +                                                                       ds->free((data_unset *) ds);
48547                                                                         return 0;
48548                                                                 }
48549                                                         } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-None-Match")))) {
48550 @@ -914,47 +920,49 @@
48551                                                                 } else {
48552                                                                         con->http_status = 400;
48553                                                                         con->keep_alive = 0;
48554 -                                                                       
48555 +
48556                                                                         if (srv->srvconf.log_request_header_on_error) {
48557 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
48558 +                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
48559                                                                                                 "duplicate If-None-Match-header -> 400");
48560                                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48561                                                                                                 "request-header:\n",
48562                                                                                                 con->request.request);
48563                                                                         }
48564 +                                                                       ds->free((data_unset *) ds);
48565                                                                         return 0;
48566                                                                 }
48567                                                         } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Range")))) {
48568                                                                 if (!con->request.http_range) {
48569                                                                         /* bytes=.*-.* */
48570 -                                                               
48571 +
48572                                                                         if (0 == strncasecmp(ds->value->ptr, "bytes=", 6) &&
48573                                                                             NULL != strchr(ds->value->ptr+6, '-')) {
48574 -                                                                               
48575 +
48576                                                                                 /* if dup, only the first one will survive */
48577                                                                                 con->request.http_range = ds->value->ptr + 6;
48578                                                                         }
48579                                                                 } else {
48580                                                                         con->http_status = 400;
48581                                                                         con->keep_alive = 0;
48582 -                                                                       
48583 +
48584                                                                         if (srv->srvconf.log_request_header_on_error) {
48585 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
48586 +                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
48587                                                                                                 "duplicate Range-header -> 400");
48588                                                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48589                                                                                                 "request-header:\n",
48590                                                                                                 con->request.request);
48591                                                                         }
48592 +                                                                       ds->free((data_unset *) ds);
48593                                                                         return 0;
48594                                                                 }
48595                                                         }
48596 -                                                       
48597 +
48598                                                         array_insert_unique(con->request.headers, (data_unset *)ds);
48599                                                 } else {
48600                                                         /* empty header-fields are not allowed by HTTP-RFC, we just ignore them */
48601                                                 }
48602                                         }
48603 -                                       
48604 +
48605                                         i++;
48606                                         first = i+1;
48607                                         is_key = 1;
48608 @@ -963,10 +971,10 @@
48609                                         in_folding = 0;
48610                                 } else {
48611                                         if (srv->srvconf.log_request_header_on_error) {
48612 -                                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
48613 +                                               log_error_write(srv, __FILE__, __LINE__, "sbs",
48614                                                                 "CR without LF", con->request.request, "-> 400");
48615                                         }
48616 -                                       
48617 +
48618                                         con->http_status = 400;
48619                                         con->keep_alive = 0;
48620                                         con->response.keep_alive = 0;
48621 @@ -982,28 +990,28 @@
48622                         }
48623                 }
48624         }
48625 -       
48626 +
48627         con->header_len = i;
48628 -       
48629 +
48630         /* do some post-processing */
48631  
48632         if (con->request.http_version == HTTP_VERSION_1_1) {
48633                 if (keep_alive_set != HTTP_CONNECTION_CLOSE) {
48634                         /* no Connection-Header sent */
48635 -                       
48636 +
48637                         /* HTTP/1.1 -> keep-alive default TRUE */
48638                         con->keep_alive = 1;
48639                 } else {
48640                         con->keep_alive = 0;
48641                 }
48642 -               
48643 +
48644                 /* RFC 2616, 14.23 */
48645                 if (con->request.http_host == NULL ||
48646                     buffer_is_empty(con->request.http_host)) {
48647                         con->http_status = 400;
48648                         con->response.keep_alive = 0;
48649                         con->keep_alive = 0;
48650 -                       
48651 +
48652                         if (srv->srvconf.log_request_header_on_error) {
48653                                 log_error_write(srv, __FILE__, __LINE__, "s", "HTTP/1.1 but Host missing -> 400");
48654                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
48655 @@ -1015,18 +1023,18 @@
48656         } else {
48657                 if (keep_alive_set == HTTP_CONNECTION_KEEPALIVE) {
48658                         /* no Connection-Header sent */
48659 -                       
48660 +
48661                         /* HTTP/1.0 -> keep-alive default FALSE  */
48662                         con->keep_alive = 1;
48663                 } else {
48664                         con->keep_alive = 0;
48665                 }
48666         }
48667 -       
48668 +
48669         /* check hostname field if it is set */
48670         if (NULL != con->request.http_host &&
48671             0 != request_check_hostname(srv, con, con->request.http_host)) {
48672 -               
48673 +
48674                 if (srv->srvconf.log_request_header_on_error) {
48675                         log_error_write(srv, __FILE__, __LINE__, "s",
48676                                         "Invalid Hostname -> 400");
48677 @@ -1038,7 +1046,7 @@
48678                 con->http_status = 400;
48679                 con->response.keep_alive = 0;
48680                 con->keep_alive = 0;
48681 -               
48682 +
48683                 return 0;
48684         }
48685  
48686 @@ -1048,7 +1056,7 @@
48687                 /* content-length is forbidden for those */
48688                 if (con_length_set && con->request.content_length != 0) {
48689                         /* content-length is missing */
48690 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
48691 +                       log_error_write(srv, __FILE__, __LINE__, "s",
48692                                         "GET/HEAD with content-length -> 400");
48693  
48694                         con->keep_alive = 0;
48695 @@ -1060,7 +1068,7 @@
48696                 /* content-length is required for them */
48697                 if (!con_length_set) {
48698                         /* content-length is missing */
48699 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
48700 +                       log_error_write(srv, __FILE__, __LINE__, "s",
48701                                         "POST-request, but content-length missing -> 411");
48702  
48703                         con->keep_alive = 0;
48704 @@ -1073,16 +1081,16 @@
48705                 /* the may have a content-length */
48706                 break;
48707         }
48708 -                       
48709 -       
48710 +
48711 +
48712         /* check if we have read post data */
48713         if (con_length_set) {
48714                 /* don't handle more the SSIZE_MAX bytes in content-length */
48715                 if (con->request.content_length > SSIZE_MAX) {
48716 -                       con->http_status = 413; 
48717 +                       con->http_status = 413;
48718                         con->keep_alive = 0;
48719  
48720 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
48721 +                       log_error_write(srv, __FILE__, __LINE__, "sds",
48722                                         "request-size too long:", con->request.content_length, "-> 413");
48723                         return 0;
48724                 }
48725 @@ -1090,25 +1098,25 @@
48726                 /* divide by 1024 as srvconf.max_request_size is in kBytes */
48727                 if (srv->srvconf.max_request_size != 0 &&
48728                     (con->request.content_length >> 10) > srv->srvconf.max_request_size) {
48729 -                       /* the request body itself is larger then 
48730 +                       /* the request body itself is larger then
48731                          * our our max_request_size
48732                          */
48733 -               
48734 +
48735                         con->http_status = 413;
48736                         con->keep_alive = 0;
48737 -               
48738 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
48739 +
48740 +                       log_error_write(srv, __FILE__, __LINE__, "sds",
48741                                         "request-size too long:", con->request.content_length, "-> 413");
48742                         return 0;
48743                 }
48744 -               
48745 -               
48746 +
48747 +
48748                 /* we have content */
48749                 if (con->request.content_length != 0) {
48750                         return 1;
48751                 }
48752         }
48753 -       
48754 +
48755         return 0;
48756  }
48757  
48758 @@ -1116,9 +1124,9 @@
48759         UNUSED(srv);
48760  
48761         if (con->request.request->used < 5) return 0;
48762 -       
48763 +
48764         if (0 == memcmp(con->request.request->ptr + con->request.request->used - 5, "\r\n\r\n", 4)) return 1;
48765         if (NULL != strstr(con->request.request->ptr, "\r\n\r\n")) return 1;
48766 -       
48767 +
48768         return 0;
48769  }
48770 --- ../lighttpd-1.4.11/src/response.c   2006-03-04 16:41:39.000000000 +0200
48771 +++ lighttpd-1.4.12/src/response.c      2006-07-16 00:26:04.000000000 +0300
48772 @@ -7,7 +7,6 @@
48773  #include <stdlib.h>
48774  #include <string.h>
48775  #include <time.h>
48776 -#include <unistd.h>
48777  #include <ctype.h>
48778  #include <assert.h>
48779  
48780 @@ -24,15 +23,17 @@
48781  #include "plugin.h"
48782  
48783  #include "sys-socket.h"
48784 +#include "sys-files.h"
48785 +#include "sys-strings.h"
48786  
48787  int http_response_write_header(server *srv, connection *con) {
48788         buffer *b;
48789         size_t i;
48790         int have_date = 0;
48791         int have_server = 0;
48792 -       
48793 +
48794         b = chunkqueue_get_prepend_buffer(con->write_queue);
48795 -       
48796 +
48797         if (con->request.http_version == HTTP_VERSION_1_1) {
48798                 BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 ");
48799         } else {
48800 @@ -41,25 +42,26 @@
48801         buffer_append_long(b, con->http_status);
48802         BUFFER_APPEND_STRING_CONST(b, " ");
48803         buffer_append_string(b, get_http_status_name(con->http_status));
48804 -       
48805 +
48806         if (con->request.http_version != HTTP_VERSION_1_1 || con->keep_alive == 0) {
48807                 BUFFER_APPEND_STRING_CONST(b, "\r\nConnection: ");
48808                 buffer_append_string(b, con->keep_alive ? "keep-alive" : "close");
48809         }
48810 -       
48811 +
48812         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
48813                 BUFFER_APPEND_STRING_CONST(b, "\r\nTransfer-Encoding: chunked");
48814         }
48815 -       
48816 -       
48817 +
48818 +
48819         /* add all headers */
48820         for (i = 0; i < con->response.headers->used; i++) {
48821                 data_string *ds;
48822 -               
48823 +
48824                 ds = (data_string *)con->response.headers->data[i];
48825 -               
48826 +
48827                 if (ds->value->used && ds->key->used &&
48828 -                   0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1)) {
48829 +                   0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1) &&
48830 +                   0 != strcasecmp(ds->key->ptr, "X-Sendfile")) {
48831                         if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Date"))) have_date = 1;
48832                         if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Server"))) have_server = 1;
48833  
48834 @@ -68,28 +70,28 @@
48835                         BUFFER_APPEND_STRING_CONST(b, ": ");
48836                         buffer_append_string_buffer(b, ds->value);
48837  #if 0
48838 -                       log_error_write(srv, __FILE__, __LINE__, "bb", 
48839 +                       log_error_write(srv, __FILE__, __LINE__, "bb",
48840                                         ds->key, ds->value);
48841  #endif
48842                 }
48843         }
48844 -       
48845 +
48846         if (!have_date) {
48847                 /* HTTP/1.1 requires a Date: header */
48848                 BUFFER_APPEND_STRING_CONST(b, "\r\nDate: ");
48849 -       
48850 +
48851                 /* cache the generated timestamp */
48852                 if (srv->cur_ts != srv->last_generated_date_ts) {
48853                         buffer_prepare_copy(srv->ts_date_str, 255);
48854 -               
48855 -                       strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1, 
48856 +
48857 +                       strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1,
48858                                  "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(srv->cur_ts)));
48859 -                        
48860 +
48861                         srv->ts_date_str->used = strlen(srv->ts_date_str->ptr) + 1;
48862 -               
48863 +
48864                         srv->last_generated_date_ts = srv->cur_ts;
48865                 }
48866 -       
48867 +
48868                 buffer_append_string_buffer(b, srv->ts_date_str);
48869         }
48870  
48871 @@ -101,16 +103,16 @@
48872                         buffer_append_string_buffer(b, con->conf.server_tag);
48873                 }
48874         }
48875 -       
48876 +
48877         BUFFER_APPEND_STRING_CONST(b, "\r\n\r\n");
48878 -       
48879 -       
48880 +
48881 +
48882         con->bytes_header = b->used - 1;
48883 -       
48884 +
48885         if (con->conf.log_response_header) {
48886                 log_error_write(srv, __FILE__, __LINE__, "sSb", "Response-Header:", "\n", b);
48887         }
48888 -       
48889 +
48890         return 0;
48891  }
48892  
48893 @@ -118,71 +120,71 @@
48894  
48895  handler_t http_response_prepare(server *srv, connection *con) {
48896         handler_t r;
48897 -       
48898 -       /* looks like someone has already done a decision */
48899 -       if (con->mode == DIRECT && 
48900 +
48901 +       /* looks like someone has already made a decision */
48902 +       if (con->mode == DIRECT &&
48903             (con->http_status != 0 && con->http_status != 200)) {
48904                 /* remove a packets in the queue */
48905                 if (con->file_finished == 0) {
48906                         chunkqueue_reset(con->write_queue);
48907                 }
48908 -               
48909 +
48910                 return HANDLER_FINISHED;
48911         }
48912 -       
48913 +
48914         /* no decision yet, build conf->filename */
48915         if (con->mode == DIRECT && con->physical.path->used == 0) {
48916                 char *qstr;
48917  
48918 -               /* we only come here when we have the parse the full request again
48919 -                * 
48920 -                * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a 
48921 +               /* we only come here when we have to parse the full request again
48922 +                *
48923 +                * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a
48924                  * problem here as mod_setenv might get called multiple times
48925                  *
48926                  * fastcgi-auth might lead to a COMEBACK too
48927                  * fastcgi again dead server too
48928                  *
48929                  * mod_compress might add headers twice too
48930 -                * 
48931 +                *
48932                  *  */
48933 -               
48934 +
48935                 if (con->conf.log_condition_handling) {
48936                         log_error_write(srv, __FILE__, __LINE__,  "s",  "run condition");
48937                 }
48938                 config_patch_connection(srv, con, COMP_SERVER_SOCKET); /* SERVERsocket */
48939 -               
48940 +
48941                 /**
48942                  * prepare strings
48943 -                * 
48944 -                * - uri.path_raw 
48945 +                *
48946 +                * - uri.path_raw
48947                  * - uri.path (secure)
48948                  * - uri.query
48949 -                * 
48950 +                *
48951                  */
48952 -               
48953 -               /** 
48954 +
48955 +               /**
48956                  * Name according to RFC 2396
48957 -                * 
48958 +                *
48959                  * - scheme
48960                  * - authority
48961                  * - path
48962                  * - query
48963 -                * 
48964 +                *
48965                  * (scheme)://(authority)(path)?(query)
48966 -                * 
48967 -                * 
48968 +                *
48969 +                *
48970                  */
48971 -       
48972 +
48973                 buffer_copy_string(con->uri.scheme, con->conf.is_ssl ? "https" : "http");
48974                 buffer_copy_string_buffer(con->uri.authority, con->request.http_host);
48975                 buffer_to_lower(con->uri.authority);
48976 -               
48977 +
48978                 config_patch_connection(srv, con, COMP_HTTP_HOST);      /* Host:        */
48979                 config_patch_connection(srv, con, COMP_HTTP_REMOTEIP);  /* Client-IP */
48980                 config_patch_connection(srv, con, COMP_HTTP_REFERER);   /* Referer:     */
48981                 config_patch_connection(srv, con, COMP_HTTP_USERAGENT); /* User-Agent:  */
48982                 config_patch_connection(srv, con, COMP_HTTP_COOKIE);    /* Cookie:  */
48983 -               
48984 +
48985                 /** extract query string from request.uri */
48986                 if (NULL != (qstr = strchr(con->request.uri->ptr, '?'))) {
48987                         buffer_copy_string    (con->uri.query, qstr + 1);
48988 @@ -200,22 +202,22 @@
48989                         log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-path     : ", con->uri.path_raw);
48990                         log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-query    : ", con->uri.query);
48991                 }
48992 -               
48993 +
48994                 /* disable keep-alive if requested */
48995 -               
48996 +
48997                 if (con->request_count > con->conf.max_keep_alive_requests) {
48998                         con->keep_alive = 0;
48999                 }
49000 -               
49001 -               
49002 +
49003 +
49004                 /**
49005 -                *  
49006 -                * call plugins 
49007 -                * 
49008 +                *
49009 +                * call plugins
49010 +                *
49011                  * - based on the raw URL
49012 -                * 
49013 +                *
49014                  */
49015 -               
49016 +
49017                 switch(r = plugins_call_handle_uri_raw(srv, con)) {
49018                 case HANDLER_GO_ON:
49019                         break;
49020 @@ -229,14 +231,14 @@
49021                         break;
49022                 }
49023  
49024 -               /* build filename 
49025 +               /* build filename
49026                  *
49027                  * - decode url-encodings  (e.g. %20 -> ' ')
49028                  * - remove path-modifiers (e.g. /../)
49029                  */
49030 -               
49031 -               
49032 -               
49033 +
49034 +
49035 +
49036                 if (con->request.http_method == HTTP_METHOD_OPTIONS &&
49037                     con->uri.path_raw->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
49038                         /* OPTIONS * ... */
49039 @@ -253,15 +255,20 @@
49040                 }
49041  
49042                 /**
49043 -                *  
49044 -                * call plugins 
49045 -                * 
49046 +                *
49047 +                * call plugins
49048 +                *
49049                  * - based on the clean URL
49050 -                * 
49051 +                *
49052                  */
49053 -               
49054 +
49055                 config_patch_connection(srv, con, COMP_HTTP_URL); /* HTTPurl */
49056 -               
49057 +
49058 +               /* do we have to downgrade to 1.0 ? */
49059 +               if (!con->conf.allow_http11) {
49060 +                       con->request.http_version = HTTP_VERSION_1_0;
49061 +               }
49062 +
49063                 switch(r = plugins_call_handle_uri_clean(srv, con)) {
49064                 case HANDLER_GO_ON:
49065                         break;
49066 @@ -274,11 +281,11 @@
49067                         log_error_write(srv, __FILE__, __LINE__, "");
49068                         break;
49069                 }
49070 -               
49071 +
49072                 if (con->request.http_method == HTTP_METHOD_OPTIONS &&
49073                     con->uri.path->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
49074 -                       /* option requests are handled directly without checking of the path */
49075 -               
49076 +                       /* option requests are handled directly without checking the path */
49077 +
49078                         response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
49079  
49080                         con->http_status = 200;
49081 @@ -288,46 +295,47 @@
49082                 }
49083  
49084                 /***
49085 -                * 
49086 -                * border 
49087 -                * 
49088 +                *
49089 +                * border
49090 +                *
49091                  * logical filename (URI) becomes a physical filename here
49092 -                * 
49093 -                * 
49094 -                * 
49095 +                *
49096 +                *
49097 +                *
49098                  */
49099 -               
49100 -               
49101 -               
49102 -               
49103 +
49104 +
49105 +
49106 +
49107                 /* 1. stat()
49108                  * ... ISREG() -> ok, go on
49109                  * ... ISDIR() -> index-file -> redirect
49110 -                * 
49111 -                * 2. pathinfo() 
49112 +                *
49113 +                * 2. pathinfo()
49114                  * ... ISREG()
49115 -                * 
49116 +                *
49117                  * 3. -> 404
49118 -                * 
49119 +                *
49120                  */
49121 -               
49122 +
49123                 /*
49124                  * SEARCH DOCUMENT ROOT
49125                  */
49126 -               
49127 +
49128                 /* set a default */
49129 -               
49130 +
49131                 buffer_copy_string_buffer(con->physical.doc_root, con->conf.document_root);
49132                 buffer_copy_string_buffer(con->physical.rel_path, con->uri.path);
49133 -               
49134 -#if defined(__WIN32) || defined(__CYGWIN__)
49135 -               /* strip dots from the end and spaces
49136 +
49137 +               filename_unix2local(con->physical.rel_path);
49138 +#if defined(_WIN32) || defined(__CYGWIN__)
49139 +               /* strip dots and spaces from the end
49140                  *
49141                  * windows/dos handle those filenames as the same file
49142                  *
49143                  * foo == foo. == foo..... == "foo...   " == "foo..  ./"
49144                  *
49145 -                * This will affect in some cases PATHINFO
49146 +                * This will affect PATHINFO in some cases
49147                  *
49148                  * on native windows we could prepend the filename with \\?\ to circumvent
49149                  * this behaviour. I have no idea how to push this through cygwin
49150 @@ -377,36 +385,41 @@
49151                         log_error_write(srv, __FILE__, __LINE__, "");
49152                         break;
49153                 }
49154 -               
49155 -               /* MacOS X and Windows can't distiguish between upper and lower-case 
49156 -                * 
49157 -                * convert to lower-case
49158 +
49159 +               /* The default Mac OS X and Windows filesystems can't distiguish between
49160 +                * upper- and lowercase, so convert to lowercase
49161                  */
49162                 if (con->conf.force_lowercase_filenames) {
49163                         buffer_to_lower(con->physical.rel_path);
49164                 }
49165  
49166 -               /* the docroot plugins might set the servername, if they don't we take http-host */
49167 +               /* the docroot plugins might set the servername; if they don't we take http-host */
49168                 if (buffer_is_empty(con->server_name)) {
49169                         buffer_copy_string_buffer(con->server_name, con->uri.authority);
49170                 }
49171 -               
49172 -               /** 
49173 -                * create physical filename 
49174 +
49175 +               /**
49176 +                * create physical filename
49177                  * -> physical.path = docroot + rel_path
49178 -                * 
49179 +                *
49180                  */
49181 -               
49182 +
49183                 buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
49184 -               BUFFER_APPEND_SLASH(con->physical.path);
49185 +               PATHNAME_APPEND_SLASH(con->physical.path);
49186                 buffer_copy_string_buffer(con->physical.basedir, con->physical.path);
49187                 if (con->physical.rel_path->used &&
49188 -                   con->physical.rel_path->ptr[0] == '/') {
49189 +                   con->physical.rel_path->ptr[0] == DIR_SEPERATOR) {
49190                         buffer_append_string_len(con->physical.path, con->physical.rel_path->ptr + 1, con->physical.rel_path->used - 2);
49191                 } else {
49192                         buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
49193                 }
49194  
49195 +        /* win32: directories can't have a trailing slash */
49196 +        if (con->physical.path->ptr[con->physical.path->used - 2] == DIR_SEPERATOR) {
49197 +            con->physical.path->ptr[con->physical.path->used - 2] = '\0';
49198 +            con->physical.path->used--;
49199 +        }
49200 +
49201                 if (con->conf.log_request_handling) {
49202                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- after doc_root");
49203                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
49204 @@ -426,7 +439,7 @@
49205                         log_error_write(srv, __FILE__, __LINE__, "");
49206                         break;
49207                 }
49208 -               
49209 +
49210                 if (con->conf.log_request_handling) {
49211                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- logical -> physical");
49212                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
49213 @@ -434,38 +447,38 @@
49214                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
49215                 }
49216         }
49217 -       
49218 -       /* 
49219 -        * Noone catched away the file from normal path of execution yet (like mod_access)
49220 -        * 
49221 +
49222 +       /*
49223 +        * No one took the file away from the normal path of execution yet (like mod_access)
49224 +        *
49225          * Go on and check of the file exists at all
49226          */
49227 -       
49228 +
49229         if (con->mode == DIRECT) {
49230                 char *slash = NULL;
49231                 char *pathinfo = NULL;
49232                 int found = 0;
49233                 stat_cache_entry *sce = NULL;
49234 -               
49235 +
49236                 if (con->conf.log_request_handling) {
49237                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling physical path");
49238                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
49239                 }
49240 -               
49241 +
49242                 if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
49243                         /* file exists */
49244 -                       
49245 +
49246                         if (con->conf.log_request_handling) {
49247                                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- file found");
49248                                 log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
49249                         }
49250 -                       
49251 +
49252                         if (S_ISDIR(sce->st.st_mode)) {
49253 -                               if (con->physical.path->ptr[con->physical.path->used - 2] != '/') {
49254 +                               if (con->uri.path->ptr[con->uri.path->used - 2] != '/') {
49255                                         /* redirect to .../ */
49256 -                                       
49257 +
49258                                         http_response_redirect_to_directory(srv, con);
49259 -                                       
49260 +
49261                                         return HANDLER_FINISHED;
49262                                 }
49263                         } else if (!S_ISREG(sce->st.st_mode)) {
49264 @@ -477,12 +490,12 @@
49265                         switch (errno) {
49266                         case EACCES:
49267                                 con->http_status = 403;
49268 -       
49269 +
49270                                 if (con->conf.log_request_handling) {
49271                                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- access denied");
49272                                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
49273                                 }
49274 -                       
49275 +
49276                                 buffer_reset(con->physical.path);
49277                                 return HANDLER_FINISHED;
49278                         case ENOENT:
49279 @@ -499,77 +512,77 @@
49280                                 /* PATH_INFO ! :) */
49281                                 break;
49282                         default:
49283 -                               /* we have no idea what happend. let's tell the user so. */
49284 +                               /* we have no idea what happened, so tell the user. */
49285                                 con->http_status = 500;
49286                                 buffer_reset(con->physical.path);
49287 -                               
49288 +
49289                                 log_error_write(srv, __FILE__, __LINE__, "ssbsb",
49290                                                 "file not found ... or so: ", strerror(errno),
49291                                                 con->uri.path,
49292                                                 "->", con->physical.path);
49293 -                               
49294 +
49295                                 return HANDLER_FINISHED;
49296                         }
49297 -                       
49298 +
49299                         /* not found, perhaps PATHINFO */
49300 -                       
49301 +
49302                         buffer_copy_string_buffer(srv->tmp_buf, con->physical.path);
49303 -                       
49304 +
49305                         do {
49306                                 struct stat st;
49307 -                               
49308 +
49309                                 if (slash) {
49310                                         buffer_copy_string_len(con->physical.path, srv->tmp_buf->ptr, slash - srv->tmp_buf->ptr);
49311                                 } else {
49312                                         buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
49313                                 }
49314 -                               
49315 +
49316                                 if (0 == stat(con->physical.path->ptr, &(st)) &&
49317                                     S_ISREG(st.st_mode)) {
49318                                         found = 1;
49319                                         break;
49320                                 }
49321 -                               
49322 +
49323                                 if (pathinfo != NULL) {
49324                                         *pathinfo = '\0';
49325                                 }
49326                                 slash = strrchr(srv->tmp_buf->ptr, '/');
49327 -                               
49328 +
49329                                 if (pathinfo != NULL) {
49330                                         /* restore '/' */
49331                                         *pathinfo = '/';
49332                                 }
49333 -                               
49334 +
49335                                 if (slash) pathinfo = slash;
49336                         } while ((found == 0) && (slash != NULL) && (slash - srv->tmp_buf->ptr > con->physical.basedir->used - 2));
49337 -                       
49338 +
49339                         if (found == 0) {
49340 -                               /* no it really doesn't exists */
49341 +                               /* no, it really doesn't exists */
49342                                 con->http_status = 404;
49343 -                               
49344 +
49345                                 if (con->conf.log_file_not_found) {
49346                                         log_error_write(srv, __FILE__, __LINE__, "sbsb",
49347                                                         "file not found:", con->uri.path,
49348                                                         "->", con->physical.path);
49349                                 }
49350 -                               
49351 +
49352                                 buffer_reset(con->physical.path);
49353 -                               
49354 +
49355                                 return HANDLER_FINISHED;
49356                         }
49357 -                       
49358 +
49359                         /* we have a PATHINFO */
49360                         if (pathinfo) {
49361                                 buffer_copy_string(con->request.pathinfo, pathinfo);
49362 -                               
49363 +
49364                                 /*
49365                                  * shorten uri.path
49366                                  */
49367 -                               
49368 +
49369                                 con->uri.path->used -= strlen(pathinfo);
49370                                 con->uri.path->ptr[con->uri.path->used - 1] = '\0';
49371                         }
49372 -                       
49373 +
49374                         if (con->conf.log_request_handling) {
49375                                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- after pathinfo check");
49376                                 log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
49377 @@ -577,12 +590,12 @@
49378                                 log_error_write(srv, __FILE__, __LINE__,  "sb", "Pathinfo     :", con->request.pathinfo);
49379                         }
49380                 }
49381 -               
49382 +
49383                 if (con->conf.log_request_handling) {
49384                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling subrequest");
49385                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
49386                 }
49387 -               
49388 +
49389                 /* call the handlers */
49390                 switch(r = plugins_call_handle_subrequest_start(srv, con)) {
49391                 case HANDLER_GO_ON:
49392 @@ -593,32 +606,32 @@
49393                         if (con->conf.log_request_handling) {
49394                                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- subrequest finished");
49395                         }
49396 -                       
49397 -                       /* something strange happend */
49398 +
49399 +                       /* something strange happened */
49400                         return r;
49401                 }
49402 -               
49403 -               /* if we are still here, no one wanted the file, status 403 is ok I think */
49404 -               
49405 +
49406 +               /* if we are still here, no one wanted the file; status 403 is ok I think */
49407 +
49408                 if (con->mode == DIRECT) {
49409                         con->http_status = 403;
49410 -                       
49411 +
49412                         return HANDLER_FINISHED;
49413                 }
49414 -               
49415 +
49416         }
49417 -       
49418 +
49419         switch(r = plugins_call_handle_subrequest(srv, con)) {
49420         case HANDLER_GO_ON:
49421 -               /* request was not handled, looks like we are done */
49422 +               /* request was not handled; looks like we are done */
49423                 return HANDLER_FINISHED;
49424         case HANDLER_FINISHED:
49425                 /* request is finished */
49426         default:
49427 -               /* something strange happend */
49428 +               /* something strange happened */
49429                 return r;
49430         }
49431 -       
49432 +
49433         /* can't happen */
49434         return HANDLER_COMEBACK;
49435  }
49436 --- ../lighttpd-1.4.11/src/server.c     2006-03-04 19:12:17.000000000 +0200
49437 +++ lighttpd-1.4.12/src/server.c        2006-07-19 20:02:55.000000000 +0300
49438 @@ -1,11 +1,9 @@
49439  #include <sys/types.h>
49440 -#include <sys/time.h>
49441  #include <sys/stat.h>
49442  
49443  #include <string.h>
49444  #include <errno.h>
49445  #include <fcntl.h>
49446 -#include <unistd.h>
49447  #include <stdlib.h>
49448  #include <time.h>
49449  #include <signal.h>
49450 @@ -29,9 +27,15 @@
49451  #include "plugin.h"
49452  #include "joblist.h"
49453  #include "network_backends.h"
49454 -
49455 +#include "status_counter.h"
49456 +#ifdef _WIN32
49457 +/* use local getopt implementation */
49458 +# undef HAVE_GETOPT_H
49459 +#endif
49460  #ifdef HAVE_GETOPT_H
49461  #include <getopt.h>
49462 +#else
49463 +#include "getopt.h"
49464  #endif
49465  
49466  #ifdef HAVE_VALGRIND_VALGRIND_H
49467 @@ -60,8 +64,17 @@
49468  /* #define USE_ALARM */
49469  #endif
49470  
49471 +#ifdef _WIN32
49472 +#undef HAVE_SIGNAL
49473 +#endif
49474 +
49475 +#include "sys-files.h"
49476 +#include "sys-process.h"
49477 +#include "sys-socket.h"
49478 +
49479  static volatile sig_atomic_t srv_shutdown = 0;
49480  static volatile sig_atomic_t graceful_shutdown = 0;
49481 +static volatile sig_atomic_t graceful_restart = 0;
49482  static volatile sig_atomic_t handle_sig_alarm = 1;
49483  static volatile sig_atomic_t handle_sig_hup = 0;
49484  
49485 @@ -72,9 +85,9 @@
49486  
49487         switch (sig) {
49488         case SIGTERM: srv_shutdown = 1; break;
49489 -       case SIGINT: 
49490 +       case SIGINT:
49491              if (graceful_shutdown) srv_shutdown = 1;
49492 -            else graceful_shutdown = 1; 
49493 +            else graceful_shutdown = 1;
49494  
49495              break;
49496         case SIGALRM: handle_sig_alarm = 1; break;
49497 @@ -86,9 +99,9 @@
49498  static void signal_handler(int sig) {
49499         switch (sig) {
49500         case SIGTERM: srv_shutdown = 1; break;
49501 -       case SIGINT: 
49502 +       case SIGINT:
49503              if (graceful_shutdown) srv_shutdown = 1;
49504 -            else graceful_shutdown = 1; 
49505 +            else graceful_shutdown = 1;
49506  
49507              break;
49508         case SIGALRM: handle_sig_alarm = 1; break;
49509 @@ -110,35 +123,35 @@
49510         signal(SIGTSTP, SIG_IGN);
49511  #endif
49512         if (0 != fork()) exit(0);
49513 -       
49514 +
49515         if (-1 == setsid()) exit(0);
49516  
49517         signal(SIGHUP, SIG_IGN);
49518  
49519         if (0 != fork()) exit(0);
49520 -       
49521 +
49522         if (0 != chdir("/")) exit(0);
49523  }
49524  #endif
49525  
49526  static server *server_init(void) {
49527         int i;
49528 -       
49529 +
49530         server *srv = calloc(1, sizeof(*srv));
49531         assert(srv);
49532 +    srv->max_fds = 1024;
49533  #define CLEAN(x) \
49534         srv->x = buffer_init();
49535 -       
49536 +
49537         CLEAN(response_header);
49538         CLEAN(parse_full_path);
49539         CLEAN(ts_debug_str);
49540         CLEAN(ts_date_str);
49541 -       CLEAN(errorlog_buf);
49542         CLEAN(response_range);
49543         CLEAN(tmp_buf);
49544         srv->empty_string = buffer_init_string("");
49545         CLEAN(cond_check_buf);
49546 -       
49547 +
49548         CLEAN(srvconf.errorlog_file);
49549         CLEAN(srvconf.groupname);
49550         CLEAN(srvconf.username);
49551 @@ -146,68 +159,62 @@
49552         CLEAN(srvconf.bindhost);
49553         CLEAN(srvconf.event_handler);
49554         CLEAN(srvconf.pid_file);
49555 -       
49556 +
49557         CLEAN(tmp_chunk_len);
49558  #undef CLEAN
49559 -       
49560 +
49561  #define CLEAN(x) \
49562         srv->x = array_init();
49563 -       
49564 +
49565         CLEAN(config_context);
49566         CLEAN(config_touched);
49567 -       CLEAN(status);
49568  #undef CLEAN
49569 -       
49570 +
49571         for (i = 0; i < FILE_CACHE_MAX; i++) {
49572                 srv->mtime_cache[i].str = buffer_init();
49573         }
49574 -       
49575 +
49576         srv->cur_ts = time(NULL);
49577         srv->startup_ts = srv->cur_ts;
49578 -       
49579 +
49580         srv->conns = calloc(1, sizeof(*srv->conns));
49581         assert(srv->conns);
49582 -       
49583 +
49584         srv->joblist = calloc(1, sizeof(*srv->joblist));
49585         assert(srv->joblist);
49586 -       
49587 +
49588         srv->fdwaitqueue = calloc(1, sizeof(*srv->fdwaitqueue));
49589         assert(srv->fdwaitqueue);
49590 -       
49591 +
49592         srv->srvconf.modules = array_init();
49593         srv->srvconf.modules_dir = buffer_init_string(LIBRARY_DIR);
49594         srv->srvconf.network_backend = buffer_init();
49595         srv->srvconf.upload_tempdirs = array_init();
49596 -       
49597 -       /* use syslog */
49598 -       srv->errorlog_fd = -1;
49599 -       srv->errorlog_mode = ERRORLOG_STDERR;
49600  
49601         srv->split_vals = array_init();
49602 -       
49603 +
49604         return srv;
49605  }
49606  
49607  static void server_free(server *srv) {
49608         size_t i;
49609 -       
49610 +
49611         for (i = 0; i < FILE_CACHE_MAX; i++) {
49612                 buffer_free(srv->mtime_cache[i].str);
49613         }
49614 -       
49615 +
49616  #define CLEAN(x) \
49617         buffer_free(srv->x);
49618 -       
49619 +
49620         CLEAN(response_header);
49621         CLEAN(parse_full_path);
49622         CLEAN(ts_debug_str);
49623         CLEAN(ts_date_str);
49624 -       CLEAN(errorlog_buf);
49625         CLEAN(response_range);
49626         CLEAN(tmp_buf);
49627         CLEAN(empty_string);
49628         CLEAN(cond_check_buf);
49629 -       
49630 +
49631         CLEAN(srvconf.errorlog_file);
49632         CLEAN(srvconf.groupname);
49633         CLEAN(srvconf.username);
49634 @@ -217,7 +224,7 @@
49635         CLEAN(srvconf.pid_file);
49636         CLEAN(srvconf.modules_dir);
49637         CLEAN(srvconf.network_backend);
49638 -       
49639 +
49640         CLEAN(tmp_chunk_len);
49641  #undef CLEAN
49642  
49643 @@ -225,15 +232,15 @@
49644         fdevent_unregister(srv->ev, srv->fd);
49645  #endif
49646         fdevent_free(srv->ev);
49647 -       
49648 +
49649         free(srv->conns);
49650 -       
49651 +
49652         if (srv->config_storage) {
49653                 for (i = 0; i < srv->config_context->used; i++) {
49654                         specific_config *s = srv->config_storage[i];
49655  
49656                         if (!s) continue;
49657 -                       
49658 +
49659                         buffer_free(s->document_root);
49660                         buffer_free(s->server_name);
49661                         buffer_free(s->server_tag);
49662 @@ -242,32 +249,31 @@
49663                         buffer_free(s->error_handler);
49664                         buffer_free(s->errorfile_prefix);
49665                         array_free(s->mimetypes);
49666 -                       
49667 +
49668                         free(s);
49669                 }
49670                 free(srv->config_storage);
49671                 srv->config_storage = NULL;
49672         }
49673 -       
49674 +
49675  #define CLEAN(x) \
49676         array_free(srv->x);
49677 -       
49678 +
49679         CLEAN(config_context);
49680         CLEAN(config_touched);
49681 -       CLEAN(status);
49682         CLEAN(srvconf.upload_tempdirs);
49683  #undef CLEAN
49684 -       
49685 +
49686         joblist_free(srv, srv->joblist);
49687         fdwaitqueue_free(srv, srv->fdwaitqueue);
49688 -       
49689 +
49690         if (srv->stat_cache) {
49691                 stat_cache_free(srv->stat_cache);
49692         }
49693  
49694         array_free(srv->srvconf.modules);
49695         array_free(srv->split_vals);
49696 -       
49697 +
49698         free(srv);
49699  }
49700  
49701 @@ -281,14 +287,12 @@
49702  " - a light and fast webserver\n" \
49703  "Build-Date: " __DATE__ " " __TIME__ "\n";
49704  ;
49705 -#undef TEXT_SSL        
49706 +#undef TEXT_SSL
49707         write(STDOUT_FILENO, b, strlen(b));
49708  }
49709  
49710  static void show_features (void) {
49711 -  show_version();
49712 -  printf("\nEvent Handlers:\n\n%s",
49713 -
49714 +  const char *s = ""
49715  #ifdef USE_SELECT
49716        "\t+ select (generic)\n"
49717  #else
49718 @@ -355,11 +359,6 @@
49719  #else
49720        "\t- crypt support\n"
49721  #endif
49722 -#ifdef USE_PAM
49723 -      "\t+ PAM support\n"
49724 -#else
49725 -      "\t- PAM support\n"
49726 -#endif
49727  #ifdef USE_OPENSSL
49728        "\t+ SSL Support\n"
49729  #else
49730 @@ -371,9 +370,9 @@
49731        "\t- PCRE support\n"
49732  #endif
49733  #ifdef HAVE_MYSQL
49734 -      "\t+ mySQL support\n"
49735 +      "\t+ MySQL support\n"
49736  #else
49737 -      "\t- mySQL support\n"
49738 +      "\t- MySQL support\n"
49739  #endif
49740  #if defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER)
49741        "\t+ LDAP support\n"
49742 @@ -410,8 +409,11 @@
49743  #else
49744        "\t- GDBM support\n"
49745  #endif
49746 -      "\n"
49747 -      );
49748 +      "\n";
49749 +
49750 +  show_version();
49751 +
49752 +  printf("\nEvent Handlers:\n\n%s", s);
49753  }
49754  
49755  static void show_help (void) {
49756 @@ -433,197 +435,565 @@
49757  " -h         show this help\n" \
49758  "\n"
49759  ;
49760 -#undef TEXT_SSL        
49761 +#undef TEXT_SSL
49762  #undef TEXT_IPV6
49763         write(STDOUT_FILENO, b, strlen(b));
49764  }
49765  
49766 -int main (int argc, char **argv) {
49767 -       server *srv = NULL;
49768 -       int print_config = 0;
49769 -       int test_config = 0;
49770 -       int i_am_root;
49771 -       int o;
49772 -       int num_childs = 0;
49773 -       int pid_fd = -1, fd;
49774 -       size_t i;
49775 -#ifdef HAVE_SIGACTION
49776 -       struct sigaction act;
49777 -#endif
49778 -#ifdef HAVE_GETRLIMIT
49779 -       struct rlimit rlim;
49780 -#endif
49781 -       
49782 -#ifdef USE_ALARM
49783 -       struct itimerval interval;
49784 -       
49785 -       interval.it_interval.tv_sec = 1;
49786 -       interval.it_interval.tv_usec = 0;
49787 -       interval.it_value.tv_sec = 1;
49788 -       interval.it_value.tv_usec = 0;
49789 -#endif
49790 -       
49791 -       
49792 -       /* for nice %b handling in strfime() */
49793 -       setlocale(LC_TIME, "C");
49794 -       
49795 -       if (NULL == (srv = server_init())) {
49796 -               fprintf(stderr, "did this really happen?\n");
49797 -               return -1;
49798 -       }
49799 -       
49800 -       /* init structs done */
49801 -       
49802 -       srv->srvconf.port = 0;
49803 -#ifdef HAVE_GETUID
49804 -       i_am_root = (getuid() == 0);
49805 -#else
49806 -       i_am_root = 0;
49807 -#endif
49808 -       srv->srvconf.dont_daemonize = 0;
49809 -       
49810 -       while(-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) {
49811 -               switch(o) {
49812 -               case 'f': 
49813 -                       if (config_read(srv, optarg)) { 
49814 -                               server_free(srv);
49815 -                               return -1;
49816 -                       }
49817 -                       break;
49818 -               case 'm':
49819 -                       buffer_copy_string(srv->srvconf.modules_dir, optarg);
49820 -                       break;
49821 -               case 'p': print_config = 1; break;
49822 -               case 't': test_config = 1; break;
49823 -               case 'D': srv->srvconf.dont_daemonize = 1; break;
49824 -               case 'v': show_version(); return 0;
49825 -               case 'V': show_features(); return 0;          
49826 -               case 'h': show_help(); return 0;
49827 -               default: 
49828 -                       show_help();
49829 -                       server_free(srv);
49830 -                       return -1;
49831 -               }
49832 -       }
49833 -       
49834 -       if (!srv->config_storage) {
49835 -               log_error_write(srv, __FILE__, __LINE__, "s",
49836 -                               "No configuration available. Try using -f option.");
49837 -               
49838 -               server_free(srv);
49839 -               return -1;
49840 -       }
49841 -       
49842 -       if (print_config) {
49843 -               data_unset *dc = srv->config_context->data[0];
49844 -               if (dc) {
49845 -                       dc->print(dc, 0);
49846 -                       fprintf(stderr, "\n");
49847 -               } else {
49848 -                       /* shouldn't happend */
49849 -                       fprintf(stderr, "global config not found\n");
49850 -               }
49851 -       }
49852 +int lighty_mainloop(server *srv) {
49853 +       fdevent_revents *revents = fdevent_revents_init();
49854  
49855 -       if (test_config) {
49856 -               printf("Syntax OK\n");
49857 -       }
49858 +       /* main-loop */
49859 +       while (!srv_shutdown) {
49860 +               int n;
49861 +               size_t ndx;
49862 +               time_t min_ts;
49863  
49864 -       if (test_config || print_config) {
49865 -               server_free(srv);
49866 -               return 0;
49867 -       }
49868 -       
49869 -       /* close stdin and stdout, as they are not needed */
49870 -       /* move stdin to /dev/null */
49871 -       if (-1 != (fd = open("/dev/null", O_RDONLY))) {
49872 -               close(STDIN_FILENO);
49873 -               dup2(fd, STDIN_FILENO);
49874 -               close(fd);
49875 -       }
49876 -       
49877 -       /* move stdout to /dev/null */
49878 -       if (-1 != (fd = open("/dev/null", O_WRONLY))) {
49879 -               close(STDOUT_FILENO);
49880 -               dup2(fd, STDOUT_FILENO);
49881 -               close(fd);
49882 -       }
49883 -       
49884 -       if (0 != config_set_defaults(srv)) {
49885 -               log_error_write(srv, __FILE__, __LINE__, "s", 
49886 -                               "setting default values failed");
49887 -               server_free(srv);
49888 -               return -1;
49889 -       }
49890 -       
49891 -       /* UID handling */
49892 -#ifdef HAVE_GETUID
49893 -       if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
49894 -               /* we are setuid-root */
49895 -               
49896 -               log_error_write(srv, __FILE__, __LINE__, "s", 
49897 -                               "Are you nuts ? Don't apply a SUID bit to this binary");
49898 -               
49899 -               server_free(srv);
49900 -               return -1;
49901 -       }
49902 -#endif
49903 -       
49904 -       /* check document-root */
49905 -       if (srv->config_storage[0]->document_root->used <= 1) {
49906 -               log_error_write(srv, __FILE__, __LINE__, "s", 
49907 -                               "document-root is not set\n");
49908 -               
49909 -               server_free(srv);
49910 -               
49911 -               return -1;
49912 -       }
49913 -       
49914 -       if (plugins_load(srv)) {
49915 -               log_error_write(srv, __FILE__, __LINE__, "s",
49916 -                               "loading plugins finally failed");
49917 -               
49918 -               plugins_free(srv);
49919 -               server_free(srv);
49920 -               
49921 -               return -1;
49922 -       }
49923 -       
49924 -       /* open pid file BEFORE chroot */
49925 -       if (srv->srvconf.pid_file->used) {
49926 -               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))) {
49927 -                       struct stat st;
49928 -                       if (errno != EEXIST) {
49929 -                               log_error_write(srv, __FILE__, __LINE__, "sbs",
49930 -                                       "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49931 -                               return -1;
49932 -                       }
49933 -                       
49934 -                       if (0 != stat(srv->srvconf.pid_file->ptr, &st)) {
49935 -                               log_error_write(srv, __FILE__, __LINE__, "sbs",
49936 -                                               "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49937 +               if (handle_sig_hup) {
49938 +                       handler_t r;
49939 +
49940 +                       /* reset notification */
49941 +                       handle_sig_hup = 0;
49942 +
49943 +#if 0
49944 +                               pid_t pid;
49945 +
49946 +                       /* send the old process into a graceful-shutdown and start a
49947 +                        * new process right away
49948 +                        *
49949 +                        * BUGS:
49950 +                        * - if webserver is running on port < 1024 (e.g. 80, 433)
49951 +                        *   we don't have the permissions to bind to that port anymore
49952 +                        *
49953 +                        *
49954 +                        *  */
49955 +                       if (0 == (pid = fork())) {
49956 +                               execve(argv[0], argv, envp);
49957 +
49958 +                               exit(-1);
49959 +                       } else if (pid == -1) {
49960 +
49961 +                       } else {
49962 +                               /* parent */
49963 +
49964 +                               graceful_shutdown = 1; /* shutdown without killing running connections */
49965 +                               graceful_restart = 1;  /* don't delete pid file */
49966                         }
49967 -                       
49968 -                       if (!S_ISREG(st.st_mode)) {
49969 -                               log_error_write(srv, __FILE__, __LINE__, "sb",
49970 -                                               "pid-file exists and isn't regular file:", srv->srvconf.pid_file);
49971 -                               return -1;
49972 +#else
49973 +                       /* cycle logfiles */
49974 +
49975 +                       switch(r = plugins_call_handle_sighup(srv)) {
49976 +                       case HANDLER_GO_ON:
49977 +                               break;
49978 +                       default:
49979 +                               log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r);
49980 +                               break;
49981                         }
49982 -                       
49983 -                       if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
49984 -                               log_error_write(srv, __FILE__, __LINE__, "sbs",
49985 -                                               "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49986 +
49987 +                       if (-1 == log_error_cycle()) {
49988 +                               log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying");
49989 +
49990                                 return -1;
49991                         }
49992 +#endif
49993                 }
49994 -       }
49995  
49996 -       if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
49997 -               /* select limits itself
49998 +               if (handle_sig_alarm) {
49999 +                       /* a new second */
50000 +
50001 +#ifdef USE_ALARM
50002 +                       /* reset notification */
50003 +                       handle_sig_alarm = 0;
50004 +#endif
50005 +
50006 +                       /* get current time */
50007 +                       min_ts = time(NULL);
50008 +
50009 +                       if (min_ts != srv->cur_ts) {
50010 +                               int cs = 0;
50011 +                               connections *conns = srv->conns;
50012 +                               handler_t r;
50013 +
50014 +                               switch(r = plugins_call_handle_trigger(srv)) {
50015 +                               case HANDLER_GO_ON:
50016 +                                       break;
50017 +                               case HANDLER_ERROR:
50018 +                                       log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed");
50019 +                                       break;
50020 +                               default:
50021 +                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
50022 +                                       break;
50023 +                               }
50024 +
50025 +                               /* trigger waitpid */
50026 +                               srv->cur_ts = min_ts;
50027 +
50028 +                               /* cleanup stat-cache */
50029 +                               stat_cache_trigger_cleanup(srv);
50030 +                               /**
50031 +                                * check all connections for timeouts
50032 +                                *
50033 +                                */
50034 +                               for (ndx = 0; ndx < conns->used; ndx++) {
50035 +                                       int changed = 0;
50036 +                                       connection *con;
50037 +                                       int t_diff;
50038 +
50039 +                                       con = conns->ptr[ndx];
50040 +
50041 +                                       if (con->state == CON_STATE_READ ||
50042 +                                           con->state == CON_STATE_READ_POST) {
50043 +                                               if (con->request_count == 1) {
50044 +                                                       if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
50045 +                                                               /* time - out */
50046 +#if 0
50047 +                                                               log_error_write(srv, __FILE__, __LINE__, "sd",
50048 +                                                                               "connection closed - read-timeout:", con->fd);
50049 +#endif
50050 +                                                               connection_set_state(srv, con, CON_STATE_ERROR);
50051 +                                                               changed = 1;
50052 +                                                       }
50053 +                                               } else {
50054 +                                                       if (srv->cur_ts - con->read_idle_ts > con->conf.max_keep_alive_idle) {
50055 +                                                               /* time - out */
50056 +#if 0
50057 +                                                               log_error_write(srv, __FILE__, __LINE__, "sd",
50058 +                                                                               "connection closed - read-timeout:", con->fd);
50059 +#endif
50060 +                                                               connection_set_state(srv, con, CON_STATE_ERROR);
50061 +                                                               changed = 1;
50062 +                                                       }
50063 +                                               }
50064 +                                       }
50065 +
50066 +                                       if ((con->state == CON_STATE_WRITE) &&
50067 +                                           (con->write_request_ts != 0)) {
50068 +#if 0
50069 +                                               if (srv->cur_ts - con->write_request_ts > 60) {
50070 +                                                       log_error_write(srv, __FILE__, __LINE__, "sdd",
50071 +                                                                       "connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts);
50072 +                                               }
50073 +#endif
50074 +
50075 +                                               if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) {
50076 +                                                       /* time - out */
50077 +#if 1
50078 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbsosds",
50079 +                                                                       "NOTE: a request for",
50080 +                                                                       con->request.uri,
50081 +                                                                       "timed out after writing",
50082 +                                                                       con->bytes_written,
50083 +                                                                       "bytes. We waited",
50084 +                                                                       (int)con->conf.max_write_idle,
50085 +                                                                       "seconds. If this a problem increase server.max-write-idle");
50086 +#endif
50087 +                                                       connection_set_state(srv, con, CON_STATE_ERROR);
50088 +                                                       changed = 1;
50089 +                                               }
50090 +                                       }
50091 +                                       /* we don't like div by zero */
50092 +                                       if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1;
50093 +
50094 +                                       if (con->traffic_limit_reached &&
50095 +                                           (con->conf.kbytes_per_second == 0 ||
50096 +                                            ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) {
50097 +                                               /* enable connection again */
50098 +                                               con->traffic_limit_reached = 0;
50099 +
50100 +                                               changed = 1;
50101 +                                       }
50102 +
50103 +                                       if (changed) {
50104 +                                               connection_state_machine(srv, con);
50105 +                                       }
50106 +                                       con->bytes_written_cur_second = 0;
50107 +                                       *(con->conf.global_bytes_per_second_cnt_ptr) = 0;
50108 +
50109 +#if 0
50110 +                                       if (cs == 0) {
50111 +                                               fprintf(stderr, "connection-state: ");
50112 +                                               cs = 1;
50113 +                                       }
50114 +
50115 +                                       fprintf(stderr, "c[%d,%d]: %s ",
50116 +                                               con->fd,
50117 +                                               con->fcgi.fd,
50118 +                                               connection_get_state(con->state));
50119 +#endif
50120 +                               }
50121 +
50122 +                               if (cs == 1) fprintf(stderr, "\n");
50123 +                       }
50124 +               }
50125 +
50126 +               if (srv->sockets_disabled) {
50127 +                       /* our server sockets are disabled, why ? */
50128 +
50129 +                       if ((srv->cur_fds + srv->want_fds < srv->max_fds * 0.8) && /* we have enough unused fds */
50130 +                           (srv->conns->used < srv->max_conns * 0.9) &&
50131 +                           (0 == graceful_shutdown)) {
50132 +                               size_t i;
50133 +
50134 +                               for (i = 0; i < srv->srv_sockets.used; i++) {
50135 +                                       server_socket *srv_socket = srv->srv_sockets.ptr[i];
50136 +                                       fdevent_event_add(srv->ev, srv_socket->sock, FDEVENT_IN);
50137 +                               }
50138 +
50139 +                               log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again");
50140 +
50141 +                               srv->sockets_disabled = 0;
50142 +                       }
50143 +               } else {
50144 +                       if ((srv->cur_fds + srv->want_fds > srv->max_fds * 0.9) || /* out of fds */
50145 +                           (srv->conns->used > srv->max_conns) || /* out of connections */
50146 +                           (graceful_shutdown)) { /* graceful_shutdown */
50147 +                               size_t i;
50148 +
50149 +                               /* disable server-fds */
50150 +
50151 +                               for (i = 0; i < srv->srv_sockets.used; i++) {
50152 +                                       server_socket *srv_socket = srv->srv_sockets.ptr[i];
50153 +                                       fdevent_event_del(srv->ev, srv_socket->sock);
50154 +
50155 +                                       if (graceful_shutdown) {
50156 +                                               /* we don't want this socket anymore,
50157 +                                                *
50158 +                                                * closing it right away will make it possible for
50159 +                                                * the next lighttpd to take over (graceful restart)
50160 +                                                *  */
50161 +
50162 +                                               fdevent_unregister(srv->ev, srv_socket->sock);
50163 +                                               closesocket(srv_socket->sock->fd);
50164 +                                               srv_socket->sock->fd = -1;
50165 +
50166 +                                               /* network_close() will cleanup after us */
50167 +                                       }
50168 +                               }
50169 +
50170 +                               if (graceful_shutdown) {
50171 +                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started");
50172 +                               } else if (srv->conns->used > srv->max_conns) {
50173 +                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached");
50174 +                               } else {
50175 +                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds");
50176 +                               }
50177 +
50178 +                               srv->sockets_disabled = 1;
50179 +                       }
50180 +               }
50181 +
50182 +               if (graceful_shutdown && srv->conns->used == 0) {
50183 +                       /* we are in graceful shutdown phase and all connections are closed
50184 +                        * we are ready to terminate without harming anyone */
50185 +                       srv_shutdown = 1;
50186 +               }
50187 +
50188 +               /* we still have some fds to share */
50189 +               if (srv->want_fds) {
50190 +                       /* check the fdwaitqueue for waiting fds */
50191 +                       int free_fds = srv->max_fds - srv->cur_fds - 16;
50192 +                       connection *con;
50193 +
50194 +                       for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) {
50195 +                               connection_state_machine(srv, con);
50196 +
50197 +                               srv->want_fds--;
50198 +                       }
50199 +               }
50200 +
50201 +               if ((n = fdevent_poll(srv->ev, 1000)) > 0) {
50202 +                       /* n is the number of events */
50203 +                       size_t i;
50204 +                       fdevent_get_revents(srv->ev, n, revents);
50205 +
50206 +                       /* handle client connections first
50207 +                        * 
50208 +                        * this is a bit of a hack, but we have to make sure than we handle 
50209 +                        * close-events before the connection is reused for a keep-alive 
50210 +                        * request
50211 +                        *
50212 +                        * this is mostly an issue for mod_proxy_core, but you never know
50213 +                        *
50214 +                        */
50215 +
50216 +                       for (i = 0; i < revents->used; i++) {
50217 +                               fdevent_revent *revent = revents->ptr[i];
50218 +                               handler_t r;
50219 +
50220 +                               /* skip server-fds */
50221 +                               if (revent->handler == network_server_handle_fdevent) continue;
50222 +
50223 +                               switch (r = (*(revent->handler))(srv, revent->context, revent->revents)) {
50224 +                               case HANDLER_FINISHED:
50225 +                               case HANDLER_GO_ON:
50226 +                               case HANDLER_WAIT_FOR_EVENT:
50227 +                               case HANDLER_WAIT_FOR_FD:
50228 +                                       break;
50229 +                               case HANDLER_ERROR:
50230 +                                       /* should never happen */
50231 +                                       SEGFAULT();
50232 +                                       break;
50233 +                               default:
50234 +                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
50235 +                                       break;
50236 +                               }
50237 +                       } 
50238 +
50239 +                       for (i = 0; i < revents->used; i++) {
50240 +                               fdevent_revent *revent = revents->ptr[i];
50241 +                               handler_t r;
50242 +
50243 +                               /* server fds only */
50244 +                               if (revent->handler != network_server_handle_fdevent) continue;
50245 +
50246 +                               switch (r = (*(revent->handler))(srv, revent->context, revent->revents)) {
50247 +                               case HANDLER_FINISHED:
50248 +                               case HANDLER_GO_ON:
50249 +                               case HANDLER_WAIT_FOR_EVENT:
50250 +                               case HANDLER_WAIT_FOR_FD:
50251 +                                       break;
50252 +                               case HANDLER_ERROR:
50253 +                                       /* should never happen */
50254 +                                       SEGFAULT();
50255 +                                       break;
50256 +                               default:
50257 +                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
50258 +                                       break;
50259 +                               }
50260 +                       } 
50261 +
50262 +               } else if (n < 0 && errno != EINTR) {
50263 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
50264 +                                       "fdevent_poll failed:",
50265 +                                       strerror(errno));
50266 +               }
50267 +
50268 +               for (ndx = 0; ndx < srv->joblist->used; ndx++) {
50269 +                       connection *con = srv->joblist->ptr[ndx];
50270 +                       handler_t r;
50271 +
50272 +                       connection_state_machine(srv, con);
50273 +
50274 +                       switch(r = plugins_call_handle_joblist(srv, con)) {
50275 +                       case HANDLER_FINISHED:
50276 +                       case HANDLER_GO_ON:
50277 +                               break;
50278 +                       default:
50279 +                               log_error_write(srv, __FILE__, __LINE__, "d", r);
50280 +                               break;
50281 +                       }
50282 +
50283 +                       con->in_joblist = 0;
50284 +               }
50285 +
50286 +               srv->joblist->used = 0;
50287 +       }
50288 +
50289 +       fdevent_revents_free(revents);
50290 +
50291 +       return 0;
50292 +}
50293 +
50294 +
50295 +int main (int argc, char **argv, char **envp) {
50296 +       server *srv = NULL;
50297 +       int print_config = 0;
50298 +       int test_config = 0;
50299 +       int i_am_root;
50300 +       int o;
50301 +       int num_childs = 0;
50302 +       int pid_fd = -1, fd;
50303 +       size_t i;
50304 +#ifdef _WIN32
50305 +       char *optarg = NULL;
50306 +#endif
50307 +
50308 +#ifdef HAVE_SIGACTION
50309 +       struct sigaction act;
50310 +#endif
50311 +#ifdef HAVE_GETRLIMIT
50312 +       struct rlimit rlim;
50313 +#endif
50314 +
50315 +#ifdef USE_ALARM
50316 +       struct itimerval interval;
50317 +
50318 +       interval.it_interval.tv_sec = 1;
50319 +       interval.it_interval.tv_usec = 0;
50320 +       interval.it_value.tv_sec = 1;
50321 +       interval.it_value.tv_usec = 0;
50322 +#endif
50323 +
50324 +       log_init();
50325 +       status_counter_init();
50326 +
50327 +       /* for nice %b handling in strfime() */
50328 +       setlocale(LC_TIME, "C");
50329 +       
50330 +       if (NULL == (srv = server_init())) {
50331 +               fprintf(stderr, "did this really happen?\n");
50332 +               return -1;
50333 +       }
50334 +
50335 +       /* init structs done */
50336 +
50337 +       srv->srvconf.port = 0;
50338 +#ifdef HAVE_GETUID
50339 +       i_am_root = (getuid() == 0);
50340 +#else
50341 +       i_am_root = 0;
50342 +#endif
50343 +       srv->srvconf.dont_daemonize = 0;
50344 +
50345 +       while(-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) {
50346 +               switch(o) {
50347 +               case 'f':
50348 +#ifdef _WIN32
50349 +                       /* evil HACK for windows, optarg is not set */
50350 +                       optarg = argv[optind-1];
50351 +#endif
50352 +                       if (config_read(srv, optarg)) {
50353 +                               server_free(srv);
50354 +                               return -1;
50355 +                       }
50356 +
50357 +                       break;
50358 +               case 'm':
50359 +                       buffer_copy_string(srv->srvconf.modules_dir, optarg);
50360 +                       break;
50361 +               case 'p': print_config = 1; break;
50362 +               case 't': test_config = 1; break;
50363 +               case 'D': srv->srvconf.dont_daemonize = 1; break;
50364 +               case 'v': show_version(); return 0;
50365 +               case 'V': show_features(); return 0;
50366 +               case 'h': show_help(); return 0;
50367 +               default:
50368 +                       show_help();
50369 +                       server_free(srv);
50370 +                       return -1;
50371 +               }
50372 +       }
50373 +
50374 +       if (!srv->config_storage) {
50375 +               log_error_write(srv, __FILE__, __LINE__, "s",
50376 +                               "No configuration available. Try using -f option.");
50377 +
50378 +               server_free(srv);
50379 +               return -1;
50380 +       }
50381 +
50382 +       if (print_config) {
50383 +               data_unset *dc = srv->config_context->data[0];
50384 +               if (dc) {
50385 +                       dc->print(dc, 0);
50386 +                       fprintf(stderr, "\n");
50387 +               } else {
50388 +                       /* shouldn't happend */
50389 +                       fprintf(stderr, "global config not found\n");
50390 +               }
50391 +       }
50392 +
50393 +       if (test_config) {
50394 +               printf("Syntax OK\n");
50395 +       }
50396 +
50397 +       if (test_config || print_config) {
50398 +               server_free(srv);
50399 +               return 0;
50400 +       }
50401 +
50402 +       /* close stdin and stdout, as they are not needed */
50403 +       /* move stdin to /dev/null */
50404 +       if (-1 != (fd = open("/dev/null", O_RDONLY))) {
50405 +               close(STDIN_FILENO);
50406 +               dup2(fd, STDIN_FILENO);
50407 +               close(fd);
50408 +       }
50409 +
50410 +       /* move stdout to /dev/null */
50411 +       if (-1 != (fd = open("/dev/null", O_WRONLY))) {
50412 +               close(STDOUT_FILENO);
50413 +               dup2(fd, STDOUT_FILENO);
50414 +               close(fd);
50415 +       }
50416 +
50417 +       if (0 != config_set_defaults(srv)) {
50418 +               log_error_write(srv, __FILE__, __LINE__, "s",
50419 +                               "setting default values failed");
50420 +               server_free(srv);
50421 +               return -1;
50422 +       }
50423 +
50424 +       /* UID handling */
50425 +#ifdef HAVE_GETUID
50426 +       if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
50427 +               /* we are setuid-root */
50428 +
50429 +               log_error_write(srv, __FILE__, __LINE__, "s",
50430 +                               "Are you nuts ? Don't apply a SUID bit to this binary");
50431 +
50432 +               server_free(srv);
50433 +               return -1;
50434 +       }
50435 +#endif
50436 +
50437 +       /* check document-root */
50438 +       if (srv->config_storage[0]->document_root->used <= 1) {
50439 +               log_error_write(srv, __FILE__, __LINE__, "s",
50440 +                               "document-root is not set\n");
50441 +
50442 +               server_free(srv);
50443 +
50444 +               return -1;
50445 +       }
50446 +
50447 +       if (plugins_load(srv)) {
50448 +               log_error_write(srv, __FILE__, __LINE__, "s",
50449 +                               "loading plugins finally failed");
50450 +
50451 +               plugins_free(srv);
50452 +               server_free(srv);
50453 +
50454 +               return -1;
50455 +       }
50456 +
50457 +#ifndef _WIN32
50458 +       /* open pid file BEFORE chroot */
50459 +       if (srv->srvconf.pid_file->used) {
50460 +               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))) {
50461 +                       struct stat st;
50462 +                       if (errno != EEXIST) {
50463 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
50464 +                                       "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
50465 +                               return -1;
50466 +                       }
50467 +
50468 +                       if (0 != stat(srv->srvconf.pid_file->ptr, &st)) {
50469 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
50470 +                                               "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno));
50471 +                       }
50472 +
50473 +                       if (!S_ISREG(st.st_mode)) {
50474 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
50475 +                                               "pid-file exists and isn't regular file:", srv->srvconf.pid_file);
50476 +                               return -1;
50477 +                       }
50478 +
50479 +                       if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
50480 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
50481 +                                               "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
50482 +                               return -1;
50483 +                       }
50484 +               }
50485 +       }
50486 +#endif
50487 +       if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50488 +               /* select limits itself
50489                  *
50490                  * as it is a hard limit and will lead to a segfault we add some safety
50491                  * */
50492 -               srv->max_fds = FD_SETSIZE - 200;
50493 +        fprintf(stderr, "%s.%d: max parallel connections: %d\r\n", __FILE__, __LINE__, FD_SETSIZE);
50494 +               srv->max_fds = FD_SETSIZE - 4;
50495         } else {
50496                 srv->max_fds = 4096;
50497         }
50498 @@ -636,7 +1006,7 @@
50499  #ifdef HAVE_VALGRIND_VALGRIND_H
50500                 if (RUNNING_ON_VALGRIND) use_rlimit = 0;
50501  #endif
50502 -               
50503 +
50504  #ifdef HAVE_GETRLIMIT
50505                 if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) {
50506                         log_error_write(srv, __FILE__, __LINE__,
50507 @@ -644,13 +1014,13 @@
50508                                         strerror(errno));
50509                         return -1;
50510                 }
50511 -               
50512 +
50513                 if (use_rlimit && srv->srvconf.max_fds) {
50514                         /* set rlimits */
50515 -                       
50516 +
50517                         rlim.rlim_cur = srv->srvconf.max_fds;
50518                         rlim.rlim_max = srv->srvconf.max_fds;
50519 -                       
50520 +
50521                         if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) {
50522                                 log_error_write(srv, __FILE__, __LINE__,
50523                                                 "ss", "couldn't set 'max filedescriptors'",
50524 @@ -659,7 +1029,7 @@
50525                         }
50526                 }
50527  
50528 -               /* #372: solaris need some fds extra for devpoll */     
50529 +               /* #372: solaris need some fds extra for devpoll */
50530                 if (rlim.rlim_cur > 10) rlim.rlim_cur -= 10;
50531  
50532                 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50533 @@ -677,33 +1047,33 @@
50534                 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50535                         /* don't raise the limit above FD_SET_SIZE */
50536                         if (srv->max_fds > FD_SETSIZE - 200) {
50537 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
50538 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
50539                                                 "can't raise max filedescriptors above",  FD_SETSIZE - 200,
50540                                                 "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds.");
50541                                 return -1;
50542                         }
50543                 }
50544  
50545 -               
50546 +
50547  #ifdef HAVE_PWD_H
50548                 /* set user and group */
50549                 if (srv->srvconf.username->used) {
50550                         if (NULL == (pwd = getpwnam(srv->srvconf.username->ptr))) {
50551 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
50552 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
50553                                                 "can't find username", srv->srvconf.username);
50554                                 return -1;
50555                         }
50556 -                       
50557 +
50558                         if (pwd->pw_uid == 0) {
50559                                 log_error_write(srv, __FILE__, __LINE__, "s",
50560                                                 "I will not set uid to 0\n");
50561                                 return -1;
50562                         }
50563                 }
50564 -               
50565 +
50566                 if (srv->srvconf.groupname->used) {
50567                         if (NULL == (grp = getgrnam(srv->srvconf.groupname->ptr))) {
50568 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
50569 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
50570                                         "can't find groupname", srv->srvconf.groupname);
50571                                 return -1;
50572                         }
50573 @@ -713,15 +1083,15 @@
50574                                 return -1;
50575                         }
50576                 }
50577 -#endif         
50578 +#endif
50579                 /* we need root-perms for port < 1024 */
50580                 if (0 != network_init(srv)) {
50581                         plugins_free(srv);
50582                         server_free(srv);
50583 -                       
50584 +
50585                         return -1;
50586                 }
50587 -#ifdef HAVE_CHROOT     
50588 +#ifdef HAVE_CHROOT
50589                 if (srv->srvconf.changeroot->used) {
50590                         tzset();
50591  
50592 @@ -761,7 +1131,7 @@
50593                 }
50594  
50595                 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50596 -                       srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200;
50597 +                       srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 4 ? rlim.rlim_cur : FD_SETSIZE - 4;
50598                 } else {
50599                         srv->max_fds = rlim.rlim_cur;
50600                 }
50601 @@ -775,18 +1145,18 @@
50602  #endif
50603                 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50604                         /* don't raise the limit above FD_SET_SIZE */
50605 -                       if (srv->max_fds > FD_SETSIZE - 200) {
50606 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
50607 -                                               "can't raise max filedescriptors above",  FD_SETSIZE - 200,
50608 +                       if (srv->max_fds > FD_SETSIZE - 4) {
50609 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
50610 +                                               "can't raise max filedescriptors above",  FD_SETSIZE - 4,
50611                                                 "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds.");
50612                                 return -1;
50613                         }
50614                 }
50615 -               
50616 +
50617                 if (0 != network_init(srv)) {
50618                         plugins_free(srv);
50619                         server_free(srv);
50620 -                       
50621 +
50622                         return -1;
50623                 }
50624         }
50625 @@ -802,25 +1172,27 @@
50626                 /* or use the default */
50627                 srv->max_conns = srv->max_fds;
50628         }
50629 -       
50630 +
50631         if (HANDLER_GO_ON != plugins_call_init(srv)) {
50632                 log_error_write(srv, __FILE__, __LINE__, "s", "Initialization of plugins failed. Going down.");
50633 -               
50634 +
50635                 plugins_free(srv);
50636                 network_close(srv);
50637                 server_free(srv);
50638 -               
50639 +
50640                 return -1;
50641         }
50642  
50643 -#ifdef HAVE_FORK       
50644 +#ifdef HAVE_FORK
50645         /* network is up, let's deamonize ourself */
50646         if (srv->srvconf.dont_daemonize == 0) daemonize();
50647  #endif
50648  
50649 +#ifdef HAVE_PWD_H
50650         srv->gid = getgid();
50651         srv->uid = getuid();
50652 -       
50653 +#endif
50654 +
50655         /* write pid file */
50656         if (pid_fd != -1) {
50657                 buffer_copy_long(srv->tmp_buf, getpid());
50658 @@ -829,17 +1201,17 @@
50659                 close(pid_fd);
50660                 pid_fd = -1;
50661         }
50662 -       
50663 +
50664         if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) {
50665                 log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down.");
50666 -               
50667 +
50668                 plugins_free(srv);
50669                 network_close(srv);
50670                 server_free(srv);
50671 -               
50672 +
50673                 return -1;
50674         }
50675 -       
50676 +
50677         /* dump unused config-keys */
50678         for (i = 0; i < srv->config_context->used; i++) {
50679                 array *config = ((data_config *)srv->config_context->data[i])->value;
50680 @@ -847,43 +1219,42 @@
50681  
50682                 for (j = 0; config && j < config->used; j++) {
50683                         data_unset *du = config->data[j];
50684 -                       
50685 +
50686                         /* all var.* is known as user defined variable */
50687                         if (strncmp(du->key->ptr, "var.", sizeof("var.") - 1) == 0) {
50688                                 continue;
50689                         }
50690  
50691                         if (NULL == array_get_element(srv->config_touched, du->key->ptr)) {
50692 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
50693 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
50694                                                 "WARNING: unknown config-key:",
50695                                                 du->key,
50696                                                 "(ignored)");
50697                         }
50698                 }
50699         }
50700 -       
50701 +
50702         if (srv->config_deprecated) {
50703 -               log_error_write(srv, __FILE__, __LINE__, "s", 
50704 +               log_error_write(srv, __FILE__, __LINE__, "s",
50705                                 "Configuration contains deprecated keys. Going down.");
50706 -               
50707 +
50708                 plugins_free(srv);
50709                 network_close(srv);
50710                 server_free(srv);
50711 -               
50712 +
50713                 return -1;
50714         }
50715 -       
50716 -       if (-1 == log_error_open(srv)) {
50717 -               log_error_write(srv, __FILE__, __LINE__, "s", 
50718 +
50719 +       if (-1 == log_error_open(srv->srvconf.errorlog_file, srv->srvconf.errorlog_use_syslog)) {
50720 +               log_error_write(srv, __FILE__, __LINE__, "s",
50721                                 "opening errorlog failed, dying");
50722 -               
50723 +
50724                 plugins_free(srv);
50725                 network_close(srv);
50726                 server_free(srv);
50727                 return -1;
50728         }
50729 -       
50730 -       
50731 +
50732  #ifdef HAVE_SIGACTION
50733         memset(&act, 0, sizeof(act));
50734         act.sa_handler = SIG_IGN;
50735 @@ -903,7 +1274,7 @@
50736         sigaction(SIGHUP,  &act, NULL);
50737         sigaction(SIGALRM, &act, NULL);
50738         sigaction(SIGCHLD, &act, NULL);
50739 -       
50740 +
50741  #elif defined(HAVE_SIGNAL)
50742         /* ignore the SIGPIPE from sendfile() */
50743         signal(SIGPIPE, SIG_IGN);
50744 @@ -914,20 +1285,20 @@
50745         signal(SIGCHLD,  signal_handler);
50746         signal(SIGINT,  signal_handler);
50747  #endif
50748 -       
50749 +
50750  #ifdef USE_ALARM
50751         signal(SIGALRM, signal_handler);
50752 -       
50753 +
50754         /* setup periodic timer (1 second) */
50755         if (setitimer(ITIMER_REAL, &interval, NULL)) {
50756                 log_error_write(srv, __FILE__, __LINE__, "s", "setting timer failed");
50757                 return -1;
50758         }
50759 -       
50760 +
50761         getitimer(ITIMER_REAL, &interval);
50762  #endif
50763  
50764 -#ifdef HAVE_FORK       
50765 +#ifdef HAVE_FORK
50766         /* start watcher and workers */
50767         num_childs = srv->srvconf.max_worker;
50768         if (num_childs > 0) {
50769 @@ -957,13 +1328,13 @@
50770         }
50771  #endif
50772  
50773 -       if (NULL == (srv->ev = fdevent_init(srv->max_fds + 1, srv->event_handler))) {
50774 +       if (NULL == (srv->ev = fdevent_init(/*srv->max_fds + 1*/ 4096, srv->event_handler))) {
50775                 log_error_write(srv, __FILE__, __LINE__,
50776                                 "s", "fdevent_init failed");
50777                 return -1;
50778         }
50779 -       /* 
50780 -        * kqueue() is called here, select resets its internals, 
50781 +       /*
50782 +        * kqueue() is called here, select resets its internals,
50783          * all server sockets get their handlers
50784          *
50785          * */
50786 @@ -971,7 +1342,7 @@
50787                 plugins_free(srv);
50788                 network_close(srv);
50789                 server_free(srv);
50790 -               
50791 +
50792                 return -1;
50793         }
50794  
50795 @@ -986,17 +1357,17 @@
50796         /* setup FAM */
50797         if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) {
50798                 if (0 != FAMOpen2(srv->stat_cache->fam, "lighttpd")) {
50799 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
50800 +                       log_error_write(srv, __FILE__, __LINE__, "s",
50801                                          "could not open a fam connection, dieing.");
50802                         return -1;
50803                 }
50804  #ifdef HAVE_FAMNOEXISTS
50805                 FAMNoExists(srv->stat_cache->fam);
50806  #endif
50807 +               srv->stat_cache->sock->fd = FAMCONNECTION_GETFD(srv->stat_cache->fam);
50808  
50809 -               srv->stat_cache->fam_fcce_ndx = -1;
50810 -               fdevent_register(srv->ev, FAMCONNECTION_GETFD(srv->stat_cache->fam), stat_cache_handle_fdevent, NULL);
50811 -               fdevent_event_add(srv->ev, &(srv->stat_cache->fam_fcce_ndx), FAMCONNECTION_GETFD(srv->stat_cache->fam), FDEVENT_IN);
50812 +               fdevent_register(srv->ev, srv->stat_cache->sock, stat_cache_handle_fdevent, NULL);
50813 +               fdevent_event_add(srv->ev, srv->stat_cache->sock, FDEVENT_IN);
50814         }
50815  #endif
50816  
50817 @@ -1007,330 +1378,36 @@
50818  
50819         for (i = 0; i < srv->srv_sockets.used; i++) {
50820                 server_socket *srv_socket = srv->srv_sockets.ptr[i];
50821 -               if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->fd)) {
50822 +               if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->sock)) {
50823                         log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno));
50824                         return -1;
50825                 }
50826         }
50827  
50828 -       /* main-loop */
50829 -       while (!srv_shutdown) {
50830 -               int n;
50831 -               size_t ndx;
50832 -               time_t min_ts;
50833 -               
50834 -               if (handle_sig_hup) {
50835 -                       handler_t r;
50836 -                       
50837 -                       /* reset notification */
50838 -                       handle_sig_hup = 0;
50839 -                       
50840 -                       
50841 -                       /* cycle logfiles */
50842 -                       
50843 -                       switch(r = plugins_call_handle_sighup(srv)) {
50844 -                       case HANDLER_GO_ON:
50845 -                               break;
50846 -                       default:
50847 -                               log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r);
50848 -                               break;
50849 -                       }
50850 -                       
50851 -                       if (-1 == log_error_cycle(srv)) {
50852 -                               log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying");
50853 -                               
50854 -                               return -1;
50855 -                       }
50856 -               }
50857 -               
50858 -               if (handle_sig_alarm) {
50859 -                       /* a new second */
50860 -                       
50861 -#ifdef USE_ALARM
50862 -                       /* reset notification */
50863 -                       handle_sig_alarm = 0;
50864 -#endif
50865 -                       
50866 -                       /* get current time */
50867 -                       min_ts = time(NULL);
50868 -                       
50869 -                       if (min_ts != srv->cur_ts) {
50870 -                               int cs = 0;
50871 -                               connections *conns = srv->conns;
50872 -                               handler_t r;
50873 -                               
50874 -                               switch(r = plugins_call_handle_trigger(srv)) {
50875 -                               case HANDLER_GO_ON:
50876 -                                       break;
50877 -                               case HANDLER_ERROR:
50878 -                                       log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed");
50879 -                                       break;
50880 -                               default:
50881 -                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
50882 -                                       break;
50883 -                               }
50884 -                               
50885 -                               /* trigger waitpid */
50886 -                               srv->cur_ts = min_ts;
50887 -                       
50888 -                               /* cleanup stat-cache */        
50889 -                               stat_cache_trigger_cleanup(srv);
50890 -                               /**
50891 -                                * check all connections for timeouts 
50892 -                                * 
50893 -                                */
50894 -                               for (ndx = 0; ndx < conns->used; ndx++) {
50895 -                                       int changed = 0;
50896 -                                       connection *con;
50897 -                                       int t_diff;
50898 -                                       
50899 -                                       con = conns->ptr[ndx];
50900 -
50901 -                                       if (con->state == CON_STATE_READ ||
50902 -                                           con->state == CON_STATE_READ_POST) {
50903 -                                               if (con->request_count == 1) {
50904 -                                                       if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
50905 -                                                               /* time - out */
50906 -#if 0
50907 -                                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
50908 -                                                                               "connection closed - read-timeout:", con->fd);
50909 -#endif
50910 -                                                               connection_set_state(srv, con, CON_STATE_ERROR);
50911 -                                                               changed = 1;
50912 -                                                       }
50913 -                                               } else {
50914 -                                                       if (srv->cur_ts - con->read_idle_ts > con->conf.max_keep_alive_idle) {
50915 -                                                               /* time - out */
50916 -#if 0
50917 -                                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
50918 -                                                                               "connection closed - read-timeout:", con->fd);
50919 -#endif
50920 -                                                               connection_set_state(srv, con, CON_STATE_ERROR);
50921 -                                                               changed = 1;
50922 -                                                       }
50923 -                                               }
50924 -                                       }
50925 -                                       
50926 -                                       if ((con->state == CON_STATE_WRITE) &&
50927 -                                           (con->write_request_ts != 0)) { 
50928 -#if 0
50929 -                                               if (srv->cur_ts - con->write_request_ts > 60) {
50930 -                                                       log_error_write(srv, __FILE__, __LINE__, "sdd", 
50931 -                                                                       "connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts);
50932 -                                               }
50933 -#endif
50934 -                                               
50935 -                                               if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) {
50936 -                                                       /* time - out */
50937 -#if 1
50938 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbsosds", 
50939 -                                                                       "NOTE: a request for",
50940 -                                                                       con->request.uri,
50941 -                                                                       "timed out after writing",
50942 -                                                                       con->bytes_written,
50943 -                                                                       "bytes. We waited",
50944 -                                                                       (int)con->conf.max_write_idle,
50945 -                                                                       "seconds. If this a problem increase server.max-write-idle");
50946 -#endif
50947 -                                                       connection_set_state(srv, con, CON_STATE_ERROR);
50948 -                                                       changed = 1;
50949 -                                               }
50950 -                                       }
50951 -                                       /* we don't like div by zero */
50952 -                                       if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1;
50953 -       
50954 -                                       if (con->traffic_limit_reached && 
50955 -                                           (con->conf.kbytes_per_second == 0 || 
50956 -                                            ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) {
50957 -                                               /* enable connection again */
50958 -                                               con->traffic_limit_reached = 0;
50959 -                                               
50960 -                                               changed = 1;
50961 -                                       }
50962 -                                       
50963 -                                       if (changed) {
50964 -                                               connection_state_machine(srv, con);
50965 -                                       }
50966 -                                       con->bytes_written_cur_second = 0;
50967 -                                       *(con->conf.global_bytes_per_second_cnt_ptr) = 0;
50968 -                                       
50969 -#if 0
50970 -                                       if (cs == 0) {
50971 -                                               fprintf(stderr, "connection-state: ");
50972 -                                               cs = 1;
50973 -                                       }
50974 -                                       
50975 -                                       fprintf(stderr, "c[%d,%d]: %s ",
50976 -                                               con->fd,
50977 -                                               con->fcgi.fd,
50978 -                                               connection_get_state(con->state));
50979 -#endif
50980 -                               }
50981 -                               
50982 -                               if (cs == 1) fprintf(stderr, "\n");
50983 -                       }
50984 -               }
50985 -
50986 -               if (srv->sockets_disabled) {
50987 -                       /* our server sockets are disabled, why ? */
50988 -
50989 -                       if ((srv->cur_fds + srv->want_fds < srv->max_fds * 0.8) && /* we have enough unused fds */
50990 -                           (srv->conns->used < srv->max_conns * 0.9) &&
50991 -                           (0 == graceful_shutdown)) {
50992 -                               for (i = 0; i < srv->srv_sockets.used; i++) {
50993 -                                       server_socket *srv_socket = srv->srv_sockets.ptr[i];
50994 -                                       fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
50995 -                               }
50996 -                       
50997 -                               log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again");
50998 -                       
50999 -                               srv->sockets_disabled = 0;
51000 -                       }
51001 -               } else {
51002 -                       if ((srv->cur_fds + srv->want_fds > srv->max_fds * 0.9) || /* out of fds */
51003 -                           (srv->conns->used > srv->max_conns) || /* out of connections */
51004 -                           (graceful_shutdown)) { /* graceful_shutdown */ 
51005 -
51006 -                               /* disable server-fds */
51007 -                       
51008 -                               for (i = 0; i < srv->srv_sockets.used; i++) {
51009 -                                       server_socket *srv_socket = srv->srv_sockets.ptr[i];
51010 -                                       fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
51011 -
51012 -                                       if (graceful_shutdown) {
51013 -                                               /* we don't want this socket anymore,
51014 -                                                *
51015 -                                                * closing it right away will make it possible for
51016 -                                                * the next lighttpd to take over (graceful restart)
51017 -                                                *  */
51018 -
51019 -                                               fdevent_unregister(srv->ev, srv_socket->fd);
51020 -                                               close(srv_socket->fd);
51021 -                                               srv_socket->fd = -1;
51022 -
51023 -                                               /* network_close() will cleanup after us */
51024 -                                       }
51025 -                               }
51026 -               
51027 -                               if (graceful_shutdown) {
51028 -                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started");
51029 -                               } else if (srv->conns->used > srv->max_conns) {
51030 -                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached");
51031 -                               } else {
51032 -                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds");
51033 -                               }
51034 -                       
51035 -                               srv->sockets_disabled = 1;
51036 -                       }
51037 -               }
51038 +       lighty_mainloop(srv);
51039  
51040 -               if (graceful_shutdown && srv->conns->used == 0) {
51041 -                       /* we are in graceful shutdown phase and all connections are closed
51042 -                        * we are ready to terminate without harming anyone */
51043 -                       srv_shutdown = 1;
51044 -               }
51045 -               
51046 -               /* we still have some fds to share */
51047 -               if (srv->want_fds) { 
51048 -                       /* check the fdwaitqueue for waiting fds */
51049 -                       int free_fds = srv->max_fds - srv->cur_fds - 16;
51050 -                       connection *con;
51051 -                       
51052 -                       for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) {
51053 -                               connection_state_machine(srv, con);
51054 -                               
51055 -                               srv->want_fds--;
51056 -                       }
51057 -               }
51058 +       status_counter_free();
51059  
51060 -               if ((n = fdevent_poll(srv->ev, 1000)) > 0) {
51061 -                       /* n is the number of events */
51062 -                       int revents;
51063 -                       int fd_ndx;
51064 -#if 0
51065 -                       if (n > 0) {
51066 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
51067 -                                               "polls:", n);
51068 -                       }
51069 -#endif                 
51070 -                       fd_ndx = -1;
51071 -                       do {
51072 -                               fdevent_handler handler;
51073 -                               void *context;
51074 -                               handler_t r;
51075 -                               
51076 -                               fd_ndx  = fdevent_event_next_fdndx (srv->ev, fd_ndx);
51077 -                               revents = fdevent_event_get_revent (srv->ev, fd_ndx);
51078 -                               fd      = fdevent_event_get_fd     (srv->ev, fd_ndx);
51079 -                               handler = fdevent_get_handler(srv->ev, fd);
51080 -                               context = fdevent_get_context(srv->ev, fd);
51081 -                               
51082 -                               /* connection_handle_fdevent needs a joblist_append */
51083 -#if 0
51084 -                               log_error_write(srv, __FILE__, __LINE__, "sdd", 
51085 -                                               "event for", fd, revents);
51086 -#endif                         
51087 -                               switch (r = (*handler)(srv, context, revents)) {
51088 -                               case HANDLER_FINISHED:
51089 -                               case HANDLER_GO_ON:
51090 -                               case HANDLER_WAIT_FOR_EVENT:
51091 -                               case HANDLER_WAIT_FOR_FD:
51092 -                                       break;
51093 -                               case HANDLER_ERROR:
51094 -                                       /* should never happen */
51095 -                                       SEGFAULT();
51096 -                                       break;
51097 -                               default:
51098 -                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
51099 -                                       break;
51100 -                               }
51101 -                       } while (--n > 0);
51102 -               } else if (n < 0 && errno != EINTR) {
51103 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
51104 -                                       "fdevent_poll failed:", 
51105 -                                       strerror(errno));
51106 -               }
51107 -               
51108 -               for (ndx = 0; ndx < srv->joblist->used; ndx++) {
51109 -                       connection *con = srv->joblist->ptr[ndx];
51110 -                       handler_t r;
51111 -                       
51112 -                       connection_state_machine(srv, con);
51113 -                       
51114 -                       switch(r = plugins_call_handle_joblist(srv, con)) {
51115 -                       case HANDLER_FINISHED:
51116 -                       case HANDLER_GO_ON:
51117 -                               break;
51118 -                       default:
51119 -                               log_error_write(srv, __FILE__, __LINE__, "d", r);
51120 -                               break;
51121 -                       }
51122 -                       
51123 -                       con->in_joblist = 0;
51124 -               }
51125 -               
51126 -               srv->joblist->used = 0;
51127 -       }
51128 -       
51129 -       if (srv->srvconf.pid_file->used &&
51130 +       if (0 == graceful_restart &&
51131 +           srv->srvconf.pid_file->used &&
51132             srv->srvconf.changeroot->used == 0) {
51133                 if (0 != unlink(srv->srvconf.pid_file->ptr)) {
51134                         if (errno != EACCES && errno != EPERM) {
51135 -                               log_error_write(srv, __FILE__, __LINE__, "sbds", 
51136 -                                               "unlink failed for:", 
51137 +                               log_error_write(srv, __FILE__, __LINE__, "sbds",
51138 +                                               "unlink failed for:",
51139                                                 srv->srvconf.pid_file,
51140                                                 errno,
51141                                                 strerror(errno));
51142                         }
51143                 }
51144         }
51145 -       
51146 +
51147         /* clean-up */
51148 -       log_error_close(srv);
51149         network_close(srv);
51150         connections_free(srv);
51151         plugins_free(srv);
51152         server_free(srv);
51153 -       
51154 +       log_free();
51155 +
51156         return 0;
51157  }
51158 --- ../lighttpd-1.4.11/src/settings.h   2005-08-11 01:26:41.000000000 +0300
51159 +++ lighttpd-1.4.12/src/settings.h      2006-07-16 00:26:04.000000000 +0300
51160 @@ -9,24 +9,24 @@
51161  /**
51162   * max size of a buffer which will just be reset
51163   * to ->used = 0 instead of really freeing the buffer
51164 - * 
51165 + *
51166   * 64kB (no real reason, just a guess)
51167   */
51168  #define BUFFER_MAX_REUSE_SIZE  (4 * 1024)
51169  
51170  /**
51171   * max size of the HTTP request header
51172 - * 
51173 + *
51174   * 32k should be enough for everything (just a guess)
51175 - * 
51176 + *
51177   */
51178  #define MAX_HTTP_REQUEST_HEADER  (32 * 1024)
51179  
51180 -typedef enum { HANDLER_UNSET, 
51181 -               HANDLER_GO_ON, 
51182 +typedef enum { HANDLER_UNSET,
51183 +               HANDLER_GO_ON,
51184                 HANDLER_FINISHED,
51185 -               HANDLER_COMEBACK, 
51186 -               HANDLER_WAIT_FOR_EVENT, 
51187 +               HANDLER_COMEBACK,
51188 +               HANDLER_WAIT_FOR_EVENT,
51189                 HANDLER_ERROR,
51190                 HANDLER_WAIT_FOR_FD
51191  } handler_t;
51192 --- ../lighttpd-1.4.11/src/spawn-fcgi.c 2006-03-07 14:18:10.000000000 +0200
51193 +++ lighttpd-1.4.12/src/spawn-fcgi.c    2006-07-16 00:26:04.000000000 +0300
51194 @@ -1,19 +1,16 @@
51195  #include <sys/types.h>
51196 -#include <sys/time.h>
51197  #include <sys/stat.h>
51198  
51199  #include <stdlib.h>
51200  #include <string.h>
51201  #include <errno.h>
51202  #include <stdio.h>
51203 -#include <unistd.h>
51204  #include <fcntl.h>
51205 -
51206 +#include <time.h>
51207  #ifdef HAVE_CONFIG_H
51208  #include "config.h"
51209  #endif
51210  
51211 -
51212  #ifdef HAVE_PWD_H
51213  #include <grp.h>
51214  #include <pwd.h>
51215 @@ -30,6 +27,7 @@
51216  #endif
51217  
51218  #include "sys-socket.h"
51219 +#include "sys-files.h"
51220  
51221  #ifdef HAVE_SYS_WAIT_H
51222  #include <sys/wait.h>
51223 @@ -45,28 +43,28 @@
51224         int fcgi_fd;
51225         int socket_type, status;
51226         struct timeval tv = { 0, 100 * 1000 };
51227 -       
51228 +
51229         struct sockaddr_un fcgi_addr_un;
51230         struct sockaddr_in fcgi_addr_in;
51231         struct sockaddr *fcgi_addr;
51232 -       
51233 +
51234         socklen_t servlen;
51235 -       
51236 +
51237         if (child_count < 2) {
51238                 child_count = 5;
51239         }
51240 -       
51241 +
51242         if (child_count > 256) {
51243                 child_count = 256;
51244         }
51245 -       
51246 -       
51247 +
51248 +
51249         if (unixsocket) {
51250                 memset(&fcgi_addr, 0, sizeof(fcgi_addr));
51251 -               
51252 +
51253                 fcgi_addr_un.sun_family = AF_UNIX;
51254                 strcpy(fcgi_addr_un.sun_path, unixsocket);
51255 -               
51256 +
51257  #ifdef SUN_LEN
51258                 servlen = SUN_LEN(&fcgi_addr_un);
51259  #else
51260 @@ -84,50 +82,50 @@
51261                  }
51262                 fcgi_addr_in.sin_port = htons(port);
51263                 servlen = sizeof(fcgi_addr_in);
51264 -               
51265 +
51266                 socket_type = AF_INET;
51267                 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
51268         }
51269 -       
51270 +
51271         if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
51272 -               fprintf(stderr, "%s.%d\n", 
51273 +               fprintf(stderr, "%s.%d\n",
51274                         __FILE__, __LINE__);
51275                 return -1;
51276         }
51277 -       
51278 +
51279         if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
51280                 /* server is not up, spawn in  */
51281                 pid_t child;
51282                 int val;
51283 -               
51284 +
51285                 if (unixsocket) unlink(unixsocket);
51286 -               
51287 +
51288                 close(fcgi_fd);
51289 -               
51290 +
51291                 /* reopen socket */
51292                 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
51293 -                       fprintf(stderr, "%s.%d\n", 
51294 +                       fprintf(stderr, "%s.%d\n",
51295                                 __FILE__, __LINE__);
51296                         return -1;
51297                 }
51298  
51299                 val = 1;
51300                 if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
51301 -                       fprintf(stderr, "%s.%d\n", 
51302 +                       fprintf(stderr, "%s.%d\n",
51303                                 __FILE__, __LINE__);
51304                         return -1;
51305                 }
51306  
51307                 /* create socket */
51308                 if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
51309 -                       fprintf(stderr, "%s.%d: bind failed: %s\n", 
51310 +                       fprintf(stderr, "%s.%d: bind failed: %s\n",
51311                                 __FILE__, __LINE__,
51312                                 strerror(errno));
51313                         return -1;
51314                 }
51315 -               
51316 +
51317                 if (-1 == listen(fcgi_fd, 1024)) {
51318 -                       fprintf(stderr, "%s.%d: fd = -1\n", 
51319 +                       fprintf(stderr, "%s.%d: fd = -1\n",
51320                                 __FILE__, __LINE__);
51321                         return -1;
51322                 }
51323 @@ -137,42 +135,45 @@
51324                 } else {
51325                         child = 0;
51326                 }
51327 -               
51328 +
51329                 switch (child) {
51330                 case 0: {
51331                         char cgi_childs[64];
51332                         char *b;
51333 -                       
51334 +
51335                         int i = 0;
51336 -                       
51337 +
51338 +                       /* loose control terminal */
51339 +                       setsid();
51340 +
51341                         /* is save as we limit to 256 childs */
51342                         sprintf(cgi_childs, "PHP_FCGI_CHILDREN=%d", child_count);
51343 -                       
51344 +
51345                         if(fcgi_fd != FCGI_LISTENSOCK_FILENO) {
51346                                 close(FCGI_LISTENSOCK_FILENO);
51347                                 dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
51348                                 close(fcgi_fd);
51349                         }
51350 -                       
51351 +
51352                         /* we don't need the client socket */
51353                         for (i = 3; i < 256; i++) {
51354                                 close(i);
51355                         }
51356 -                       
51357 +
51358                         /* create environment */
51359 -                       
51360 +
51361                         putenv(cgi_childs);
51362 -                       
51363 +
51364                         /* fork and replace shell */
51365                         b = malloc(strlen("exec ") + strlen(appPath) + 1);
51366                         strcpy(b, "exec ");
51367                         strcat(b, appPath);
51368 -                       
51369 +
51370                         /* exec the cgi */
51371                         execl("/bin/sh", "sh", "-c", b, NULL);
51372 -                       
51373 +
51374                         exit(errno);
51375 -                       
51376 +
51377                         break;
51378                 }
51379                 case -1:
51380 @@ -180,47 +181,47 @@
51381                         break;
51382                 default:
51383                         /* father */
51384 -                       
51385 +
51386                         /* wait */
51387                         select(0, NULL, NULL, NULL, &tv);
51388 -                       
51389 +
51390                         switch (waitpid(child, &status, WNOHANG)) {
51391                         case 0:
51392 -                               fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n", 
51393 +                               fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n",
51394                                         __FILE__, __LINE__,
51395                                         child);
51396 -                               
51397 +
51398                                 /* write pid file */
51399                                 if (pid_fd != -1) {
51400                                         /* assume a 32bit pid_t */
51401                                         char pidbuf[12];
51402 -                                       
51403 +
51404                                         snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child);
51405 -                                       
51406 +
51407                                         write(pid_fd, pidbuf, strlen(pidbuf));
51408                                         close(pid_fd);
51409                                         pid_fd = -1;
51410                                 }
51411 -                               
51412 +
51413                                 break;
51414                         case -1:
51415                                 break;
51416                         default:
51417                                 if (WIFEXITED(status)) {
51418 -                                       fprintf(stderr, "%s.%d: child exited with: %d, %s\n", 
51419 +                                       fprintf(stderr, "%s.%d: child exited with: %d, %s\n",
51420                                                 __FILE__, __LINE__,
51421                                                 WEXITSTATUS(status), strerror(WEXITSTATUS(status)));
51422                                 } else if (WIFSIGNALED(status)) {
51423 -                                       fprintf(stderr, "%s.%d: child signaled: %d\n", 
51424 +                                       fprintf(stderr, "%s.%d: child signaled: %d\n",
51425                                                 __FILE__, __LINE__,
51426                                                 WTERMSIG(status));
51427                                 } else {
51428 -                                       fprintf(stderr, "%s.%d: child died somehow: %d\n", 
51429 +                                       fprintf(stderr, "%s.%d: child died somehow: %d\n",
51430                                                 __FILE__, __LINE__,
51431                                                 status);
51432                                 }
51433                         }
51434 -                               
51435 +
51436                         break;
51437                 }
51438         } else {
51439 @@ -228,16 +229,16 @@
51440                         __FILE__, __LINE__);
51441                 return -1;
51442         }
51443 -       
51444 +
51445         close(fcgi_fd);
51446 -       
51447 +
51448         return 0;
51449  }
51450  
51451  
51452  void show_version () {
51453         char *b = "spawn-fcgi" "-" PACKAGE_VERSION \
51454 -" - spawns fastcgi processes\n" 
51455 +" - spawns fastcgi processes\n"
51456  ;
51457         write(1, b, strlen(b));
51458  }
51459 @@ -265,7 +266,7 @@
51460  
51461  
51462  int main(int argc, char **argv) {
51463 -       char *fcgi_app = NULL, *changeroot = NULL, *username = NULL, 
51464 +       char *fcgi_app = NULL, *changeroot = NULL, *username = NULL,
51465                 *groupname = NULL, *unixsocket = NULL, *pid_file = NULL,
51466                  *addr = NULL;
51467         unsigned short port = 0;
51468 @@ -273,9 +274,9 @@
51469         int i_am_root, o;
51470         int pid_fd = -1;
51471         int nofork = 0;
51472 -       
51473 +
51474         i_am_root = (getuid() == 0);
51475 -       
51476 +
51477         while(-1 != (o = getopt(argc, argv, "c:f:g:hna:p:u:vC:s:P:"))) {
51478                 switch(o) {
51479                 case 'f': fcgi_app = optarg; break;
51480 @@ -290,137 +291,137 @@
51481                 case 'P': pid_file = optarg; /* PID file */ break;
51482                 case 'v': show_version(); return 0;
51483                 case 'h': show_help(); return 0;
51484 -               default: 
51485 +               default:
51486                         show_help();
51487                         return -1;
51488                 }
51489         }
51490 -       
51491 +
51492         if (fcgi_app == NULL || (port == 0 && unixsocket == NULL)) {
51493                 show_help();
51494                 return -1;
51495         }
51496 -           
51497 +
51498         if (unixsocket && port) {
51499 -               fprintf(stderr, "%s.%d: %s\n", 
51500 +               fprintf(stderr, "%s.%d: %s\n",
51501                         __FILE__, __LINE__,
51502                         "either a unix domain socket or a tcp-port, but not both\n");
51503 -               
51504 +
51505                 return -1;
51506         }
51507 -       
51508 +
51509         if (unixsocket && strlen(unixsocket) > UNIX_PATH_MAX - 1) {
51510 -               fprintf(stderr, "%s.%d: %s\n", 
51511 +               fprintf(stderr, "%s.%d: %s\n",
51512                         __FILE__, __LINE__,
51513                         "path of the unix socket is too long\n");
51514 -               
51515 +
51516                 return -1;
51517         }
51518  
51519         /* UID handling */
51520         if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
51521                 /* we are setuid-root */
51522 -               
51523 -               fprintf(stderr, "%s.%d: %s\n", 
51524 +
51525 +               fprintf(stderr, "%s.%d: %s\n",
51526                         __FILE__, __LINE__,
51527                         "Are you nuts ? Don't apply a SUID bit to this binary\n");
51528 -               
51529 +
51530                 return -1;
51531         }
51532 -       
51533 -       if (pid_file && 
51534 +
51535 +       if (pid_file &&
51536             (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)))) {
51537                 struct stat st;
51538                 if (errno != EEXIST) {
51539 -                       fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n", 
51540 +                       fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
51541                                 __FILE__, __LINE__,
51542                                 pid_file, strerror(errno));
51543 -                       
51544 +
51545                         return -1;
51546                 }
51547 -               
51548 +
51549                 /* ok, file exists */
51550 -               
51551 +
51552                 if (0 != stat(pid_file, &st)) {
51553 -                       fprintf(stderr, "%s.%d: stating pid-file '%s' failed: %s\n", 
51554 +                       fprintf(stderr, "%s.%d: stating pid-file '%s' failed: %s\n",
51555                                 __FILE__, __LINE__,
51556                                 pid_file, strerror(errno));
51557 -                       
51558 +
51559                         return -1;
51560                 }
51561 -               
51562 +
51563                 /* is it a regular file ? */
51564 -               
51565 +
51566                 if (!S_ISREG(st.st_mode)) {
51567 -                       fprintf(stderr, "%s.%d: pid-file exists and isn't regular file: '%s'\n", 
51568 +                       fprintf(stderr, "%s.%d: pid-file exists and isn't regular file: '%s'\n",
51569                                 __FILE__, __LINE__,
51570                                 pid_file);
51571 -                       
51572 +
51573                         return -1;
51574                 }
51575 -               
51576 +
51577                 if (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
51578 -                       fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n", 
51579 +                       fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
51580                                 __FILE__, __LINE__,
51581                                 pid_file, strerror(errno));
51582 -                       
51583 +
51584                         return -1;
51585                 }
51586         }
51587 -       
51588 +
51589         if (i_am_root) {
51590                 struct group *grp = NULL;
51591                 struct passwd *pwd = NULL;
51592 -               
51593 +
51594                 /* set user and group */
51595 -               
51596 +
51597                 if (username) {
51598                         if (NULL == (pwd = getpwnam(username))) {
51599 -                               fprintf(stderr, "%s.%d: %s, %s\n", 
51600 +                               fprintf(stderr, "%s.%d: %s, %s\n",
51601                                         __FILE__, __LINE__,
51602                                         "can't find username", username);
51603                                 return -1;
51604                         }
51605 -                       
51606 +
51607                         if (pwd->pw_uid == 0) {
51608 -                               fprintf(stderr, "%s.%d: %s\n", 
51609 +                               fprintf(stderr, "%s.%d: %s\n",
51610                                         __FILE__, __LINE__,
51611                                         "I will not set uid to 0\n");
51612                                 return -1;
51613                         }
51614                 }
51615 -               
51616 +
51617                 if (groupname) {
51618                         if (NULL == (grp = getgrnam(groupname))) {
51619 -                               fprintf(stderr, "%s.%d: %s %s\n", 
51620 +                               fprintf(stderr, "%s.%d: %s %s\n",
51621                                         __FILE__, __LINE__,
51622 -                                       "can't find groupname", 
51623 +                                       "can't find groupname",
51624                                         groupname);
51625                                 return -1;
51626                         }
51627                         if (grp->gr_gid == 0) {
51628 -                               fprintf(stderr, "%s.%d: %s\n", 
51629 +                               fprintf(stderr, "%s.%d: %s\n",
51630                                         __FILE__, __LINE__,
51631                                         "I will not set gid to 0\n");
51632                                 return -1;
51633                         }
51634                 }
51635 -               
51636 +
51637                 if (changeroot) {
51638                         if (-1 == chroot(changeroot)) {
51639 -                               fprintf(stderr, "%s.%d: %s %s\n", 
51640 +                               fprintf(stderr, "%s.%d: %s %s\n",
51641                                         __FILE__, __LINE__,
51642                                         "chroot failed: ", strerror(errno));
51643                                 return -1;
51644                         }
51645                         if (-1 == chdir("/")) {
51646 -                               fprintf(stderr, "%s.%d: %s %s\n", 
51647 +                               fprintf(stderr, "%s.%d: %s %s\n",
51648                                         __FILE__, __LINE__,
51649                                         "chdir failed: ", strerror(errno));
51650                                 return -1;
51651                         }
51652                 }
51653 -               
51654 +
51655                 /* drop root privs */
51656                 if (groupname) {
51657                         setgid(grp->gr_gid);
51658 @@ -428,7 +429,7 @@
51659                 }
51660                 if (username) setuid(pwd->pw_uid);
51661         }
51662 -       
51663 +
51664         return fcgi_spawn_connection(fcgi_app, addr, port, unixsocket, child_count, pid_fd, nofork);
51665  }
51666  #else
51667 --- ../lighttpd-1.4.11/src/splaytree.c  2005-09-12 21:51:28.000000000 +0300
51668 +++ lighttpd-1.4.12/src/splaytree.c     2006-07-16 00:26:03.000000000 +0300
51669 @@ -56,19 +56,19 @@
51670  
51671  #define node_size splaytree_size
51672  
51673 -/* Splay using the key i (which may or may not be in the tree.) 
51674 - * The starting root is t, and the tree used is defined by rat 
51675 +/* Splay using the key i (which may or may not be in the tree.)
51676 + * The starting root is t, and the tree used is defined by rat
51677   * size fields are maintained */
51678  splay_tree * splaytree_splay (splay_tree *t, int i) {
51679      splay_tree N, *l, *r, *y;
51680      int comp, root_size, l_size, r_size;
51681 -    
51682 +
51683      if (t == NULL) return t;
51684      N.left = N.right = NULL;
51685      l = r = &N;
51686      root_size = node_size(t);
51687      l_size = r_size = 0;
51688
51689 +
51690      for (;;) {
51691          comp = compare(i, t->key);
51692          if (comp < 0) {
51693 @@ -120,7 +120,7 @@
51694          y->size = r_size;
51695          r_size -= 1+node_size(y->right);
51696      }
51697
51698 +
51699      l->right = t->left;                                /* assemble */
51700      r->left = t->right;
51701      t->left = N.right;
51702 --- ../lighttpd-1.4.11/src/splaytree.h  2005-09-12 21:51:13.000000000 +0300
51703 +++ lighttpd-1.4.12/src/splaytree.h     2006-07-16 00:26:03.000000000 +0300
51704 @@ -19,6 +19,6 @@
51705  /* This macro returns the size of a node.  Unlike "x->size",     */
51706  /* it works even if x=NULL.  The test could be avoided by using  */
51707  /* a special version of NULL which was a real node with size 0.  */
51708
51709 +
51710  
51711  #endif
51712 --- ../lighttpd-1.4.11/src/stat_cache.c 2005-11-22 15:23:51.000000000 +0200
51713 +++ lighttpd-1.4.12/src/stat_cache.c    2006-07-18 13:03:40.000000000 +0300
51714 @@ -6,7 +6,6 @@
51715  #include <stdlib.h>
51716  #include <string.h>
51717  #include <errno.h>
51718 -#include <unistd.h>
51719  #include <stdio.h>
51720  #include <fcntl.h>
51721  #include <assert.h>
51722 @@ -25,19 +24,8 @@
51723  #endif
51724  
51725  #include "sys-mmap.h"
51726 -
51727 -/* NetBSD 1.3.x needs it */
51728 -#ifndef MAP_FAILED
51729 -# define MAP_FAILED -1
51730 -#endif
51731 -
51732 -#ifndef O_LARGEFILE
51733 -# define O_LARGEFILE 0
51734 -#endif
51735 -
51736 -#ifndef HAVE_LSTAT
51737 -#define lstat stat
51738 -#endif
51739 +#include "sys-files.h"
51740 +#include "sys-strings.h"
51741  
51742  #if 0
51743  /* enables debug code for testing if all nodes in the stat-cache as accessable */
51744 @@ -52,8 +40,8 @@
51745   *
51746   * if we get a change-event from FAM, we increment the version in the FAM->dir mapping
51747   *
51748 - * if the stat()-cache is queried we check if the version id for the directory is the 
51749 - * same and return immediatly. 
51750 + * if the stat()-cache is queried we check if the version id for the directory is the
51751 + * same and return immediatly.
51752   *
51753   *
51754   * What we need:
51755 @@ -62,17 +50,17 @@
51756   * - for each FAMRequest we have to find the version in the directory cache (index as userdata)
51757   *
51758   * stat <<-> directory <-> FAMRequest
51759 - * 
51760 - * if file is deleted, directory is dirty, file is rechecked ... 
51761 + *
51762 + * if file is deleted, directory is dirty, file is rechecked ...
51763   * if directory is deleted, directory mapping is removed
51764 - *  
51765 + *
51766   * */
51767  
51768  #ifdef HAVE_FAM_H
51769  typedef struct {
51770         FAMRequest *req;
51771         FAMConnection *fc;
51772 -       
51773 +
51774         buffer *name;
51775  
51776         int version;
51777 @@ -83,16 +71,16 @@
51778   * - we need a hash
51779   * - the hash-key is used as sorting criteria for a tree
51780   * - a splay-tree is used as we can use the caching effect of it
51781 - */ 
51782 + */
51783  
51784  /* we want to cleanup the stat-cache every few seconds, let's say 10
51785   *
51786   * - remove entries which are outdated since 30s
51787   * - remove entries which are fresh but havn't been used since 60s
51788   * - if we don't have a stat-cache entry for a directory, release it from the monitor
51789 - */ 
51790 + */
51791  
51792 -#ifdef DEBUG_STAT_CACHE        
51793 +#ifdef DEBUG_STAT_CACHE
51794  typedef struct {
51795         int *ptr;
51796  
51797 @@ -105,15 +93,16 @@
51798  
51799  stat_cache *stat_cache_init(void) {
51800         stat_cache *fc = NULL;
51801 -       
51802 +
51803         fc = calloc(1, sizeof(*fc));
51804 -       
51805 +
51806         fc->dir_name = buffer_init();
51807  #ifdef HAVE_FAM_H
51808         fc->fam = calloc(1, sizeof(*fc->fam));
51809 +       fc->sock = iosocket_init();
51810  #endif
51811  
51812 -#ifdef DEBUG_STAT_CACHE        
51813 +#ifdef DEBUG_STAT_CACHE
51814         ctrl.size = 0;
51815  #endif
51816  
51817 @@ -122,24 +111,24 @@
51818  
51819  static stat_cache_entry * stat_cache_entry_init(void) {
51820         stat_cache_entry *sce = NULL;
51821 -       
51822 +
51823         sce = calloc(1, sizeof(*sce));
51824 -       
51825 +
51826         sce->name = buffer_init();
51827         sce->etag = buffer_init();
51828         sce->content_type = buffer_init();
51829 -       
51830 +
51831         return sce;
51832  }
51833  
51834  static void stat_cache_entry_free(void *data) {
51835         stat_cache_entry *sce = data;
51836         if (!sce) return;
51837 -       
51838 +
51839         buffer_free(sce->etag);
51840         buffer_free(sce->name);
51841         buffer_free(sce->content_type);
51842 -       
51843 +
51844         free(sce);
51845  }
51846  
51847 @@ -148,22 +137,22 @@
51848         fam_dir_entry *fam_dir = NULL;
51849  
51850         fam_dir = calloc(1, sizeof(*fam_dir));
51851 -       
51852 +
51853         fam_dir->name = buffer_init();
51854 -       
51855 +
51856         return fam_dir;
51857  }
51858  
51859  static void fam_dir_entry_free(void *data) {
51860         fam_dir_entry *fam_dir = data;
51861 -       
51862 +
51863         if (!fam_dir) return;
51864 -       
51865 +
51866         FAMCancelMonitor(fam_dir->fc, fam_dir->req);
51867 -       
51868 +
51869         buffer_free(fam_dir->name);
51870         free(fam_dir->req);
51871 -       
51872 +
51873         free(fam_dir);
51874  }
51875  #endif
51876 @@ -174,7 +163,7 @@
51877                 splay_tree *node = sc->files;
51878  
51879                 osize = sc->files->size;
51880 -                       
51881 +
51882                 stat_cache_entry_free(node->data);
51883                 sc->files = splaytree_delete(sc->files, node->key);
51884  
51885 @@ -187,12 +176,12 @@
51886         while (sc->dirs) {
51887                 int osize;
51888                 splay_tree *node = sc->dirs;
51889 -               
51890 +
51891                 osize = sc->dirs->size;
51892  
51893                 fam_dir_entry_free(node->data);
51894                 sc->dirs = splaytree_delete(sc->dirs, node->key);
51895 -               
51896 +
51897                 if (osize == 1) {
51898                         assert(NULL == sc->dirs);
51899                 } else {
51900 @@ -202,6 +191,7 @@
51901  
51902         if (sc->fam) {
51903                 FAMClose(sc->fam);
51904 +               iosocket_free(sc->sock);
51905                 free(sc->fam);
51906         }
51907  #endif
51908 @@ -212,7 +202,7 @@
51909  static int stat_cache_attr_get(buffer *buf, char *name) {
51910         int attrlen;
51911         int ret;
51912 -       
51913 +
51914         attrlen = 1024;
51915         buffer_prepare_copy(buf, attrlen);
51916         attrlen--;
51917 @@ -251,15 +241,15 @@
51918             sc->fam) {
51919  
51920                 events = FAMPending(sc->fam);
51921 -       
51922 +
51923                 for (i = 0; i < events; i++) {
51924                         FAMEvent fe;
51925                         fam_dir_entry *fam_dir;
51926                         splay_tree *node;
51927                         int ndx;
51928 -               
51929 +
51930                         FAMNextEvent(sc->fam, &fe);
51931 -       
51932 +
51933                         /* handle event */
51934  
51935                         switch(fe.code) {
51936 @@ -280,7 +270,7 @@
51937  
51938                                 sc->dirs = splaytree_splay(sc->dirs, ndx);
51939                                 node = sc->dirs;
51940 -                       
51941 +
51942                                 if (node && (node->key == ndx)) {
51943                                         int osize = splaytree_size(sc->dirs);
51944  
51945 @@ -298,17 +288,15 @@
51946  
51947         if (revent & FDEVENT_HUP) {
51948                 /* fam closed the connection */
51949 -               srv->stat_cache->fam_fcce_ndx = -1;
51950 -
51951 -               fdevent_event_del(srv->ev, &(sc->fam_fcce_ndx), FAMCONNECTION_GETFD(sc->fam));
51952 -               fdevent_unregister(srv->ev, FAMCONNECTION_GETFD(sc->fam));
51953 +               fdevent_event_del(srv->ev, sc->sock);
51954 +               fdevent_unregister(srv->ev, sc->sock);
51955  
51956                 FAMClose(sc->fam);
51957                 free(sc->fam);
51958  
51959                 sc->fam = NULL;
51960         }
51961 -       
51962 +
51963         return HANDLER_GO_ON;
51964  }
51965  
51966 @@ -332,7 +320,7 @@
51967   *
51968   *
51969   *
51970 - * returns: 
51971 + * returns:
51972   *  - HANDLER_FINISHED on cache-miss (don't forget to reopen the file)
51973   *  - HANDLER_ERROR on stat() failed -> see errno for problem
51974   */
51975 @@ -348,16 +336,16 @@
51976         struct stat st;
51977         size_t k;
51978         int fd;
51979 -#ifdef DEBUG_STAT_CACHE        
51980 +#ifdef DEBUG_STAT_CACHE
51981         size_t i;
51982  #endif
51983  
51984         int file_ndx;
51985         splay_tree *file_node = NULL;
51986  
51987 -       *ret_sce = NULL; 
51988 +       *ret_sce = NULL;
51989  
51990 -       /* 
51991 +       /*
51992          * check if the directory for this file has changed
51993          */
51994  
51995 @@ -366,23 +354,23 @@
51996         file_ndx = hashme(name);
51997         sc->files = splaytree_splay(sc->files, file_ndx);
51998  
51999 -#ifdef DEBUG_STAT_CACHE        
52000 +#ifdef DEBUG_STAT_CACHE
52001         for (i = 0; i < ctrl.used; i++) {
52002                 if (ctrl.ptr[i] == file_ndx) break;
52003         }
52004  #endif
52005  
52006         if (sc->files && (sc->files->key == file_ndx)) {
52007 -#ifdef DEBUG_STAT_CACHE        
52008 +#ifdef DEBUG_STAT_CACHE
52009                 /* it was in the cache */
52010                 assert(i < ctrl.used);
52011  #endif
52012 -               
52013 -               /* we have seen this file already and 
52014 +
52015 +               /* we have seen this file already and
52016                  * don't stat() it again in the same second */
52017  
52018                 file_node = sc->files;
52019 -               
52020 +
52021                 sce = file_node->data;
52022  
52023                 /* check if the name is the same, we might have a collision */
52024 @@ -390,7 +378,7 @@
52025                 if (buffer_is_equal(name, sce->name)) {
52026                         if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_SIMPLE) {
52027                                 if (sce->stat_ts == srv->cur_ts) {
52028 -                                       *ret_sce = sce; 
52029 +                                       *ret_sce = sce;
52030                                         return HANDLER_GO_ON;
52031                                 }
52032                         }
52033 @@ -400,15 +388,15 @@
52034                          * file_node is used by the FAM check below to see if we know this file
52035                          * and if we can save a stat().
52036                          *
52037 -                        * BUT, the sce is not reset here as the entry into the cache is ok, we 
52038 +                        * BUT, the sce is not reset here as the entry into the cache is ok, we
52039                          * it is just not pointing to our requested file.
52040 -                        * 
52041 +                        *
52042                          *  */
52043  
52044                         file_node = NULL;
52045                 }
52046         } else {
52047 -#ifdef DEBUG_STAT_CACHE        
52048 +#ifdef DEBUG_STAT_CACHE
52049                 if (i != ctrl.used) {
52050                         fprintf(stderr, "%s.%d: %08x was already inserted but not found in cache, %s\n", __FILE__, __LINE__, file_ndx, name->ptr);
52051                 }
52052 @@ -424,23 +412,23 @@
52053                 }
52054  
52055                 dir_ndx = hashme(sc->dir_name);
52056 -               
52057 +
52058                 sc->dirs = splaytree_splay(sc->dirs, dir_ndx);
52059 -               
52060 +
52061                 if (sc->dirs && (sc->dirs->key == dir_ndx)) {
52062                         dir_node = sc->dirs;
52063                 }
52064 -               
52065 +
52066                 if (dir_node && file_node) {
52067                         /* we found a file */
52068 -                       
52069 +
52070                         sce = file_node->data;
52071                         fam_dir = dir_node->data;
52072 -                       
52073 +
52074                         if (fam_dir->version == sce->dir_version) {
52075                                 /* the stat()-cache entry is still ok */
52076 -                               
52077 -                               *ret_sce = sce; 
52078 +
52079 +                               *ret_sce = sce;
52080                                 return HANDLER_GO_ON;
52081                         }
52082                 }
52083 @@ -448,7 +436,7 @@
52084  #endif
52085  
52086         /*
52087 -        * *lol* 
52088 +        * *lol*
52089          * - open() + fstat() on a named-pipe results in a (intended) hang.
52090          * - stat() if regualar file + open() to see if we can read from it is better
52091          *
52092 @@ -469,16 +457,16 @@
52093  
52094         if (NULL == sce) {
52095                 int osize = 0;
52096 -                      
52097 +
52098                 if (sc->files) {
52099                         osize = sc->files->size;
52100                 }
52101  
52102                 sce = stat_cache_entry_init();
52103                 buffer_copy_string_buffer(sce->name, name);
52104 -               
52105 -               sc->files = splaytree_insert(sc->files, file_ndx, sce); 
52106 -#ifdef DEBUG_STAT_CACHE        
52107 +
52108 +               sc->files = splaytree_insert(sc->files, file_ndx, sce);
52109 +#ifdef DEBUG_STAT_CACHE
52110                 if (ctrl.size == 0) {
52111                         ctrl.size = 16;
52112                         ctrl.used = 0;
52113 @@ -499,29 +487,29 @@
52114         sce->st = st;
52115         sce->stat_ts = srv->cur_ts;
52116  
52117 -       /* catch the obvious symlinks 
52118 +       /* catch the obvious symlinks
52119          *
52120          * this is not a secure check as we still have a race-condition between
52121 -        * the stat() and the open. We can only solve this by 
52122 +        * the stat() and the open. We can only solve this by
52123          * 1. open() the file
52124          * 2. fstat() the fd
52125          *
52126          * and keeping the file open for the rest of the time. But this can
52127          * only be done at network level.
52128 -        * 
52129 +        *
52130          * */
52131         if (S_ISLNK(st.st_mode) && !con->conf.follow_symlink) {
52132                 return HANDLER_ERROR;
52133         }
52134  
52135 -       if (S_ISREG(st.st_mode)) {      
52136 +       if (S_ISREG(st.st_mode)) {
52137                 /* determine mimetype */
52138                 buffer_reset(sce->content_type);
52139 -               
52140 +
52141                 for (k = 0; k < con->conf.mimetypes->used; k++) {
52142                         data_string *ds = (data_string *)con->conf.mimetypes->data[k];
52143                         buffer *type = ds->key;
52144 -               
52145 +
52146                         if (type->used == 0) continue;
52147  
52148                         /* check if the right side is the same */
52149 @@ -538,8 +526,10 @@
52150                         stat_cache_attr_get(sce->content_type, name->ptr);
52151                 }
52152  #endif
52153 +       } else if (S_ISDIR(st.st_mode)) {
52154 +               etag_create(sce->etag, &(sce->st));
52155         }
52156 -               
52157 +
52158  #ifdef HAVE_FAM_H
52159         if (sc->fam &&
52160             (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM)) {
52161 @@ -549,19 +539,19 @@
52162                         fam_dir->fc = sc->fam;
52163  
52164                         buffer_copy_string_buffer(fam_dir->name, sc->dir_name);
52165 -                       
52166 +
52167                         fam_dir->version = 1;
52168 -                       
52169 +
52170                         fam_dir->req = calloc(1, sizeof(FAMRequest));
52171 -                       
52172 -                       if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr, 
52173 +
52174 +                       if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr,
52175                                                      fam_dir->req, fam_dir)) {
52176 -                               
52177 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
52178 -                                               "monitoring dir failed:", 
52179 -                                               fam_dir->name, 
52180 +
52181 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
52182 +                                               "monitoring dir failed:",
52183 +                                               fam_dir->name,
52184                                                 FamErrlist[FAMErrno]);
52185 -                               
52186 +
52187                                 fam_dir_entry_free(fam_dir);
52188                         } else {
52189                                 int osize = 0;
52190 @@ -570,7 +560,7 @@
52191                                         osize = sc->dirs->size;
52192                                 }
52193  
52194 -                               sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir); 
52195 +                               sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir);
52196                                 assert(sc->dirs);
52197                                 assert(sc->dirs->data == fam_dir);
52198                                 assert(osize == (sc->dirs->size - 1));
52199 @@ -578,9 +568,9 @@
52200                 } else {
52201                         fam_dir = dir_node->data;
52202                 }
52203 -               
52204 +
52205                 /* bind the fam_fc to the stat() cache entry */
52206 -                       
52207 +
52208                 if (fam_dir) {
52209                         sce->dir_version = fam_dir->version;
52210                         sce->dir_ndx     = dir_ndx;
52211 @@ -594,11 +584,11 @@
52212  }
52213  
52214  /**
52215 - * remove stat() from cache which havn't been stat()ed for 
52216 + * remove stat() from cache which havn't been stat()ed for
52217   * more than 10 seconds
52218 - * 
52219   *
52220 - * walk though the stat-cache, collect the ids which are too old 
52221 + *
52222 + * walk though the stat-cache, collect the ids which are too old
52223   * and remove them in a second loop
52224   */
52225  
52226 @@ -639,9 +629,9 @@
52227                 sc->files = splaytree_splay(sc->files, ndx);
52228  
52229                 node = sc->files;
52230 -               
52231 +
52232                 if (node && (node->key == ndx)) {
52233 -#ifdef DEBUG_STAT_CACHE        
52234 +#ifdef DEBUG_STAT_CACHE
52235                         size_t j;
52236                         int osize = splaytree_size(sc->files);
52237                         stat_cache_entry *sce = node->data;
52238 @@ -649,7 +639,7 @@
52239                         stat_cache_entry_free(node->data);
52240                         sc->files = splaytree_delete(sc->files, ndx);
52241  
52242 -#ifdef DEBUG_STAT_CACHE        
52243 +#ifdef DEBUG_STAT_CACHE
52244                         for (j = 0; j < ctrl.used; j++) {
52245                                 if (ctrl.ptr[j] == ndx) {
52246                                         ctrl.ptr[j] = ctrl.ptr[--ctrl.used];
52247 --- ../lighttpd-1.4.11/src/status_counter.c     1970-01-01 03:00:00.000000000 +0300
52248 +++ lighttpd-1.4.12/src/status_counter.c        2006-07-19 20:02:55.000000000 +0300
52249 @@ -0,0 +1,75 @@
52250 +#include <stdlib.h>
52251 +
52252 +#include "status_counter.h"
52253 +/**
52254 + * The status array can carry all the status information you want
52255 + * the key to the array is <module-prefix>.<name>
52256 + * and the values are counters
52257 + *
52258 + * example:
52259 + *   fastcgi.backends        = 10
52260 + *   fastcgi.active-backends = 6
52261 + *   fastcgi.backend.<key>.load = 24
52262 + *   fastcgi.backend.<key>....
52263 + *
52264 + *   fastcgi.backend.<key>.disconnects = ...
52265 + */
52266 +
52267 +static array *counters = NULL;
52268 +
52269 +void status_counter_init(void) {
52270 +       counters = array_init();
52271 +}
52272 +void status_counter_free(void) {
52273 +       array_free(counters);
52274 +}
52275 +
52276 +array *status_counter_get_array(void) {
52277 +       return counters;
52278 +}
52279 +
52280 +data_integer *status_counter_get_counter(const char *s, size_t len) {
52281 +       data_integer *di;
52282 +       array *status = status_counter_get_array();
52283 +
52284 +       if (NULL == (di = (data_integer *)array_get_element(status, s))) {
52285 +               /* not found, create it */
52286 +
52287 +               if (NULL == (di = (data_integer *)array_get_unused_element(status, TYPE_INTEGER))) {
52288 +                       di = data_integer_init();
52289 +               }
52290 +               buffer_copy_string_len(di->key, s, len);
52291 +               di->value = 0;
52292 +
52293 +               array_insert_unique(status, (data_unset *)di);
52294 +       }
52295 +       return di;
52296 +}
52297 +
52298 +/* dummies of the statistic framework functions
52299 + * they will be moved to a statistics.c later */
52300 +int status_counter_inc(const char *s, size_t len) {
52301 +       data_integer *di = status_counter_get_counter(s, len);
52302 +
52303 +       di->value++;
52304 +
52305 +       return 0;
52306 +}
52307 +
52308 +int status_counter_dec(const char *s, size_t len) {
52309 +       data_integer *di = status_counter_get_counter(s, len);
52310 +
52311 +       if (di->value > 0) di->value--;
52312 +
52313 +       return 0;
52314 +}
52315 +
52316 +int status_counter_set(const char *s, size_t len, int val) {
52317 +       data_integer *di = status_counter_get_counter(s, len);
52318 +
52319 +       di->value = val;
52320 +
52321 +       return 0;
52322 +}
52323 +
52324 +
52325 --- ../lighttpd-1.4.11/src/status_counter.h     1970-01-01 03:00:00.000000000 +0300
52326 +++ lighttpd-1.4.12/src/status_counter.h        2006-07-19 20:02:55.000000000 +0300
52327 @@ -0,0 +1,16 @@
52328 +#ifndef _STATUS_COUNTER_H_
52329 +#define _STATUS_COUNTER_H_
52330 +
52331 +#include <sys/types.h>
52332 +
52333 +#include "array.h"
52334 +
52335 +void status_counter_init(void);
52336 +void status_counter_free(void);
52337 +array *status_counter_get_array(void);
52338 +data_integer *status_counter_get_counter(const char *s, size_t len);
52339 +int status_counter_inc(const char *s, size_t len);
52340 +int status_counter_dec(const char *s, size_t len);
52341 +int status_counter_set(const char *s, size_t len, int val);
52342 +
52343 +#endif 
52344 --- ../lighttpd-1.4.11/src/stream.c     2005-09-23 21:50:15.000000000 +0300
52345 +++ lighttpd-1.4.12/src/stream.c        2006-07-16 00:26:04.000000000 +0300
52346 @@ -1,7 +1,6 @@
52347  #include <sys/types.h>
52348  #include <sys/stat.h>
52349  
52350 -#include <unistd.h> 
52351  #include <fcntl.h>
52352  
52353  #include "stream.h"
52354 @@ -10,6 +9,7 @@
52355  #endif
52356  
52357  #include "sys-mmap.h"
52358 +#include "sys-files.h"
52359  
52360  #ifndef O_BINARY
52361  # define O_BINARY 0
52362 @@ -19,39 +19,39 @@
52363         struct stat st;
52364  #ifdef HAVE_MMAP
52365         int fd;
52366 -#elif defined __WIN32
52367 +#elif defined _WIN32
52368         HANDLE *fh, *mh;
52369         void *p;
52370  #endif
52371  
52372         f->start = NULL;
52373 -       
52374 +
52375         if (-1 == stat(fn->ptr, &st)) {
52376                 return -1;
52377         }
52378 -       
52379 +
52380         f->size = st.st_size;
52381  
52382  #ifdef HAVE_MMAP
52383         if (-1 == (fd = open(fn->ptr, O_RDONLY | O_BINARY))) {
52384                 return -1;
52385         }
52386 -       
52387 +
52388         f->start = mmap(0, f->size, PROT_READ, MAP_SHARED, fd, 0);
52389 -       
52390 +
52391         close(fd);
52392 -       
52393 +
52394         if (MAP_FAILED == f->start) {
52395                 return -1;
52396         }
52397  
52398 -#elif defined __WIN32
52399 -       fh = CreateFile(fn->ptr, 
52400 -                       GENERIC_READ, 
52401 -                       FILE_SHARE_READ, 
52402 -                       NULL, 
52403 -                       OPEN_EXISTING, 
52404 -                       FILE_ATTRIBUTE_READONLY, 
52405 +#elif defined _WIN32
52406 +       fh = CreateFile(fn->ptr,
52407 +                       GENERIC_READ,
52408 +                       FILE_SHARE_READ,
52409 +                       NULL,
52410 +                       OPEN_EXISTING,
52411 +                       FILE_ATTRIBUTE_READONLY,
52412                         NULL);
52413  
52414         if (!fh) return -1;
52415 @@ -66,7 +66,7 @@
52416         if (!mh) {
52417                 LPVOID lpMsgBuf;
52418                 FormatMessage(
52419 -                       FORMAT_MESSAGE_ALLOCATE_BUFFER | 
52420 +                       FORMAT_MESSAGE_ALLOCATE_BUFFER |
52421                         FORMAT_MESSAGE_FROM_SYSTEM,
52422                         NULL,
52423                         GetLastError(),
52424 @@ -76,7 +76,7 @@
52425  
52426                 return -1;
52427         }
52428 -       
52429 +
52430         p = MapViewOfFile(mh,
52431                         FILE_MAP_READ,
52432                         0,
52433 @@ -87,9 +87,9 @@
52434  
52435         f->start = p;
52436  #else
52437 -# error no mmap found  
52438 +# error no mmap found
52439  #endif
52440 -       
52441 +
52442         return 0;
52443  }
52444  
52445 --- ../lighttpd-1.4.11/src/sys-files.h  1970-01-01 03:00:00.000000000 +0300
52446 +++ lighttpd-1.4.12/src/sys-files.h     2006-07-16 00:26:04.000000000 +0300
52447 @@ -0,0 +1,67 @@
52448 +#ifndef _SYS_FILES_H_
52449 +#define _SYS_FILES_H_
52450 +
52451 +#define DIR_SEPERATOR_UNIX '/'
52452 +#define DIR_SEPERATOR_WIN '\\'
52453 +
52454 +#ifdef _WIN32
52455 +#include <windows.h>
52456 +#include <io.h>     /* open */
52457 +#include <direct.h> /* chdir */
52458 +
52459 +#include "buffer.h"
52460 +
52461 +#define DIR_SEPERATOR DIR_SEPERATOR_WIN
52462 +
52463 +#define __S_ISTYPE(mode, mask)  (((mode) & _S_IFMT) == (mask))
52464 +
52465 +#define S_ISDIR(mode)    __S_ISTYPE((mode), _S_IFDIR)
52466 +#define S_ISCHR(mode)    __S_ISTYPE((mode), _S_IFCHR)
52467 +#define S_ISBLK(mode)    __S_ISTYPE((mode), _S_IFBLK)
52468 +#define S_ISREG(mode)    __S_ISTYPE((mode), _S_IFREG)
52469 +/* we don't support symlinks */
52470 +#define S_ISLNK(mode)    0
52471 +
52472 +#define lstat stat
52473 +#define mkstemp mktemp
52474 +#define mkdir(x, y) mkdir(x)
52475 +
52476 +struct dirent {
52477 +    const char *d_name;
52478 +};
52479 +
52480 +typedef struct {
52481 +    HANDLE h;
52482 +    WIN32_FIND_DATA finddata;
52483 +    struct dirent dent;
52484 +} DIR;
52485 +
52486 +DIR *opendir(const char *dn);
52487 +struct dirent *readdir(DIR *d);
52488 +void closedir(DIR *d);
52489 +
52490 +buffer *filename_unix2local(buffer *b);
52491 +buffer *pathname_unix2local(buffer *b);
52492 +
52493 +#else
52494 +#include <unistd.h>
52495 +#include <dirent.h>
52496 +
52497 +#define DIR_SEPERATOR DIR_SEPERATOR_UNIX
52498 +
52499 +#define filename_unix2local(x) (x)
52500 +#define pathname_unix2local(x) (x)
52501 +#endif
52502 +
52503 +#define PATHNAME_APPEND_SLASH(x) \
52504 +       if (x->used > 1 && x->ptr[x->used - 2] != DIR_SEPERATOR) { \
52505 +        char sl[2] = { DIR_SEPERATOR, 0 }; \
52506 +        BUFFER_APPEND_STRING_CONST(x, sl); \
52507 +    }
52508 +
52509 +#ifndef O_LARGEFILE
52510 +# define O_LARGEFILE 0
52511 +#endif
52512 +
52513 +#endif
52514 +
52515 --- ../lighttpd-1.4.11/src/sys-mmap.h   2005-08-11 01:26:34.000000000 +0300
52516 +++ lighttpd-1.4.12/src/sys-mmap.h      2006-07-16 00:26:04.000000000 +0300
52517 @@ -1,7 +1,7 @@
52518  #ifndef WIN32_MMAP_H
52519  #define WIN32_MMAP_H
52520  
52521 -#ifdef __WIN32
52522 +#ifdef _WIN32
52523  
52524  #define MAP_FAILED -1
52525  #define PROT_SHARED 0
52526 --- ../lighttpd-1.4.11/src/sys-process.h        1970-01-01 03:00:00.000000000 +0300
52527 +++ lighttpd-1.4.12/src/sys-process.h   2006-07-16 00:26:04.000000000 +0300
52528 @@ -0,0 +1,17 @@
52529 +#ifndef _SYS_PROCESS_H_
52530 +#define _SYS_PROCESS_H_
52531 +
52532 +#ifdef _WIN32
52533 +#include <process.h>
52534 +#define pid_t int
52535 +/* win32 has no fork() */
52536 +#define kill(x, y)
52537 +#define getpid() 0
52538 +
52539 +#else
52540 +#include <sys/wait.h>
52541 +#include <unistd.h>
52542 +#endif
52543 +
52544 +#endif
52545 +
52546 --- ../lighttpd-1.4.11/src/sys-socket.h 2005-08-11 01:26:39.000000000 +0300
52547 +++ lighttpd-1.4.12/src/sys-socket.h    2006-07-19 20:02:55.000000000 +0300
52548 @@ -1,15 +1,26 @@
52549  #ifndef WIN32_SOCKET_H
52550  #define WIN32_SOCKET_H
52551  
52552 -#ifdef __WIN32
52553 +#ifdef _WIN32
52554  
52555  #include <winsock2.h>
52556  
52557  #define ECONNRESET WSAECONNRESET
52558  #define EINPROGRESS WSAEINPROGRESS
52559  #define EALREADY WSAEALREADY
52560 +#define ENOTCONN WSAENOTCONN
52561 +#define EWOULDBLOCK WSAEWOULDBLOCK
52562  #define ioctl ioctlsocket
52563  #define hstrerror(x) ""
52564 +#define STDIN_FILENO 0
52565 +#define STDOUT_FILENO 1
52566 +#define STDERR_FILENO 2
52567 +#define ssize_t int
52568 +
52569 +int inet_aton(const char *cp, struct in_addr *inp);
52570 +#define HAVE_INET_ADDR
52571 +#undef HAVE_INET_ATON
52572 +
52573  #else
52574  #include <sys/socket.h>
52575  #include <sys/ioctl.h>
52576 @@ -18,7 +29,29 @@
52577  #include <sys/un.h>
52578  #include <arpa/inet.h>
52579  
52580 +#ifndef SUN_LEN
52581 +#define SUN_LEN(su) \
52582 +        (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
52583 +#endif
52584 +
52585 +#define closesocket(x) close(x)
52586 +
52587  #include <netdb.h>
52588 +#endif /* !_WIN32 */
52589 +
52590 +#ifdef HAVE_INET_NTOP
52591 +# define HAVE_IPV6
52592 +#endif
52593 +
52594 +typedef union {
52595 +#ifdef HAVE_IPV6
52596 +       struct sockaddr_in6 ipv6;
52597 +#endif
52598 +       struct sockaddr_in ipv4;
52599 +#ifdef HAVE_SYS_UN_H
52600 +       struct sockaddr_un un;
52601  #endif
52602 +       struct sockaddr plain;
52603 +} sock_addr;
52604  
52605  #endif
52606 --- ../lighttpd-1.4.11/src/sys-strings.h        1970-01-01 03:00:00.000000000 +0300
52607 +++ lighttpd-1.4.12/src/sys-strings.h   2006-07-16 00:26:03.000000000 +0300
52608 @@ -0,0 +1,11 @@
52609 +#ifndef _SYS_STRINGS_H_
52610 +#define _SYS_STRINGS_H_
52611 +
52612 +#ifdef _WIN32
52613 +#define strcasecmp stricmp
52614 +#define strncasecmp strnicmp
52615 +#define strtoll(p, e, b) _strtoi64(p, e, b)
52616 +#endif
52617 +
52618 +#endif
52619 +
52620 --- ../lighttpd-1.4.11/tests/LightyTest.pm      2006-01-14 20:32:31.000000000 +0200
52621 +++ lighttpd-1.4.12/tests/LightyTest.pm 2006-07-18 13:03:40.000000000 +0300
52622 @@ -87,14 +87,16 @@
52623         # pre-process configfile if necessary
52624         #
52625  
52626 -       unlink($self->{TESTDIR}."/tmp/cfg.file");
52627 -       system("cat ".$self->{SRCDIR}."/".$self->{CONFIGFILE}.' | perl -pe "s#\@SRCDIR\@#'.$self->{BASEDIR}.'/tests/#" > '.$self->{TESTDIR}.'/tmp/cfg.file');
52628 +       $ENV{'SRCDIR'} = $self->{BASEDIR}.'/tests';
52629 +       $ENV{'PORT'} = $self->{PORT};
52630  
52631         unlink($self->{LIGHTTPD_PIDFILE});
52632 -       if (1) {
52633 -               system($self->{LIGHTTPD_PATH}." -f ".$self->{TESTDIR}."/tmp/cfg.file -m ".$self->{MODULES_PATH});
52634 +       if (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'strace') {
52635 +               system("strace -tt -s 512 -o strace ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH}." &");
52636 +       } elsif (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'valgrind') {
52637 +               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}." &");
52638         } else {
52639 -               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}." &");
52640 +               system($self->{LIGHTTPD_PATH}." -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH});
52641         }
52642  
52643         select(undef, undef, undef, 0.1);
52644 @@ -184,7 +186,7 @@
52645                                         (my $h = $1) =~ tr/[A-Z]/[a-z]/;
52646  
52647                                         if (defined $resp_hdr{$h}) {
52648 -                                               diag(sprintf("header %s is duplicated: %s and %s\n",
52649 +                                               diag(sprintf("header '%s' is duplicated: '%s' and '%s'\n",
52650                                                              $h, $resp_hdr{$h}, $2));
52651                                         } else {
52652                                                 $resp_hdr{$h} = $2;
52653 @@ -196,6 +198,9 @@
52654                         }
52655                 }
52656  
52657 +               $t->{etag} = $resp_hdr{'etag'};
52658 +               $t->{date} = $resp_hdr{'date'};
52659 +
52660                 # check length
52661                 if (defined $resp_hdr{"content-length"}) {
52662                         $resp_body = substr($lines, 0, $resp_hdr{"content-length"});
52663 --- ../lighttpd-1.4.11/tests/Makefile.am        2005-09-16 15:48:40.000000000 +0300
52664 +++ lighttpd-1.4.12/tests/Makefile.am   2006-07-16 00:26:05.000000000 +0300
52665 @@ -39,10 +39,18 @@
52666        mod-redirect.t \
52667        mod-userdir.t \
52668        mod-rewrite.t \
52669 +      mod-proxy.t \
52670        request.t \
52671        mod-ssi.t \
52672        LightyTest.pm \
52673 -      mod-setenv.t 
52674 +      mod-setenv.t \
52675 +      lowercase.t \
52676 +      lowercase.conf \
52677 +      proxy.conf \
52678 +      cachable.t \
52679 +      default.conf \
52680 +      proxy-backend-1.conf \
52681 +      proxy-backend-2.conf 
52682  
52683  
52684  TESTS_ENVIRONMENT=$(srcdir)/wrapper.sh $(srcdir) $(top_builddir) 
52685 --- ../lighttpd-1.4.11/tests/bug-06.conf        2005-08-27 17:44:19.000000000 +0300
52686 +++ lighttpd-1.4.12/tests/bug-06.conf   2006-07-16 00:26:04.000000000 +0300
52687 @@ -1,5 +1,5 @@
52688 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52689 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52690 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52691 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52692  
52693  ## bind to port (default: 80)
52694  server.port                 = 2048
52695 @@ -8,7 +8,7 @@
52696  
52697  ## bind to localhost (default: all interfaces)
52698  server.bind                = "localhost"
52699 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52700 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52701  server.name                = "www.example.org"
52702  server.tag                 = "Apache 1.3.29"
52703  
52704 @@ -59,7 +59,7 @@
52705  ######################## MODULE CONFIG ############################
52706  
52707  
52708 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52709 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52710  
52711  mimetype.assign             = ( ".png"  => "image/png", 
52712                                  ".jpg"  => "image/jpeg",
52713 @@ -77,7 +77,7 @@
52714                                 ".c"    => "text/plain",
52715                                 ".conf" => "text/plain" )
52716  
52717 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52718 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52719  compress.filetype           = ("text/plain", "text/html")
52720  
52721  setenv.add-environment      = ( "TRAC_ENV" => "foo")
52722 @@ -90,7 +90,7 @@
52723                                     "host" => "127.0.0.1",
52724                                     "port" => 1026,
52725  #                                  "mode" => "authorizer",
52726 -#                                  "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
52727 +#                                  "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
52728                                   )
52729                                 )
52730                               )
52731 @@ -106,7 +106,7 @@
52732  ssl.pemfile                 = "server.pem"
52733  
52734  auth.backend                = "plain"
52735 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52736 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52737  auth.backend.plain.groupfile = "lighttpd.group"
52738  
52739  auth.backend.ldap.hostname  = "localhost"
52740 @@ -149,15 +149,15 @@
52741  status.config-url           = "/server-config"
52742  
52743  simple-vhost.document-root  = "pages"
52744 -simple-vhost.server-root    = "@SRCDIR@/tmp/lighttpd/servers/"
52745 +simple-vhost.server-root    = env.SRCDIR + "/tmp/lighttpd/servers/"
52746  simple-vhost.default-host   = "www.example.org"
52747  
52748  $HTTP["host"] == "vvv.example.org" {
52749 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52750 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52751  }
52752  
52753  $HTTP["host"] == "zzz.example.org" {
52754 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52755 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52756    server.name = "zzz.example.org"
52757  }
52758  
52759 --- ../lighttpd-1.4.11/tests/bug-12.conf        2005-08-27 17:44:19.000000000 +0300
52760 +++ lighttpd-1.4.12/tests/bug-12.conf   2006-07-16 00:26:04.000000000 +0300
52761 @@ -1,5 +1,5 @@
52762 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52763 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52764 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52765 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52766  
52767  ## bind to port (default: 80)
52768  server.port                 = 2048
52769 @@ -8,7 +8,7 @@
52770  
52771  ## bind to localhost (default: all interfaces)
52772  server.bind                = "localhost"
52773 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52774 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52775  server.name                = "www.example.org"
52776  server.tag                 = "Apache 1.3.29"
52777  
52778 @@ -61,7 +61,7 @@
52779  ######################## MODULE CONFIG ############################
52780  
52781  
52782 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52783 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52784  
52785  mimetype.assign             = ( ".png"  => "image/png", 
52786                                  ".jpg"  => "image/jpeg",
52787 @@ -79,7 +79,7 @@
52788                                 ".c"    => "text/plain",
52789                                 ".conf" => "text/plain" )
52790  
52791 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52792 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52793  compress.filetype           = ("text/plain", "text/html")
52794  
52795  setenv.add-environment      = ( "TRAC_ENV" => "foo")
52796 @@ -92,7 +92,7 @@
52797                                     "host" => "127.0.0.1",
52798                                     "port" => 1026,
52799  #                                  "mode" => "authorizer",
52800 -#                                  "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
52801 +#                                  "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
52802                                   )
52803                                 )
52804                               )
52805 @@ -108,7 +108,7 @@
52806  ssl.pemfile                 = "server.pem"
52807  
52808  auth.backend                = "plain"
52809 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52810 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52811  auth.backend.plain.groupfile = "lighttpd.group"
52812  
52813  auth.backend.ldap.hostname  = "localhost"
52814 @@ -151,15 +151,15 @@
52815  status.config-url           = "/server-config"
52816  
52817  simple-vhost.document-root  = "pages"
52818 -simple-vhost.server-root    = "@SRCDIR@/tmp/lighttpd/servers/"
52819 +simple-vhost.server-root    = env.SRCDIR + "/tmp/lighttpd/servers/"
52820  simple-vhost.default-host   = "www.example.org"
52821  
52822  $HTTP["host"] == "vvv.example.org" {
52823 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52824 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52825  }
52826  
52827  $HTTP["host"] == "zzz.example.org" {
52828 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52829 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52830    server.name = "zzz.example.org"
52831  }
52832  
52833 --- ../lighttpd-1.4.11/tests/cachable.t 1970-01-01 03:00:00.000000000 +0300
52834 +++ lighttpd-1.4.12/tests/cachable.t    2006-07-18 13:03:40.000000000 +0300
52835 @@ -0,0 +1,112 @@
52836 +#!/usr/bin/env perl
52837 +BEGIN {
52838 +    # add current source dir to the include-path
52839 +    # we need this for make distcheck
52840 +   (my $srcdir = $0) =~ s#/[^/]+$#/#;
52841 +   unshift @INC, $srcdir;
52842 +}
52843 +
52844 +use strict;
52845 +use IO::Socket;
52846 +use Test::More tests => 12;
52847 +use LightyTest;
52848 +
52849 +my $tf = LightyTest->new();
52850 +my $t;
52851 +
52852 +$tf->{CONFIGFILE} = 'lighttpd.conf';
52853 +    
52854 +ok($tf->start_proc == 0, "Starting lighttpd") or die();
52855 +
52856 +## check if If-Modified-Since, If-None-Match works
52857 +
52858 +$t->{REQUEST}  = ( <<EOF
52859 +GET / HTTP/1.0
52860 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT
52861 +EOF
52862 + );
52863 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52864 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-Modified-Since');
52865 +
52866 +$t->{REQUEST}  = ( <<EOF
52867 +GET / HTTP/1.0
52868 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
52869 +EOF
52870 + );
52871 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+Last-Modified' => ''} ];
52872 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-Modified-Since, comment');
52873 +
52874 +my $now = $t->{date};
52875 +
52876 +$t->{REQUEST}  = ( <<EOF
52877 +GET / HTTP/1.0
52878 +If-Modified-Since: $now
52879 +EOF
52880 + );
52881 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52882 +ok($tf->handle_http($t) == 0, 'Conditional GET - new If-Modified-Since');
52883 +
52884 +$t->{REQUEST}  = ( <<EOF
52885 +GET / HTTP/1.0
52886 +If-Modified-Since: $now; foo
52887 +EOF
52888 + );
52889 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52890 +ok($tf->handle_http($t) == 0, 'Conditional GET - new If-Modified-Since, comment');
52891 +
52892 +$t->{REQUEST}  = ( <<EOF
52893 +GET / HTTP/1.0
52894 +If-None-Match: foo
52895 +EOF
52896 + );
52897 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+ETag' => ''} ];
52898 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-None-Match');
52899 +
52900 +my $etag = $t->{etag};
52901 +
52902 +$t->{REQUEST}  = ( <<EOF
52903 +GET / HTTP/1.0
52904 +If-None-Match: $etag
52905 +EOF
52906 + );
52907 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52908 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-None-Match');
52909 +
52910 +$t->{REQUEST}  = ( <<EOF
52911 +GET / HTTP/1.0
52912 +If-None-Match: $etag
52913 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
52914 +EOF
52915 + );
52916 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52917 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + old Last-Modified');
52918 +
52919 +$t->{REQUEST}  = ( <<EOF
52920 +GET / HTTP/1.0
52921 +If-None-Match: $etag
52922 +If-Modified-Since: $now; foo
52923 +EOF
52924 + );
52925 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52926 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag, Last-Modified + comment');
52927 +
52928 +$t->{REQUEST}  = ( <<EOF
52929 +GET / HTTP/1.0
52930 +If-None-Match: Foo
52931 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
52932 +EOF
52933 + );
52934 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52935 +ok($tf->handle_http($t) == 0, 'Conditional GET - old ETAG + old Last-Modified');
52936 +
52937 +$t->{REQUEST}  = ( <<EOF
52938 +GET / HTTP/1.0
52939 +If-None-Match: $etag
52940 +If-Modified-Since: $now foo
52941 +EOF
52942 + );
52943 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 412 } ];
52944 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + Last-Modified + overlong timestamp');
52945 +
52946 +ok($tf->stop_proc == 0, "Stopping lighttpd");
52947 +
52948 --- ../lighttpd-1.4.11/tests/condition.conf     2005-08-27 17:44:19.000000000 +0300
52949 +++ lighttpd-1.4.12/tests/condition.conf        2006-07-16 00:26:05.000000000 +0300
52950 @@ -2,15 +2,15 @@
52951  debug.log-request-handling = "enable"
52952  debug.log-condition-handling = "enable"
52953  
52954 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52955 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52956 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52957 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52958  
52959  ## bind to port (default: 80)
52960  server.port                 = 2048
52961  
52962  ## bind to localhost (default: all interfaces)
52963  server.bind                = "localhost"
52964 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52965 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52966  server.name                = "www.example.org"
52967  server.tag                 = "Apache 1.3.29"
52968  
52969 @@ -22,25 +22,25 @@
52970  ######################## MODULE CONFIG ############################
52971  
52972  
52973 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52974 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52975  
52976  mimetype.assign             = ( ".html" => "text/html" )
52977  
52978  url.redirect = ("^" => "/default")
52979  
52980  $HTTP["host"] == "www.example.org" {
52981 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52982 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52983    server.name = "www.example.org"
52984    url.redirect = ("^" => "/match_1")
52985  }
52986  else $HTTP["host"] == "test1.example.org" {
52987 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52988 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52989    server.name = "test1.example.org"
52990    url.redirect = ("^" => "/match_2")
52991  }
52992  # comments
52993  else $HTTP["host"] == "test2.example.org" {
52994 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52995 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52996    server.name = "test2.example.org"
52997    url.redirect = ("^" => "/match_3")
52998  }
52999 @@ -48,7 +48,7 @@
53000          # comments
53001  
53002  else $HTTP["host"] == "test3.example.org" {
53003 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53004 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53005    server.name = "test3.example.org"
53006    url.redirect = ("^" => "/match_4")
53007  
53008 --- ../lighttpd-1.4.11/tests/core-keepalive.t   2005-11-17 15:54:19.000000000 +0200
53009 +++ lighttpd-1.4.12/tests/core-keepalive.t      2006-07-16 00:26:05.000000000 +0300
53010 @@ -40,7 +40,7 @@
53011  
53012  GET /12345.txt HTTP/1.0
53013  Host: 123.example.org
53014 -Connection: keep-alive
53015 +Connection: close
53016  EOF
53017   );
53018  $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } , { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53019 --- ../lighttpd-1.4.11/tests/default.conf       1970-01-01 03:00:00.000000000 +0300
53020 +++ lighttpd-1.4.12/tests/default.conf  2006-07-16 00:26:05.000000000 +0300
53021 @@ -0,0 +1,111 @@
53022 +server.name                = "www.example.org"
53023 +
53024 +## bind to port (default: 80)
53025 +server.port                 = env.PORT
53026 +
53027 +
53028 +server.dir-listing          = "enable"
53029 +
53030 +#server.event-handler        = "linux-sysepoll"
53031 +#server.event-handler        = "linux-rtsig"
53032 +
53033 +server.modules              = ( 
53034 +                               "mod_rewrite",
53035 +                               "mod_setenv",
53036 +                               "mod_access", 
53037 +                               "mod_auth",
53038 +                               "mod_status", 
53039 +                               "mod_expire",
53040 +                               "mod_simple_vhost",
53041 +                               "mod_redirect", 
53042 +                               "mod_secdownload",
53043 +                               "mod_ssi",
53044 +                               "mod_fastcgi",
53045 +                               "mod_proxy",
53046 +                               "mod_cgi",
53047 +                               "mod_compress",
53048 +                               "mod_userdir",
53049 +                               "mod_accesslog" ) 
53050 +
53051 +server.indexfiles           = ( "index.php", "index.html", 
53052 +                                "index.htm", "default.htm" )
53053 +
53054 +ssi.extension = ( ".shtml" )
53055 +
53056 +######################## MODULE CONFIG ############################
53057 +
53058 +
53059 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
53060 +server.errorlog             = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53061 +
53062 +mimetype.assign             = ( ".png"  => "image/png", 
53063 +                                ".jpg"  => "image/jpeg",
53064 +                                ".jpeg" => "image/jpeg",
53065 +                                ".gif"  => "image/gif",
53066 +                                ".html" => "text/html",
53067 +                                ".htm"  => "text/html",
53068 +                                ".pdf"  => "application/pdf",
53069 +                                ".swf"  => "application/x-shockwave-flash",
53070 +                                ".spl"  => "application/futuresplash",
53071 +                                ".txt"  => "text/plain",
53072 +                                ".tar.gz" =>   "application/x-tgz",
53073 +                                ".tgz"  => "application/x-tgz",
53074 +                                ".gz"   => "application/x-gzip",
53075 +                               ".c"    => "text/plain",
53076 +                               ".conf" => "text/plain" )
53077 +
53078 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
53079 +compress.filetype           = ("text/plain", "text/html")
53080 +
53081 +setenv.add-environment      = ( "TRAC_ENV" => "tracenv", "SETENV" => "setenv")
53082 +
53083 +cgi.assign                  = ( ".pl"  => "/usr/bin/perl",
53084 +                                ".cgi" => "/usr/bin/perl",
53085 +                               ".py"  => "/usr/bin/python" )
53086 +                       
53087 +userdir.include-user = ( "jan" )
53088 +userdir.path = "/"
53089 +
53090 +ssl.engine                  = "disable"
53091 +ssl.pemfile                 = "server.pem"
53092 +
53093 +auth.backend                = "plain"
53094 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53095 +auth.backend.htpasswd.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.htpasswd"
53096 +auth.backend.plain.groupfile = "lighttpd.group"
53097 +
53098 +auth.backend.ldap.hostname  = "localhost"
53099 +auth.backend.ldap.base-dn   = "dc=my-domain,dc=com"
53100 +auth.backend.ldap.filter    = "(uid=$)"
53101 +
53102 +auth.require                = ( "/server-status" => 
53103 +                                ( 
53104 +                                 "method"  => "digest",
53105 +                                 "realm"   => "download archiv",
53106 +                                 "require" => "valid-user"
53107 +                               ),
53108 +                               "/auth.php" => 
53109 +                                ( 
53110 +                                 "method"  => "basic",
53111 +                                 "realm"   => "download archiv",
53112 +                                 "require" => "user=jan"
53113 +                               ),
53114 +                               "/server-config" => 
53115 +                                ( 
53116 +                                 "method"  => "basic",
53117 +                                 "realm"   => "download archiv",
53118 +                                 "require" => "valid-user"
53119 +                               )
53120 +                              )
53121 +
53122 +url.access-deny             = ( "~", ".inc")
53123 +
53124 +url.redirect                = ( "^/redirect/$" => "http://localhost:2048/" )
53125 +
53126 +url.rewrite                = ( "^/rewrite/foo($|\?.+)" => "/indexfile/rewrite.php$1",
53127 +                               "^/rewrite/bar(?:$|\?(.+))" => "/indexfile/rewrite.php?bar&$1" )
53128 +
53129 +#### status module
53130 +status.status-url           = "/server-status"
53131 +status.config-url           = "/server-config"
53132 +
53133 --- ../lighttpd-1.4.11/tests/docroot/www/dummydir/.svn/entries  2006-03-09 19:21:49.000000000 +0200
53134 +++ lighttpd-1.4.12/tests/docroot/www/dummydir/.svn/entries     2006-07-20 01:14:57.000000000 +0300
53135 @@ -9,5 +9,6 @@
53136     last-author="jan"
53137     kind="dir"
53138     uuid="152afb58-edef-0310-8abb-c4023f1b3aa9"
53139 -   revision="1040"/>
53140 +   repos="svn://svn.lighttpd.net/lighttpd"
53141 +   revision="1211"/>
53142  </wc-entries>
53143 --- ../lighttpd-1.4.11/tests/fastcgi-10.conf    2005-08-31 23:36:34.000000000 +0300
53144 +++ lighttpd-1.4.12/tests/fastcgi-10.conf       2006-07-16 00:26:04.000000000 +0300
53145 @@ -1,12 +1,12 @@
53146 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53147 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
53148 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53149 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53150  
53151  ## bind to port (default: 80)
53152  server.port                 = 2048
53153  
53154  ## bind to localhost (default: all interfaces)
53155  server.bind                = "localhost"
53156 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
53157 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53158  server.name                = "www.example.org"
53159  server.tag                 = "Apache 1.3.29"
53160  
53161 @@ -44,7 +44,7 @@
53162  ######################## MODULE CONFIG ############################
53163  
53164  
53165 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
53166 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
53167  
53168  mimetype.assign             = ( ".png"  => "image/png", 
53169                                  ".jpg"  => "image/jpeg",
53170 @@ -62,7 +62,7 @@
53171                                 ".c"    => "text/plain",
53172                                 ".conf" => "text/plain" )
53173  
53174 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
53175 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
53176  compress.filetype           = ("text/plain", "text/html")
53177  
53178  fastcgi.debug               = 0
53179 @@ -85,7 +85,7 @@
53180  ssl.pemfile                 = "server.pem"
53181  
53182  auth.backend                = "plain"
53183 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
53184 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53185  auth.backend.plain.groupfile = "lighttpd.group"
53186  
53187  auth.backend.ldap.hostname  = "localhost"
53188 @@ -128,11 +128,11 @@
53189  status.config-url           = "/server-config"
53190  
53191  $HTTP["host"] == "vvv.example.org" {
53192 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53193 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53194  }
53195  
53196  $HTTP["host"] == "zzz.example.org" {
53197 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53198 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53199    server.name = "zzz.example.org"
53200  }
53201  
53202 --- ../lighttpd-1.4.11/tests/fastcgi-13.conf    2006-01-03 12:38:17.000000000 +0200
53203 +++ lighttpd-1.4.12/tests/fastcgi-13.conf       2006-07-18 13:03:40.000000000 +0300
53204 @@ -1,5 +1,5 @@
53205 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53206 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
53207 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53208 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53209  
53210  debug.log-request-header   = "enable"
53211  debug.log-response-header  = "enable"
53212 @@ -10,7 +10,7 @@
53213  
53214  ## bind to localhost (default: all interfaces)
53215  server.bind                = "localhost"
53216 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
53217 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53218  server.name                = "www.example.org"
53219  server.tag                 = "Apache 1.3.29"
53220  
53221 @@ -59,7 +59,7 @@
53222  ######################## MODULE CONFIG ############################
53223  
53224  
53225 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
53226 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
53227  
53228  mimetype.assign             = ( ".png"  => "image/png", 
53229                                  ".jpg"  => "image/jpeg",
53230 @@ -77,7 +77,7 @@
53231                                 ".c"    => "text/plain",
53232                                 ".conf" => "text/plain" )
53233  
53234 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
53235 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
53236  compress.filetype           = ("text/plain", "text/html")
53237  
53238  fastcgi.debug               = 0
53239 @@ -85,7 +85,7 @@
53240                                    "grisu" => ( 
53241                                     "host" => "127.0.0.1",
53242                                     "port" => 1048,
53243 -                                   "bin-path" => "/home/jan/Documents/php-5.1.0/sapi/cgi/php -c /usr/local/lib/php.ini",
53244 +                                   "bin-path" => "/home/jan/Documents/php-5.1.4/sapi/cgi/php -c /usr/local/lib/php.ini",
53245                                     "bin-copy-environment" => ( "PATH", "SHELL", "USER" ),
53246                                   )
53247                                 )
53248 @@ -102,7 +102,7 @@
53249  ssl.pemfile                 = "server.pem"
53250  
53251  auth.backend                = "plain"
53252 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
53253 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53254  auth.backend.plain.groupfile = "lighttpd.group"
53255  
53256  auth.backend.ldap.hostname  = "localhost"
53257 @@ -145,11 +145,11 @@
53258  status.config-url           = "/server-config"
53259  
53260  $HTTP["host"] == "vvv.example.org" {
53261 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53262 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53263  }
53264  
53265  $HTTP["host"] == "zzz.example.org" {
53266 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53267 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53268    server.name = "zzz.example.org"
53269  }
53270  
53271 --- ../lighttpd-1.4.11/tests/fastcgi-auth.conf  2005-08-27 17:44:19.000000000 +0300
53272 +++ lighttpd-1.4.12/tests/fastcgi-auth.conf     2006-07-16 00:26:05.000000000 +0300
53273 @@ -1,5 +1,5 @@
53274 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53275 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
53276 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53277 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53278  
53279  debug.log-request-header   = "enable"
53280  debug.log-response-header  = "enable"
53281 @@ -12,7 +12,7 @@
53282  
53283  ## bind to localhost (default: all interfaces)
53284  server.bind                = "localhost"
53285 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
53286 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53287  server.name                = "www.example.org"
53288  server.tag                 = "Apache 1.3.29"
53289  
53290 @@ -61,7 +61,7 @@
53291  ######################## MODULE CONFIG ############################
53292  
53293  
53294 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
53295 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
53296  
53297  mimetype.assign             = ( ".png"  => "image/png", 
53298                                  ".jpg"  => "image/jpeg",
53299 @@ -79,7 +79,7 @@
53300                                 ".c"    => "text/plain",
53301                                 ".conf" => "text/plain" )
53302  
53303 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
53304 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
53305  compress.filetype           = ("text/plain", "text/html")
53306  
53307  fastcgi.debug               = 0
53308 @@ -87,9 +87,9 @@
53309                                    "grisu" => ( 
53310                                     "host" => "127.0.0.1",
53311                                     "port" => 20000,
53312 -                                   "bin-path" => "@SRCDIR@/fcgi-auth",
53313 +                                   "bin-path" => env.SRCDIR + "/fcgi-auth",
53314                                      "mode" => "authorizer",
53315 -                                    "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
53316 +                                    "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
53317                                     
53318                                   )
53319                                 )
53320 @@ -106,7 +106,7 @@
53321  ssl.pemfile                 = "server.pem"
53322  
53323  auth.backend                = "plain"
53324 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
53325 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53326  auth.backend.plain.groupfile = "lighttpd.group"
53327  
53328  auth.backend.ldap.hostname  = "localhost"
53329 @@ -149,11 +149,11 @@
53330  status.config-url           = "/server-config"
53331  
53332  $HTTP["host"] == "vvv.example.org" {
53333 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53334 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53335  }
53336  
53337  $HTTP["host"] == "zzz.example.org" {
53338 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53339 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53340    server.name = "zzz.example.org"
53341  }
53342  
53343 --- ../lighttpd-1.4.11/tests/fastcgi-responder.conf     2005-08-27 17:44:19.000000000 +0300
53344 +++ lighttpd-1.4.12/tests/fastcgi-responder.conf        2006-07-16 00:26:05.000000000 +0300
53345 @@ -1,5 +1,5 @@
53346 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53347 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
53348 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53349 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53350  
53351  #debug.log-request-header   = "enable"
53352  #debug.log-response-header  = "enable"
53353 @@ -15,7 +15,7 @@
53354  
53355  ## bind to localhost (default: all interfaces)
53356  server.bind                = "localhost"
53357 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
53358 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53359  server.name                = "www.example.org"
53360  server.tag                 = "Apache 1.3.29"
53361  
53362 @@ -64,7 +64,7 @@
53363  ######################## MODULE CONFIG ############################
53364  
53365  
53366 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
53367 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
53368  
53369  mimetype.assign             = ( ".png"  => "image/png", 
53370                                  ".jpg"  => "image/jpeg",
53371 @@ -82,7 +82,7 @@
53372                                 ".c"    => "text/plain",
53373                                 ".conf" => "text/plain" )
53374  
53375 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
53376 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
53377  compress.filetype           = ("text/plain", "text/html")
53378  
53379  fastcgi.debug               = 0
53380 @@ -90,10 +90,11 @@
53381                                    "grisu" => ( 
53382                                     "host" => "127.0.0.1",
53383                                     "port" => 10000,
53384 -                                   "bin-path" => "@SRCDIR@/fcgi-responder",
53385 +                                   "bin-path" => env.SRCDIR + "/fcgi-responder",
53386                                     "check-local" => "disable",
53387                                     "max-procs" => 1,
53388 -                                   "min-procs" => 1
53389 +                                   "min-procs" => 1,
53390 +                                   "allow-x-send-file" => "enable",
53391                                   )
53392                                 )
53393                               )
53394 @@ -109,7 +110,7 @@
53395  ssl.pemfile                 = "server.pem"
53396  
53397  auth.backend                = "plain"
53398 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
53399 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53400  auth.backend.plain.groupfile = "lighttpd.group"
53401  
53402  auth.backend.ldap.hostname  = "localhost"
53403 @@ -152,11 +153,11 @@
53404  status.config-url           = "/server-config"
53405  
53406  $HTTP["host"] == "vvv.example.org" {
53407 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53408 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53409  }
53410  
53411  $HTTP["host"] == "zzz.example.org" {
53412 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53413 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53414    server.name = "zzz.example.org"
53415  }
53416  
53417 --- ../lighttpd-1.4.11/tests/fcgi-responder.c   2005-08-11 01:26:55.000000000 +0300
53418 +++ lighttpd-1.4.12/tests/fcgi-responder.c      2006-07-16 00:26:05.000000000 +0300
53419 @@ -6,11 +6,17 @@
53420  int main () {
53421         int num_requests = 2;
53422         
53423 -       while (num_requests > 0 &&
53424 -              FCGI_Accept() >= 0) {
53425 -               char* p;
53426 -               
53427 -               if (NULL != (p = getenv("QUERY_STRING"))) {
53428 +       while (num_requests > 0 && FCGI_Accept() >= 0) {
53429 +               char* p = NULL;
53430 +               char* doc_root = NULL;
53431 +               char fname[4096];
53432 +               char* pfname = (char *)fname;
53433 +
53434 +               doc_root = getenv("DOCUMENT_ROOT");
53435 +               p = getenv("QUERY_STRING");
53436 +
53437 +               if (NULL != p && NULL != doc_root) {
53438 +                       snprintf(pfname, sizeof(fname), "%s/phpinfo.php", doc_root);
53439                         if (0 == strcmp(p, "lf")) {
53440                                 printf("Status: 200 OK\n\n");
53441                         } else if (0 == strcmp(p, "crlf")) {
53442 @@ -23,6 +29,18 @@
53443                                 printf("Status: 200 OK\r\n");
53444                                 fflush(stdout);
53445                                 printf("\r\n");
53446 +                       } else if (0 == strcmp(p,"x-lighttpd-send-file")) {
53447 +                               printf("Status: 200 OK\r\n");
53448 +                               printf("X-LIGHTTPD-send-file: %s\r\n", pfname);
53449 +                               printf("\r\n");
53450 +                       } else if (0 == strcmp(p,"xsendfile")) {
53451 +                               printf("Status: 200 OK\r\n");
53452 +                               printf("X-Sendfile: %s\r\n", pfname);
53453 +                               printf("\r\n");
53454 +                       } else if (0 == strcmp(p,"xsendfile-mixed-case")) {
53455 +                               printf("Status: 200 OK\r\n");
53456 +                               printf("X-SeNdFiLe: %s\r\n", pfname);
53457 +                               printf("\r\n");
53458                         } else if (0 == strcmp(p, "die-at-end")) {
53459                                 printf("Status: 200 OK\r\n\r\n");
53460                                 num_requests--;
53461 --- ../lighttpd-1.4.11/tests/lighttpd.conf      2006-03-09 15:26:58.000000000 +0200
53462 +++ lighttpd-1.4.12/tests/lighttpd.conf 2006-07-16 00:26:05.000000000 +0300
53463 @@ -1,80 +1,18 @@
53464 -debug.log-request-handling = "enable"
53465 -debug.log-condition-handling = "enable"
53466 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53467 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
53468 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53469 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53470 +server.tag = "Apache 1.3.29"
53471  
53472  ## 64 Mbyte ... nice limit
53473  server.max-request-size = 65000
53474  
53475 -## bind to port (default: 80)
53476 -server.port                 = 2048
53477 +include "default.conf"
53478  
53479 -## bind to localhost (default: all interfaces)
53480 -server.bind                = "localhost"
53481 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
53482 -server.name                = "www.example.org"
53483 -server.tag                 = "Apache 1.3.29"
53484 -
53485 -server.dir-listing          = "enable"
53486 -
53487 -#server.event-handler        = "linux-sysepoll"
53488 -#server.event-handler        = "linux-rtsig"
53489 -
53490 -#server.modules.path         = ""
53491 -server.modules              = ( 
53492 -                               "mod_rewrite",
53493 -                               "mod_setenv",
53494 -                               "mod_secdownload",
53495 -                               "mod_access", 
53496 -                               "mod_auth",
53497 -#                              "mod_httptls",
53498 -                               "mod_status", 
53499 -                               "mod_expire",
53500 -                               "mod_simple_vhost",
53501 -                               "mod_redirect", 
53502 -#                              "mod_evhost",
53503 -#                              "mod_localizer",
53504 -                               "mod_fastcgi",
53505 -                               "mod_cgi",
53506 -                               "mod_compress",
53507 -                               "mod_userdir",
53508 -                               "mod_ssi",
53509 -                               "mod_accesslog" ) 
53510 -
53511 -server.indexfiles           = ( "index.php", "index.html", 
53512 -                                "index.htm", "default.htm" )
53513 -
53514 -
53515 -######################## MODULE CONFIG ############################
53516 -
53517 -ssi.extension = ( ".shtml" )
53518 -
53519 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
53520 -
53521 -mimetype.assign             = ( ".png"  => "image/png", 
53522 -                                ".jpg"  => "image/jpeg",
53523 -                                ".jpeg" => "image/jpeg",
53524 -                                ".gif"  => "image/gif",
53525 -                                ".html" => "text/html",
53526 -                                ".htm"  => "text/html",
53527 -                                ".pdf"  => "application/pdf",
53528 -                                ".swf"  => "application/x-shockwave-flash",
53529 -                                ".spl"  => "application/futuresplash",
53530 -                                ".txt"  => "text/plain",
53531 -                                ".tar.gz" =>   "application/x-tgz",
53532 -                                ".tgz"  => "application/x-tgz",
53533 -                                ".gz"   => "application/x-gzip",
53534 -                               ".c"    => "text/plain",
53535 -                               ".conf" => "text/plain" )
53536 +setenv.add-request-header   = ( "FOO" => "foo")
53537 +setenv.add-response-header  = ( "BAR" => "foo")
53538  
53539  $HTTP["host"] == "cache.example.org" {
53540 -  compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
53541 +  compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
53542  }
53543 -compress.filetype           = ("text/plain", "text/html")
53544 -
53545 -setenv.add-environment      = ( "TRAC_ENV" => "tracenv", "SETENV" => "setenv")
53546 -setenv.add-request-header   = ( "FOO" => "foo")
53547 -setenv.add-response-header  = ( "BAR" => "foo")
53548  
53549  $HTTP["url"] =~ "\.pdf$" {
53550    server.range-requests = "disable"
53551 @@ -85,76 +23,31 @@
53552                                 "/prefix.fcgi" => ( ( "host" => "127.0.0.1", "port" => 1026, "check-local" => "disable", "broken-scriptfilename" => "enable" ) )
53553                               )
53554                 
53555 -
53556 -cgi.assign                  = ( ".pl"  => "/usr/bin/perl",
53557 -                                ".cgi" => "/usr/bin/perl",
53558 -                               ".py"  => "/usr/bin/python" )
53559 -                       
53560 -userdir.include-user = ( "jan" )
53561 -userdir.path = "/"
53562 -
53563 -ssl.engine                  = "disable"
53564 -ssl.pemfile                 = "server.pem"
53565 -
53566  $HTTP["host"] == "auth-htpasswd.example.org" {
53567         auth.backend                = "htpasswd"
53568  }
53569  
53570 -auth.backend                = "plain"
53571 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
53572 -
53573 -auth.backend.htpasswd.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.htpasswd"
53574 -
53575 -
53576 -auth.require                = ( "/server-status" => 
53577 -                                ( 
53578 -                                 "method"  => "digest",
53579 -                                 "realm"   => "download archiv",
53580 -                                 "require" => "group=www|user=jan|host=192.168.2.10"
53581 -                               ),
53582 -                               "/server-config" => 
53583 -                                ( 
53584 -                                 "method"  => "basic",
53585 -                                 "realm"   => "download archiv",
53586 -                                 "require" => "valid-user"
53587 -                               )
53588 -                              )
53589 -
53590 -url.access-deny             = ( "~", ".inc")
53591 -
53592 -url.rewrite                = ( "^/rewrite/foo($|\?.+)" => "/indexfile/rewrite.php$1",
53593 -                               "^/rewrite/bar(?:$|\?(.+))" => "/indexfile/rewrite.php?bar&$1" )
53594 -
53595 -expire.url                  = ( "/expire/access" => "access 2 hours", 
53596 -                               "/expire/modification" => "access plus 1 seconds 2 minutes")
53597 -
53598 -#cache.cache-dir             = "/home/weigon/wwwroot/cache/"
53599 -
53600 -#### status module
53601 -status.status-url           = "/server-status"
53602 -status.config-url           = "/server-config"
53603 -
53604  $HTTP["host"] == "vvv.example.org" {
53605 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53606 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53607    secdownload.secret          = "verysecret"
53608 -  secdownload.document-root   = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53609 +  secdownload.document-root   = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53610    secdownload.uri-prefix      = "/sec/"
53611    secdownload.timeout         = 120
53612  }
53613  
53614  $HTTP["host"] == "zzz.example.org" {
53615 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53616 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53617    server.name = "zzz.example.org"
53618  }
53619  
53620  $HTTP["host"] == "no-simple.example.org" {
53621 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/123.example.org/pages/"
53622 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/123.example.org/pages/"
53623    server.name = "zzz.example.org"
53624  }
53625  
53626  $HTTP["host"] !~ "(no-simple\.example\.org)" {
53627    simple-vhost.document-root  = "pages"
53628 -  simple-vhost.server-root    = "@SRCDIR@/tmp/lighttpd/servers/"
53629 +  simple-vhost.server-root    = env.SRCDIR + "/tmp/lighttpd/servers/"
53630    simple-vhost.default-host   = "www.example.org"
53631  }
53632  
53633 --- ../lighttpd-1.4.11/tests/lowercase.conf     1970-01-01 03:00:00.000000000 +0300
53634 +++ lighttpd-1.4.12/tests/lowercase.conf        2006-07-16 00:26:05.000000000 +0300
53635 @@ -0,0 +1,80 @@
53636 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53637 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53638 +
53639 +## bind to port (default: 80)
53640 +server.port                 = 2048
53641 +
53642 +## bind to localhost (default: all interfaces)
53643 +server.bind                = "localhost"
53644 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53645 +
53646 +server.force-lowercase-filenames = "enable"
53647 +
53648 +server.dir-listing          = "enable"
53649 +
53650 +server.modules              = ( 
53651 +                               "mod_rewrite",
53652 +                               "mod_setenv",
53653 +                               "mod_secdownload",
53654 +                               "mod_access", 
53655 +                               "mod_auth",
53656 +                               "mod_status", 
53657 +                               "mod_expire",
53658 +                               "mod_redirect", 
53659 +                               "mod_fastcgi",
53660 +                               "mod_cgi" ) 
53661 +
53662 +server.indexfiles           = ( "index.php", "index.html", 
53663 +                                "index.htm", "default.htm" )
53664 +
53665 +
53666 +######################## MODULE CONFIG ############################
53667 +
53668 +mimetype.assign             = ( ".png"  => "image/png", 
53669 +                                ".jpg"  => "image/jpeg",
53670 +                                ".jpeg" => "image/jpeg",
53671 +                                ".gif"  => "image/gif",
53672 +                                ".html" => "text/html",
53673 +                                ".htm"  => "text/html",
53674 +                                ".pdf"  => "application/pdf",
53675 +                                ".swf"  => "application/x-shockwave-flash",
53676 +                                ".spl"  => "application/futuresplash",
53677 +                                ".txt"  => "text/plain",
53678 +                                ".tar.gz" =>   "application/x-tgz",
53679 +                                ".tgz"  => "application/x-tgz",
53680 +                                ".gz"   => "application/x-gzip",
53681 +                               ".c"    => "text/plain",
53682 +                               ".conf" => "text/plain" )
53683 +
53684 +fastcgi.debug               = 0
53685 +fastcgi.server              = ( ".php" =>        ( ( "host" => "127.0.0.1", "port" => 1026, "broken-scriptfilename" => "enable" ) ),
53686 +                               "/prefix.fcgi" => ( ( "host" => "127.0.0.1", "port" => 1026, "check-local" => "disable", "broken-scriptfilename" => "enable" ) )
53687 +                             )
53688 +               
53689 +
53690 +cgi.assign                  = ( ".pl"  => "/usr/bin/perl",
53691 +                                ".cgi" => "/usr/bin/perl",
53692 +                               ".py"  => "/usr/bin/python" )
53693 +                       
53694 +auth.backend                = "plain"
53695 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53696 +
53697 +auth.backend.htpasswd.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.htpasswd"
53698 +
53699 +$HTTP["host"] == "lowercase-auth" {
53700 +  auth.require             = ( "/image.jpg" => 
53701 +                                ( 
53702 +                                 "method"  => "digest",
53703 +                                 "realm"   => "download archiv",
53704 +                                 "require" => "valid-user"
53705 +                               )
53706 +                              )
53707 +}
53708 +
53709 +$HTTP["host"] == "lowercase-deny" {
53710 +  url.access-deny             = ( ".jpg")
53711 +}
53712 +
53713 +$HTTP["host"] == "lowercase-exclude" {
53714 +  static-file.exclude-extensions = ( ".jpg" )
53715 +}
53716 --- ../lighttpd-1.4.11/tests/lowercase.t        1970-01-01 03:00:00.000000000 +0300
53717 +++ lighttpd-1.4.12/tests/lowercase.t   2006-07-16 00:26:05.000000000 +0300
53718 @@ -0,0 +1,94 @@
53719 +#!/usr/bin/env perl
53720 +BEGIN {
53721 +    # add current source dir to the include-path
53722 +    # we need this for make distcheck
53723 +   (my $srcdir = $0) =~ s#/[^/]+$#/#;
53724 +   unshift @INC, $srcdir;
53725 +}
53726 +
53727 +use strict;
53728 +use IO::Socket;
53729 +use Test::More tests => 10;
53730 +use LightyTest;
53731 +
53732 +my $tf = LightyTest->new();
53733 +my $t;
53734 +
53735 +$tf->{CONFIGFILE} = 'lowercase.conf';
53736 +    
53737 +ok($tf->start_proc == 0, "Starting lighttpd") or die();
53738 +
53739 +## check if lower-casing works
53740 +
53741 +$t->{REQUEST}  = ( <<EOF
53742 +GET /image.JPG HTTP/1.0
53743 +EOF
53744 + );
53745 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53746 +ok($tf->handle_http($t) == 0, 'uppercase access');
53747 +
53748 +$t->{REQUEST}  = ( <<EOF
53749 +GET /image.jpg HTTP/1.0
53750 +EOF
53751 + );
53752 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53753 +ok($tf->handle_http($t) == 0, 'lowercase access');
53754 +
53755 +## check that mod-auth works
53756 +
53757 +$t->{REQUEST}  = ( <<EOF
53758 +GET /image.JPG HTTP/1.0
53759 +Host: lowercase-auth
53760 +EOF
53761 + );
53762 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ];
53763 +ok($tf->handle_http($t) == 0, 'uppercase access');
53764 +
53765 +$t->{REQUEST}  = ( <<EOF
53766 +GET /image.jpg HTTP/1.0
53767 +Host: lowercase-auth
53768 +EOF
53769 + );
53770 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ];
53771 +ok($tf->handle_http($t) == 0, 'lowercase access');
53772 +
53773 +
53774 +## check that mod-staticfile exclude works
53775 +$t->{REQUEST}  = ( <<EOF
53776 +GET /image.JPG HTTP/1.0
53777 +Host: lowercase-exclude
53778 +EOF
53779 + );
53780 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53781 +ok($tf->handle_http($t) == 0, 'upper case access to staticfile.exclude-extension');
53782 +
53783 +$t->{REQUEST}  = ( <<EOF
53784 +GET /image.jpg HTTP/1.0
53785 +Host: lowercase-exclude
53786 +EOF
53787 + );
53788 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53789 +ok($tf->handle_http($t) == 0, 'lowercase access');
53790 +
53791 +
53792 +## check that mod-access exclude works
53793 +$t->{REQUEST}  = ( <<EOF
53794 +GET /image.JPG HTTP/1.0
53795 +Host: lowercase-deny
53796 +EOF
53797 + );
53798 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53799 +ok($tf->handle_http($t) == 0, 'uppercase access to url.access-deny protected location');
53800 +
53801 +$t->{REQUEST}  = ( <<EOF
53802 +GET /image.jpg HTTP/1.0
53803 +Host: lowercase-deny
53804 +EOF
53805 + );
53806 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53807 +ok($tf->handle_http($t) == 0, 'lowercase access');
53808 +
53809 +
53810 +
53811 +ok($tf->stop_proc == 0, "Stopping lighttpd");
53812 +
53813 --- ../lighttpd-1.4.11/tests/mod-cgi.t  2005-09-01 14:43:05.000000000 +0300
53814 +++ lighttpd-1.4.12/tests/mod-cgi.t     2006-07-18 13:03:40.000000000 +0300
53815 @@ -43,7 +43,7 @@
53816  GET /nph-status.pl HTTP/1.0
53817  EOF
53818   );
53819 -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53820 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 502 } ];
53821  ok($tf->handle_http($t) == 0, 'NPH + perl, Bug #14');
53822  
53823  $t->{REQUEST} = ( <<EOF
53824 --- ../lighttpd-1.4.11/tests/mod-fastcgi.t      2006-03-09 15:30:45.000000000 +0200
53825 +++ lighttpd-1.4.12/tests/mod-fastcgi.t 2006-07-18 13:03:40.000000000 +0300
53826 @@ -7,7 +7,7 @@
53827  }
53828  
53829  use strict;
53830 -use Test::More tests => 47;
53831 +use Test::More tests => 49;
53832  use LightyTest;
53833  
53834  my $tf = LightyTest->new();
53835 @@ -15,7 +15,7 @@
53836  my $t;
53837  
53838  SKIP: {
53839 -       skip "no PHP running on port 1026", 30 unless $tf->listening_on(1026);
53840 +       skip "no PHP running on port 1026", 29 unless $tf->listening_on(1026);
53841  
53842         ok($tf->start_proc == 0, "Starting lighttpd") or die();
53843  
53844 @@ -223,7 +223,7 @@
53845  }
53846  
53847  SKIP: {
53848 -       skip "no php found", 4 unless -x "/home/jan/Documents/php-5.1.0/sapi/cgi/php"; 
53849 +       skip "no php found", 4 unless -x "/home/jan/Documents/php-5.1.4/sapi/cgi/php";
53850         $tf->{CONFIGFILE} = 'fastcgi-13.conf';
53851         ok($tf->start_proc == 0, "Starting lighttpd with $tf->{CONFIGFILE}") or die();
53852         $t->{REQUEST}  = ( <<EOF
53853 @@ -285,6 +285,34 @@
53854         $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => 'test123' } ];
53855         ok($tf->handle_http($t) == 0, 'line-ending \r\n + \r\n');
53856  
53857 +    # X-LIGHTTPD-send-file
53858 +       $t->{REQUEST}  = ( <<EOF
53859 +GET /index.fcgi?x-lighttpd-send-file HTTP/1.0
53860 +Host: www.example.org
53861 +EOF
53862 + );
53863 +       $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
53864 +' } ];
53865 +       ok($tf->handle_http($t) == 0, 'X-LIGHTTPD-send-file');
53866 +    # X-Sendfile
53867 +       $t->{REQUEST}  = ( <<EOF
53868 +GET /index.fcgi?xsendfile HTTP/1.0
53869 +Host: www.example.org
53870 +EOF
53871 + );
53872 +       $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
53873 +' } ];
53874 +       ok($tf->handle_http($t) == 0, 'X-Sendfile');
53875 +
53876 +       $t->{REQUEST}  = ( <<EOF
53877 +GET /index.fcgi?xsendfile-mixed-case HTTP/1.0
53878 +Host: www.example.org
53879 +EOF
53880 + );
53881 +       $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
53882 +' } ];
53883 +       ok($tf->handle_http($t) == 0, 'X-SeNdFiLe in mixed case');
53884 +
53885         $t->{REQUEST}  = ( <<EOF
53886  GET /index.fcgi?die-at-end HTTP/1.0
53887  Host: www.example.org
53888 --- ../lighttpd-1.4.11/tests/mod-proxy.t        1970-01-01 03:00:00.000000000 +0300
53889 +++ lighttpd-1.4.12/tests/mod-proxy.t   2006-07-18 13:03:40.000000000 +0300
53890 @@ -0,0 +1,175 @@
53891 +#!/usr/bin/env perl
53892 +BEGIN {
53893 +    # add current source dir to the include-path
53894 +    # we need this for make distcheck
53895 +   (my $srcdir = $0) =~ s#/[^/]+$#/#;
53896 +   unshift @INC, $srcdir;
53897 +}
53898 +
53899 +use strict;
53900 +use IO::Socket;
53901 +use Test::More tests => 21;
53902 +use LightyTest;
53903 +
53904 +my $tf_proxy = LightyTest->new();
53905 +my $tf_backend1 = LightyTest->new();
53906 +my $tf_backend2 = LightyTest->new();
53907 +
53908 +my $t;
53909 +
53910 +## we need two procs
53911 +## 1. the real webserver
53912 +## 2. the proxy server
53913 +
53914 +SKIP: {
53915 +  skip "disabled for now", 21;
53916 +$tf_proxy->{PORT} = 2048;
53917 +$tf_proxy->{CONFIGFILE} = 'proxy.conf';
53918 +$tf_proxy->{LIGHTTPD_PIDFILE} = $tf_proxy->{SRCDIR}.'/tmp/lighttpd/lighttpd-proxy.pid';
53919 +
53920 +$tf_backend1->{PORT} = 2050;
53921 +$tf_backend1->{CONFIGFILE} = 'proxy-backend-1.conf';
53922 +$tf_backend1->{LIGHTTPD_PIDFILE} = $tf_backend1->{SRCDIR}.'/tmp/lighttpd/lighttpd-backend-1.pid';
53923 +
53924 +$tf_backend2->{PORT} = 2051;
53925 +$tf_backend2->{CONFIGFILE} = 'proxy-backend-2.conf';
53926 +$tf_backend2->{LIGHTTPD_PIDFILE} = $tf_backend2->{SRCDIR}.'/tmp/lighttpd/lighttpd-backend-2.pid';
53927 +
53928 +
53929 +ok($tf_backend1->start_proc == 0, "Starting lighttpd") or die();
53930 +
53931 +ok($tf_proxy->start_proc == 0, "Starting lighttpd as proxy") or die();
53932 +
53933 +sleep(1);
53934 +
53935 +$t->{REQUEST}  = ( <<EOF
53936 +GET /index.html HTTP/1.0
53937 +Host: www.example.org
53938 +EOF
53939 + );
53940 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53941 +ok($tf_proxy->handle_http($t) == 0, 'valid request');
53942 +
53943 +$t->{REQUEST}  = ( <<EOF
53944 +GET /index.html HTTP/1.0
53945 +Host: www.example.org
53946 +EOF
53947 + );
53948 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Server' => 'proxy-backend-1' } ];
53949 +ok($tf_proxy->handle_http($t) == 0, 'drop Server from real server');
53950 +
53951 +$t->{REQUEST}  = ( <<EOF
53952 +GET /balance-rr/foo HTTP/1.0
53953 +Host: www.example.org
53954 +EOF
53955 + );
53956 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53957 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - one backend');
53958 +
53959 +$t->{REQUEST}  = ( <<EOF
53960 +GET /balance-rr/foo HTTP/1.0
53961 +Host: www.example.org
53962 +EOF
53963 + );
53964 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53965 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - one host down, failover');
53966 +
53967 +$t->{REQUEST}  = ( <<EOF
53968 +GET /balance-fair/foo HTTP/1.0
53969 +Host: www.example.org
53970 +EOF
53971 + );
53972 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53973 +ok($tf_proxy->handle_http($t) == 0, 'balance fair - one backend');
53974 +
53975 +## backend 2 starting 
53976 +ok($tf_backend2->start_proc == 0, "Starting second proxy backend") or die();
53977 +
53978 +$t->{REQUEST}  = ( <<EOF
53979 +GET /balance-rr/foo HTTP/1.0
53980 +Host: www.example.org
53981 +EOF
53982 + );
53983 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53984 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - lb, backend 1');
53985 +
53986 +$t->{REQUEST}  = ( <<EOF
53987 +GET /balance-rr/foo HTTP/1.0
53988 +Host: www.example.org
53989 +EOF
53990 + );
53991 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53992 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - lb, backend 2');
53993 +
53994 +$t->{REQUEST}  = ( <<EOF
53995 +GET /balance-hash/foo HTTP/1.0
53996 +Host: www.example.org
53997 +EOF
53998 + );
53999 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
54000 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 1');
54001 +
54002 +$t->{REQUEST}  = ( <<EOF
54003 +GET /balance-hash/foo HTTP/1.0
54004 +Host: www.example.org
54005 +EOF
54006 + );
54007 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
54008 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 1 - same URL');
54009 +
54010 +$t->{REQUEST}  = ( <<EOF
54011 +GET /balance-hash/bar HTTP/1.0
54012 +Host: www.example.org
54013 +EOF
54014 + );
54015 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
54016 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 2');
54017 +
54018 +$t->{REQUEST}  = ( <<EOF
54019 +GET /balance-hash/bar HTTP/1.0
54020 +Host: www.example.org
54021 +EOF
54022 + );
54023 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
54024 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 2 - same URL');
54025 +
54026 +## backend 1 stopping, failover 
54027 +ok($tf_backend1->stop_proc == 0, "Stopping backend 1");
54028 +
54029 +$t->{REQUEST}  = ( <<EOF
54030 +GET /balance-hash/foo HTTP/1.0
54031 +Host: www.example.org
54032 +EOF
54033 + );
54034 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
54035 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - failover to backend 2');
54036 +
54037 +$t->{REQUEST}  = ( <<EOF
54038 +GET /balance-hash/bar HTTP/1.0
54039 +Host: www.example.org
54040 +EOF
54041 + );
54042 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
54043 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - failover to backend 2 - same URL');
54044 +
54045 +$t->{REQUEST}  = ( <<EOF
54046 +GET /balance-rr/foo HTTP/1.0
54047 +Host: www.example.org
54048 +EOF
54049 + );
54050 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
54051 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - failover to backend 2');
54052 +
54053 +$t->{REQUEST}  = ( <<EOF
54054 +GET /balance-fair/foo HTTP/1.0
54055 +Host: www.example.org
54056 +EOF
54057 + );
54058 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
54059 +ok($tf_proxy->handle_http($t) == 0, 'balance fair - failover to backend 2');
54060 +
54061 +
54062 +ok($tf_backend2->stop_proc == 0, "Stopping lighttpd");
54063 +
54064 +ok($tf_proxy->stop_proc == 0, "Stopping lighttpd proxy");
54065 +}
54066 --- ../lighttpd-1.4.11/tests/proxy-backend-1.conf       1970-01-01 03:00:00.000000000 +0300
54067 +++ lighttpd-1.4.12/tests/proxy-backend-1.conf  2006-07-16 00:26:05.000000000 +0300
54068 @@ -0,0 +1,7 @@
54069 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
54070 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd-backend-1.pid"
54071 +
54072 +include "default.conf"
54073 +
54074 +
54075 +server.tag = "proxy-backend-1"
54076 --- ../lighttpd-1.4.11/tests/proxy-backend-2.conf       1970-01-01 03:00:00.000000000 +0300
54077 +++ lighttpd-1.4.12/tests/proxy-backend-2.conf  2006-07-16 00:26:04.000000000 +0300
54078 @@ -0,0 +1,7 @@
54079 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
54080 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd-backend-2.pid"
54081 +
54082 +include "default.conf"
54083 +
54084 +
54085 +server.tag = "proxy-backend-2"
54086 --- ../lighttpd-1.4.11/tests/proxy.conf 1970-01-01 03:00:00.000000000 +0300
54087 +++ lighttpd-1.4.12/tests/proxy.conf    2006-07-16 00:26:05.000000000 +0300
54088 @@ -0,0 +1,26 @@
54089 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
54090 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd-proxy.pid"
54091 +server.tag = "proxy"
54092 +
54093 +include "default.conf"
54094 +
54095 +## 127.0.0.1 and 127.0.0.2 are the same host
54096 +proxy.server              = ( 
54097 +  "" => (( "host" => "127.0.0.1",
54098 +          "port" => 2050 ),
54099 +         ( "host" => "127.0.0.2",
54100 +           "port" => 2051 )
54101 +  ))
54102 +               
54103 +$HTTP["url"] =~ "^/balance-rr/" {
54104 +  proxy.balance = "round-robin"
54105 +}
54106 +
54107 +$HTTP["url"] =~ "^/balance-hash/" {
54108 +  proxy.balance = "hash"
54109 +}
54110 +
54111 +$HTTP["url"] =~ "^/balance-fair/" {
54112 +  proxy.balance = "fair"
54113 +}
54114 +
54115 --- ../lighttpd-1.4.11/tests/var-include.conf   2005-08-27 17:44:19.000000000 +0300
54116 +++ lighttpd-1.4.12/tests/var-include.conf      2006-07-16 00:26:05.000000000 +0300
54117 @@ -2,15 +2,15 @@
54118  debug.log-request-handling = "enable"
54119  debug.log-condition-handling = "enable"
54120  
54121 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
54122 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
54123 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
54124 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
54125  
54126  ## bind to port (default: 80)
54127  server.port                 = 2048
54128  
54129  ## bind to localhost (default: all interfaces)
54130  server.bind                = "localhost"
54131 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
54132 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
54133  server.name                = "www.example.org"
54134  server.tag                 = "Apache 1.3.29"
54135  
54136 @@ -21,19 +21,19 @@
54137  ######################## MODULE CONFIG ############################
54138  
54139  
54140 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
54141 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
54142  
54143  mimetype.assign             = ( ".html" => "text/html" )
54144  
54145  url.redirect = ("^" => "/default")
54146  
54147  $HTTP["host"] == "www.example.org" {
54148 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
54149 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
54150    server.name = "www.example.org"
54151    url.redirect = ("^" => "/redirect")
54152  }
54153  $HTTP["host"] == "test.example.org" {
54154 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
54155 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
54156    server.name = "test.example.org"
54157    var.myvar = "good"
54158    var.one = 1
This page took 5.928415 seconds and 4 git commands to generate.